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

package i18n

import (
	"errors"
	"fmt"
	"log"
	"os"

	"gopkg.in/goyy/goyy.v0/util/strings"
)

var defaultLocale string = Locale_en_US

// I18n is the interface that wraps the operation i18n method.
type I18n interface {
	Message(key string) string
	Messagef(key string, args ...interface{}) string
	Error(key string) error
	Errorf(key string, args ...interface{}) error
	Panic(key string)
	Panicf(key string, args ...interface{})
	Locale() string
	SetLocale(locale string)
}

// New creates a new I18n by map.
// Get the latest default locale.
func New(locales map[string]map[string]string) I18n {
	if locales == nil {
		log.Fatalln("i18n.New:the locales not be nil!")
	}
	return &i18N{locales: locales}
}

// NewBy creates a new I18n by map and locale.
func NewBy(locales map[string]map[string]string, locale string) I18n {
	if locales == nil {
		log.Fatalln("i18n.New:the locales not be nil!")
	}
	return &i18N{locales: locales, locale: transformLocale(locale)}
}

// NewByEnv creates a new I18n by map.
// locale value from the I18N_LOCALE of the environment variable.
func NewByEnv(locales map[string]map[string]string) I18n {
	locale := os.Getenv("I18N_LOCALE")
	return NewBy(locales, transformLocale(locale))
}

type i18N struct {
	locale  string
	locales map[string]map[string]string
}

// Try to resolve the message. Return "" if no message was found.
func (me *i18N) Message(key string) string {
	if v, ok := me.locales[me.Locale()]; ok {
		if s, ok := v[key]; ok {
			return s
		}
	}
	return ""
}

// Try to resolve and format the message. Return "" if no message was found.
func (me *i18N) Messagef(key string, args ...interface{}) string {
	s := me.Message(key)
	if strings.IsBlank(s) {
		return ""
	}
	return fmt.Sprintf(s, args...)
}

// Try to resolve the error.
func (me *i18N) Error(key string) error {
	return errors.New(me.Message(key))
}

// Try to resolve and format the error.
func (me *i18N) Errorf(key string, args ...interface{}) error {
	return errors.New(me.Messagef(key, args...))
}

// Try to resolve the panic.
func (me *i18N) Panic(key string) {
	panic(errors.New(me.Message(key)))
}

// Try to resolve and format the panic.
func (me *i18N) Panicf(key string, args ...interface{}) {
	panic(errors.New(me.Messagef(key, args...)))
}

// Gets the current locale for the i18n.
func (me *i18N) Locale() string {
	if strings.IsBlank(me.locale) {
		me.locale = defaultLocale
	}
	return me.locale
}

// Sets the current locale for the i18n.
func (me *i18N) SetLocale(locale string) {
	if strings.IsNotBlank(locale) {
		me.locale = transformLocale(locale)
	}
}

// Gets the default locale.
func DefaultLocale() string {
	return defaultLocale
}

// Sets the default locale.
func SetDefaultLocale(locale string) {
	if strings.IsNotBlank(locale) {
		defaultLocale = transformLocale(locale)
		if strings.IsBlank(defaultLocale) {
			defaultLocale = Locale_en_US
		}
	}
}

func transformLocale(locale string) string {
	switch locale {
	case "cs_CZ":
		return Locale_cs_CZ
	case "da_DK":
		return Locale_da_DK
	case "de_DE":
		return Locale_de_DE
	case "en_GB":
		return Locale_en_GB
	case "en_US":
		return Locale_en_US
	case "en_XM":
		return Locale_en_XM
	case "es_ES":
		return Locale_es_ES
	case "es_LA":
		return Locale_es_LA
	case "es_MX":
		return Locale_es_MX
	case "es_NA":
		return Locale_es_NA
	case "fi_FI":
		return Locale_fi_FI
	case "fr_CA":
		return Locale_fr_CA
	case "fr_FR":
		return Locale_fr_FR
	case "fr_XM":
		return Locale_fr_XM
	case "hu_HU":
		return Locale_hu_HU
	case "it_IT":
		return Locale_it_IT
	case "ja_JP":
		return Locale_ja_JP
	case "ko_KR":
		return Locale_ko_KR
	case "nb_NO":
		return Locale_nb_NO
	case "nl_NL":
		return Locale_nl_NL
	case "pl_PL":
		return Locale_pl_PL
	case "pt_BR":
		return Locale_pt_BR
	case "ro_RO":
		return Locale_ro_RO
	case "ru_RU":
		return Locale_ru_RU
	case "sv_SE":
		return Locale_sv_SE
	case "tr_TR":
		return Locale_tr_TR
	case "uk_UA":
		return Locale_uk_UA
	case "zh_CN":
		return Locale_zh_CN
	case "zh_TW":
		return Locale_zh_TW
	default:
		return "" // Get the latest default locale when the value is blank
		//return defaultLocale
	}
}
<commit_msg>Add support for default locale<commit_after>// Copyright 2014 The goyy Authors.  All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package i18n

import (
	"errors"
	"fmt"
	"log"
	"os"

	"gopkg.in/goyy/goyy.v0/util/strings"
)

var defaultLocale string = Locale_en_US

// I18n is the interface that wraps the operation i18n method.
type I18n interface {
	Message(key string) string
	Messagef(key string, args ...interface{}) string
	Error(key string) error
	Errorf(key string, args ...interface{}) error
	Panic(key string)
	Panicf(key string, args ...interface{})
	Locale() string
	SetLocale(locale string)
}

// New creates a new I18n by map.
// Get the latest default locale.
func New(locales map[string]map[string]string) I18n {
	if locales == nil {
		log.Fatalln("i18n.New:the locales not be nil!")
	}
	return &i18N{locales: locales}
}

// NewBy creates a new I18n by map and locale.
func NewBy(locales map[string]map[string]string, locale string) I18n {
	if locales == nil {
		log.Fatalln("i18n.New:the locales not be nil!")
	}
	return &i18N{locales: locales, locale: transformLocale(locale)}
}

// NewByEnv creates a new I18n by map.
// locale value from the I18N_LOCALE of the environment variable.
func NewByEnv(locales map[string]map[string]string) I18n {
	locale := os.Getenv("I18N_LOCALE")
	return NewBy(locales, transformLocale(locale))
}

type i18N struct {
	locale  string
	locales map[string]map[string]string
}

// Try to resolve the message. Return "" if no message was found.
func (me *i18N) Message(key string) string {
	if v, ok := me.locales[me.Locale()]; ok {
		if s, ok := v[key]; ok {
			return s
		}
	} else {
		if v, ok := me.locales[Locale_en_US]; ok {
			if s, ok := v[key]; ok {
				return s
			}
		} else {
			if v, ok := me.locales[Locale_zh_CN]; ok {
				if s, ok := v[key]; ok {
					return s
				}
			}
		}
	}
	return ""
}

// Try to resolve and format the message. Return "" if no message was found.
func (me *i18N) Messagef(key string, args ...interface{}) string {
	s := me.Message(key)
	if strings.IsBlank(s) {
		return ""
	}
	return fmt.Sprintf(s, args...)
}

// Try to resolve the error.
func (me *i18N) Error(key string) error {
	return errors.New(me.Message(key))
}

// Try to resolve and format the error.
func (me *i18N) Errorf(key string, args ...interface{}) error {
	return errors.New(me.Messagef(key, args...))
}

// Try to resolve the panic.
func (me *i18N) Panic(key string) {
	panic(errors.New(me.Message(key)))
}

// Try to resolve and format the panic.
func (me *i18N) Panicf(key string, args ...interface{}) {
	panic(errors.New(me.Messagef(key, args...)))
}

// Gets the current locale for the i18n.
func (me *i18N) Locale() string {
	if strings.IsBlank(me.locale) {
		me.locale = defaultLocale
	}
	return me.locale
}

// Sets the current locale for the i18n.
func (me *i18N) SetLocale(locale string) {
	if strings.IsNotBlank(locale) {
		me.locale = transformLocale(locale)
	}
}

// Gets the default locale.
func DefaultLocale() string {
	return defaultLocale
}

// Sets the default locale.
func SetDefaultLocale(locale string) {
	if strings.IsNotBlank(locale) {
		defaultLocale = transformLocale(locale)
		if strings.IsBlank(defaultLocale) {
			defaultLocale = Locale_en_US
		}
	}
}

func transformLocale(locale string) string {
	switch locale {
	case "cs_CZ":
		return Locale_cs_CZ
	case "da_DK":
		return Locale_da_DK
	case "de_DE":
		return Locale_de_DE
	case "en_GB":
		return Locale_en_GB
	case "en_US":
		return Locale_en_US
	case "en_XM":
		return Locale_en_XM
	case "es_ES":
		return Locale_es_ES
	case "es_LA":
		return Locale_es_LA
	case "es_MX":
		return Locale_es_MX
	case "es_NA":
		return Locale_es_NA
	case "fi_FI":
		return Locale_fi_FI
	case "fr_CA":
		return Locale_fr_CA
	case "fr_FR":
		return Locale_fr_FR
	case "fr_XM":
		return Locale_fr_XM
	case "hu_HU":
		return Locale_hu_HU
	case "it_IT":
		return Locale_it_IT
	case "ja_JP":
		return Locale_ja_JP
	case "ko_KR":
		return Locale_ko_KR
	case "nb_NO":
		return Locale_nb_NO
	case "nl_NL":
		return Locale_nl_NL
	case "pl_PL":
		return Locale_pl_PL
	case "pt_BR":
		return Locale_pt_BR
	case "ro_RO":
		return Locale_ro_RO
	case "ru_RU":
		return Locale_ru_RU
	case "sv_SE":
		return Locale_sv_SE
	case "tr_TR":
		return Locale_tr_TR
	case "uk_UA":
		return Locale_uk_UA
	case "zh_CN":
		return Locale_zh_CN
	case "zh_TW":
		return Locale_zh_TW
	default:
		return "" // Get the latest default locale when the value is blank
		//return defaultLocale
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	// "github.com/go-martini/martini"
	// _ "github.com/jinzhu/gorm"
	// "github.com/martini-contrib/render"
)

func RunServer(c *cli.Context) {
	// m := martini.Classic()
	// m.Use(render.Renderer())
	//
	// config := app.Config{DatabaseConnectionString: "user=jais dbname=panorma_dev sslmode=disable", LogDatabaseQueries: true}
	//
	// db = app.SetupDatabase(config)
	//
	// m.Get("/api/albums", func(r render.Render) {
	// 	r.JSON(200, app.RootAlbums(db))
	// })

	//api/photos?year=(&month=(&day=))
	// GET /api/albums/:album_id -> { albums, photos }
	// PST /api/albums
	// GET /api/photos/:photo_id -> { photo, duplicates }
	// PUT /api/albums/:album_id
	// GET /api/albums/:album_id/add/:photo_id
	// GET /api/albums/:album_id/remove/:photo_id
	// GET /api/duplicates
	// GET /api/duplicates/:duplicate_id
	// DEL /api/duplicates/:duplicate_id

	// m.Run()
}
<commit_msg>Add basic working server setup with negroni and gorilla mux<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	_ "github.com/jinzhu/gorm"
	"github.com/unrolled/render"
	"net/http"
)

var Render = render.New()

func HomeHandler(w http.ResponseWriter, req *http.Request) {
	Render.JSON(w, http.StatusOK, map[string]string{"hello": "world"})
}

func RunServer(c *cli.Context) {
	router := mux.NewRouter()
	router.HandleFunc("/", HomeHandler)

	server := negroni.Classic()
	server.UseHandler(router)
	server.Run(":3000")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/mgutz/ansi"
)

var (
	color = ansi.ColorCode("white+b:green")
	reset = ansi.ColorCode("reset")
)

var logo string = `                                         ` + reset + " Ram:      %s" + color + `
 __________.__  __         .__           ` + reset + " Pacakges: %d" + color + `
 \______   \__|/  |________|__| ____     ` + reset + " CPU:      %s" + color + `
  |    |  _/  \   __\_  __ \  |/ ___\    ` + reset + " Uptime:   %s" + color + `
  |    |   \  ||  |  |  | \/  / /_/  >   ` + reset + " User:     %s" + color + `
  |______  /__||__|  |__|  |__\___  /    ` + reset + " Hostname: %s" + color + `
         \/                  /_____/
      Version 1.0
                                         `

func getUptime() string {
	out, err := exec.Command("sysctl", "-n", "kern.boottime").Output()
	if err != nil {
		panic(err)
	}

	boottimeint, err := strconv.ParseInt(string(out[:len(out)-1]), 10, 64)
	if err != nil {
		panic(err)
	}

	boottime := time.Unix(boottimeint, 0)
	dur := time.Since(boottime)

	days := int(dur.Hours() / 24)
	hours := int(dur.Hours()) % 24
	minutes := int(dur.Minutes()) % 60

	return fmt.Sprintf("%d days, %d hours, %d minutes", days, hours, minutes)
}

func getPackageCount() int {
	out, err := exec.Command("pkg_info").Output()
	if err != nil {
		panic(err)
	}

	return len(strings.Split(string(out), "\n"))
}

func getCPUName() string {
	out, err := exec.Command("sysctl", "-n", "hw.model").Output()
	if err != nil {
		panic(err)
	}

	return strings.Split(string(out), "@")[0]
}
<commit_msg>Space out bitrig text better<commit_after>package main

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/mgutz/ansi"
)

var (
	color = ansi.ColorCode("white+b:green")
	reset = ansi.ColorCode("reset")
)

var logo string = `                                            ` + reset + " Ram:      %s" + color + `
    __________.__  __         .__           ` + reset + " Pacakges: %d" + color + `
    \______   \__|/  |________|__| ____     ` + reset + " CPU:      %s" + color + `
     |    |  _/  \   __\_  __ \  |/ ___\    ` + reset + " Uptime:   %s" + color + `
     |    |   \  ||  |  |  | \/  / /_/  >   ` + reset + " User:     %s" + color + `
     |______  /__||__|  |__|  |__\___  /    ` + reset + " Hostname: %s" + color + `
            \/                  /_____/
         Version 1.0
                                            `

func getUptime() string {
	out, err := exec.Command("sysctl", "-n", "kern.boottime").Output()
	if err != nil {
		panic(err)
	}

	boottimeint, err := strconv.ParseInt(string(out[:len(out)-1]), 10, 64)
	if err != nil {
		panic(err)
	}

	boottime := time.Unix(boottimeint, 0)
	dur := time.Since(boottime)

	days := int(dur.Hours() / 24)
	hours := int(dur.Hours()) % 24
	minutes := int(dur.Minutes()) % 60

	return fmt.Sprintf("%d days, %d hours, %d minutes", days, hours, minutes)
}

func getPackageCount() int {
	out, err := exec.Command("pkg_info").Output()
	if err != nil {
		panic(err)
	}

	return len(strings.Split(string(out), "\n"))
}

func getCPUName() string {
	out, err := exec.Command("sysctl", "-n", "hw.model").Output()
	if err != nil {
		panic(err)
	}

	return strings.Split(string(out), "@")[0]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	dtime "github.com/deis/deis/pkg/time"
	"github.com/fsouza/go-dockerclient"
	"github.com/go-martini/martini"
	"golang.org/x/net/websocket"
)

var debugMode bool

func debug(v ...interface{}) {
	if debugMode {
		log.Println(v...)
	}
}

func assert(err error, context string) {
	if err != nil {
		log.Fatalf("%s: %v", context, err)
	}
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

type Colorizer map[string]int

// returns up to 14 color escape codes (then repeats) for each unique key
func (c Colorizer) Get(key string) string {
	i, exists := c[key]
	if !exists {
		c[key] = len(c)
		i = c[key]
	}
	bright := "1;"
	if i%14 > 6 {
		bright = ""
	}
	return "\x1b[" + bright + "3" + strconv.Itoa(7-(i%7)) + "m"
}

func syslogStreamer(target Target, types []string, logstream chan *Log) {
	typestr := "," + strings.Join(types, ",") + ","
	for logline := range logstream {
		if typestr != ",," && !strings.Contains(typestr, logline.Type) {
			continue
		}
		tag, pid := getLogName(logline.Name)
		var conn net.Conn
		if strings.EqualFold(target.Protocol, "tcp") {
			addr, err := net.ResolveTCPAddr("tcp", target.Addr)
			assert(err, "syslog")
			tcpconn, err := net.DialTCP("tcp", nil, addr)
			assert(err, "syslog")
			assert(tcpconn.SetWriteBuffer(1048576), "syslog")
			conn = tcpconn
		} else if strings.EqualFold(target.Protocol, "udp") {
			addr, err := net.ResolveUDPAddr("udp", target.Addr)
			assert(err, "syslog")
			udpconn, err := net.DialUDP("udp", nil, addr)
			assert(err, "syslog")
			assert(udpconn.SetWriteBuffer(1048576), "syslog")
			conn = udpconn
		} else {
			assert(fmt.Errorf("%s is not a supported protocol, use either udp or tcp", target.Protocol), "syslog")
		}
		// HACK: Go's syslog package hardcodes the log format, so let's send our own message
		_, err := fmt.Fprintf(conn,
			"%s %s[%s]: %s",
			time.Now().Format(getopt("DATETIME_FORMAT", dtime.DeisDatetimeFormat)),
			tag,
			pid,
			logline.Data)
		assert(err, "syslog")
	}
}

// getLogName returns a custom tag and PID for containers that
// match Deis' specific application name format. Otherwise,
// it returns the original name and 1 as the PID.
func getLogName(name string) (string, string) {
	// example regex that should match: go_v2.web.1
	match := getMatch(`(^[a-z0-9-]+)_(v[0-9]+)\.([a-z-_]+\.[0-9]+)$`, name)
	if match != nil {
		return match[1], match[3]
	}
	match = getMatch(`^k8s_([a-z0-9-]+)-[a-z]+\.[\da-f]+_[a-z0-9-]+-([a-z]+-[\da-z]*)_`, name)
	if match != nil {
		return match[1], match[2]
	}
	return name, "1"
}

func getMatch(regex string, name string) []string {
	r := regexp.MustCompile(regex)
	match := r.FindStringSubmatch(name)
	return match
}

func websocketStreamer(w http.ResponseWriter, req *http.Request, logstream chan *Log, closer chan bool) {
	websocket.Handler(func(conn *websocket.Conn) {
		for logline := range logstream {
			if req.URL.Query().Get("type") != "" && logline.Type != req.URL.Query().Get("type") {
				continue
			}
			_, err := conn.Write(append(marshal(logline), '\n'))
			if err != nil {
				closer <- true
				return
			}
		}
	}).ServeHTTP(w, req)
}

func httpStreamer(w http.ResponseWriter, req *http.Request, logstream chan *Log, multi bool) {
	var colors Colorizer
	var usecolor, usejson bool
	nameWidth := 16
	if req.URL.Query().Get("colors") != "off" {
		colors = make(Colorizer)
		usecolor = true
	}
	if req.Header.Get("Accept") == "application/json" {
		w.Header().Add("Content-Type", "application/json")
		usejson = true
	} else {
		w.Header().Add("Content-Type", "text/plain")
	}
	for logline := range logstream {
		if req.URL.Query().Get("types") != "" && logline.Type != req.URL.Query().Get("types") {
			continue
		}
		if usejson {
			w.Write(append(marshal(logline), '\n'))
		} else {
			if multi {
				if len(logline.Name) > nameWidth {
					nameWidth = len(logline.Name)
				}
				if usecolor {
					w.Write([]byte(fmt.Sprintf(
						"%s%"+strconv.Itoa(nameWidth)+"s|%s\x1b[0m\n",
						colors.Get(logline.Name), logline.Name, logline.Data,
					)))
				} else {
					w.Write([]byte(fmt.Sprintf(
						"%"+strconv.Itoa(nameWidth)+"s|%s\n", logline.Name, logline.Data,
					)))
				}
			} else {
				w.Write(append([]byte(logline.Data), '\n'))
			}
		}
		w.(http.Flusher).Flush()
	}
}

func getEtcdValueOrDefault(c *etcd.Client, key string, defaultValue string) string {
	resp, err := c.Get(key, false, false)
	if err != nil {
		if strings.Contains(fmt.Sprintf("%v", err), "Key not found") {
			return defaultValue
		}
		assert(err, "url")
	}
	return resp.Node.Value
}

func main() {
	debugMode = getopt("DEBUG", "") != ""
	port := getopt("PORT", "8000")
	endpoint := getopt("DOCKER_HOST", "unix:///var/run/docker.sock")
	routespath := getopt("ROUTESPATH", "/var/lib/logspout")

	client, err := docker.NewClient(endpoint)
	assert(err, "docker")
	attacher := NewAttachManager(client)
	router := NewRouteManager(attacher)

	// HACK: if we are connecting to etcd, get the logger's connection
	// details from there
	if etcdHost := os.Getenv("ETCD_HOST"); etcdHost != "" {
		connectionString := []string{"http://" + etcdHost + ":4001"}
		debug("etcd:", connectionString[0])
		etcd := etcd.NewClient(connectionString)
		etcd.SetDialTimeout(3 * time.Second)
		hostResp, err := etcd.Get("/deis/logs/host", false, false)
		assert(err, "url")
		portResp, err := etcd.Get("/deis/logs/port", false, false)
		assert(err, "url")
		protocol := getEtcdValueOrDefault(etcd, "/deis/logs/protocol", "udp")
		host := fmt.Sprintf("%s:%s", hostResp.Node.Value, portResp.Node.Value)
		log.Printf("routing all to %s://%s", protocol, host)
		router.Add(&Route{Target: Target{Type: "syslog", Addr: host, Protocol: protocol}})
	}

	if len(os.Args) > 1 {
		u, err := url.Parse(os.Args[1])
		assert(err, "url")
		log.Println("routing all to " + os.Args[1])
		router.Add(&Route{Target: Target{Type: u.Scheme, Addr: u.Host}})
	}

	if _, err := os.Stat(routespath); err == nil {
		log.Println("loading and persisting routes in " + routespath)
		assert(router.Load(RouteFileStore(routespath)), "persistor")
	}

	m := martini.Classic()

	m.Get("/logs(?:/(?P<predicate>[a-zA-Z]+):(?P<value>.+))?", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		source := new(Source)
		switch {
		case params["predicate"] == "id" && params["value"] != "":
			source.ID = params["value"][:12]
		case params["predicate"] == "name" && params["value"] != "":
			source.Name = params["value"]
		case params["predicate"] == "filter" && params["value"] != "":
			source.Filter = params["value"]
		}

		if source.ID != "" && attacher.Get(source.ID) == nil {
			http.NotFound(w, req)
			return
		}

		logstream := make(chan *Log)
		defer close(logstream)

		var closer <-chan bool
		if req.Header.Get("Upgrade") == "websocket" {
			closerBi := make(chan bool)
			go websocketStreamer(w, req, logstream, closerBi)
			closer = closerBi
		} else {
			go httpStreamer(w, req, logstream, source.All() || source.Filter != "")
			closer = w.(http.CloseNotifier).CloseNotify()
		}

		attacher.Listen(source, logstream, closer)
	})

	m.Get("/routes", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Add("Content-Type", "application/json")
		routes, _ := router.GetAll()
		w.Write(append(marshal(routes), '\n'))
	})

	m.Post("/routes", func(w http.ResponseWriter, req *http.Request) (int, string) {
		route := new(Route)
		if err := unmarshal(req.Body, route); err != nil {
			return http.StatusBadRequest, "Bad request: " + err.Error()
		}

		// TODO: validate?
		router.Add(route)

		w.Header().Add("Content-Type", "application/json")
		return http.StatusCreated, string(append(marshal(route), '\n'))
	})

	m.Get("/routes/:id", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		route, _ := router.Get(params["id"])
		if route == nil {
			http.NotFound(w, req)
			return
		}
		w.Write(append(marshal(route), '\n'))
	})

	m.Delete("/routes/:id", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		if ok := router.Remove(params["id"]); !ok {
			http.NotFound(w, req)
		}
	})

	log.Println("logspout serving http on :" + port)
	log.Fatal(http.ListenAndServe(":"+port, m))
}
<commit_msg>fix(logspout): set GOMAXPROCS=1<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	dtime "github.com/deis/deis/pkg/time"
	"github.com/fsouza/go-dockerclient"
	"github.com/go-martini/martini"
	"golang.org/x/net/websocket"
)

var debugMode bool

func debug(v ...interface{}) {
	if debugMode {
		log.Println(v...)
	}
}

func assert(err error, context string) {
	if err != nil {
		log.Fatalf("%s: %v", context, err)
	}
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

type Colorizer map[string]int

// returns up to 14 color escape codes (then repeats) for each unique key
func (c Colorizer) Get(key string) string {
	i, exists := c[key]
	if !exists {
		c[key] = len(c)
		i = c[key]
	}
	bright := "1;"
	if i%14 > 6 {
		bright = ""
	}
	return "\x1b[" + bright + "3" + strconv.Itoa(7-(i%7)) + "m"
}

func syslogStreamer(target Target, types []string, logstream chan *Log) {
	typestr := "," + strings.Join(types, ",") + ","
	for logline := range logstream {
		if typestr != ",," && !strings.Contains(typestr, logline.Type) {
			continue
		}
		tag, pid := getLogName(logline.Name)
		var conn net.Conn
		if strings.EqualFold(target.Protocol, "tcp") {
			addr, err := net.ResolveTCPAddr("tcp", target.Addr)
			assert(err, "syslog")
			tcpconn, err := net.DialTCP("tcp", nil, addr)
			assert(err, "syslog")
			assert(tcpconn.SetWriteBuffer(1048576), "syslog")
			conn = tcpconn
		} else if strings.EqualFold(target.Protocol, "udp") {
			addr, err := net.ResolveUDPAddr("udp", target.Addr)
			assert(err, "syslog")
			udpconn, err := net.DialUDP("udp", nil, addr)
			assert(err, "syslog")
			assert(udpconn.SetWriteBuffer(1048576), "syslog")
			conn = udpconn
		} else {
			assert(fmt.Errorf("%s is not a supported protocol, use either udp or tcp", target.Protocol), "syslog")
		}
		// HACK: Go's syslog package hardcodes the log format, so let's send our own message
		_, err := fmt.Fprintf(conn,
			"%s %s[%s]: %s",
			time.Now().Format(getopt("DATETIME_FORMAT", dtime.DeisDatetimeFormat)),
			tag,
			pid,
			logline.Data)
		assert(err, "syslog")
	}
}

// getLogName returns a custom tag and PID for containers that
// match Deis' specific application name format. Otherwise,
// it returns the original name and 1 as the PID.
func getLogName(name string) (string, string) {
	// example regex that should match: go_v2.web.1
	match := getMatch(`(^[a-z0-9-]+)_(v[0-9]+)\.([a-z-_]+\.[0-9]+)$`, name)
	if match != nil {
		return match[1], match[3]
	}
	match = getMatch(`^k8s_([a-z0-9-]+)-[a-z]+\.[\da-f]+_[a-z0-9-]+-([a-z]+-[\da-z]*)_`, name)
	if match != nil {
		return match[1], match[2]
	}
	return name, "1"
}

func getMatch(regex string, name string) []string {
	r := regexp.MustCompile(regex)
	match := r.FindStringSubmatch(name)
	return match
}

func websocketStreamer(w http.ResponseWriter, req *http.Request, logstream chan *Log, closer chan bool) {
	websocket.Handler(func(conn *websocket.Conn) {
		for logline := range logstream {
			if req.URL.Query().Get("type") != "" && logline.Type != req.URL.Query().Get("type") {
				continue
			}
			_, err := conn.Write(append(marshal(logline), '\n'))
			if err != nil {
				closer <- true
				return
			}
		}
	}).ServeHTTP(w, req)
}

func httpStreamer(w http.ResponseWriter, req *http.Request, logstream chan *Log, multi bool) {
	var colors Colorizer
	var usecolor, usejson bool
	nameWidth := 16
	if req.URL.Query().Get("colors") != "off" {
		colors = make(Colorizer)
		usecolor = true
	}
	if req.Header.Get("Accept") == "application/json" {
		w.Header().Add("Content-Type", "application/json")
		usejson = true
	} else {
		w.Header().Add("Content-Type", "text/plain")
	}
	for logline := range logstream {
		if req.URL.Query().Get("types") != "" && logline.Type != req.URL.Query().Get("types") {
			continue
		}
		if usejson {
			w.Write(append(marshal(logline), '\n'))
		} else {
			if multi {
				if len(logline.Name) > nameWidth {
					nameWidth = len(logline.Name)
				}
				if usecolor {
					w.Write([]byte(fmt.Sprintf(
						"%s%"+strconv.Itoa(nameWidth)+"s|%s\x1b[0m\n",
						colors.Get(logline.Name), logline.Name, logline.Data,
					)))
				} else {
					w.Write([]byte(fmt.Sprintf(
						"%"+strconv.Itoa(nameWidth)+"s|%s\n", logline.Name, logline.Data,
					)))
				}
			} else {
				w.Write(append([]byte(logline.Data), '\n'))
			}
		}
		w.(http.Flusher).Flush()
	}
}

func getEtcdValueOrDefault(c *etcd.Client, key string, defaultValue string) string {
	resp, err := c.Get(key, false, false)
	if err != nil {
		if strings.Contains(fmt.Sprintf("%v", err), "Key not found") {
			return defaultValue
		}
		assert(err, "url")
	}
	return resp.Node.Value
}

func main() {
	runtime.GOMAXPROCS(1)
	debugMode = getopt("DEBUG", "") != ""
	port := getopt("PORT", "8000")
	endpoint := getopt("DOCKER_HOST", "unix:///var/run/docker.sock")
	routespath := getopt("ROUTESPATH", "/var/lib/logspout")

	client, err := docker.NewClient(endpoint)
	assert(err, "docker")
	attacher := NewAttachManager(client)
	router := NewRouteManager(attacher)

	// HACK: if we are connecting to etcd, get the logger's connection
	// details from there
	if etcdHost := os.Getenv("ETCD_HOST"); etcdHost != "" {
		connectionString := []string{"http://" + etcdHost + ":4001"}
		debug("etcd:", connectionString[0])
		etcd := etcd.NewClient(connectionString)
		etcd.SetDialTimeout(3 * time.Second)
		hostResp, err := etcd.Get("/deis/logs/host", false, false)
		assert(err, "url")
		portResp, err := etcd.Get("/deis/logs/port", false, false)
		assert(err, "url")
		protocol := getEtcdValueOrDefault(etcd, "/deis/logs/protocol", "udp")
		host := fmt.Sprintf("%s:%s", hostResp.Node.Value, portResp.Node.Value)
		log.Printf("routing all to %s://%s", protocol, host)
		router.Add(&Route{Target: Target{Type: "syslog", Addr: host, Protocol: protocol}})
	}

	if len(os.Args) > 1 {
		u, err := url.Parse(os.Args[1])
		assert(err, "url")
		log.Println("routing all to " + os.Args[1])
		router.Add(&Route{Target: Target{Type: u.Scheme, Addr: u.Host}})
	}

	if _, err := os.Stat(routespath); err == nil {
		log.Println("loading and persisting routes in " + routespath)
		assert(router.Load(RouteFileStore(routespath)), "persistor")
	}

	m := martini.Classic()

	m.Get("/logs(?:/(?P<predicate>[a-zA-Z]+):(?P<value>.+))?", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		source := new(Source)
		switch {
		case params["predicate"] == "id" && params["value"] != "":
			source.ID = params["value"][:12]
		case params["predicate"] == "name" && params["value"] != "":
			source.Name = params["value"]
		case params["predicate"] == "filter" && params["value"] != "":
			source.Filter = params["value"]
		}

		if source.ID != "" && attacher.Get(source.ID) == nil {
			http.NotFound(w, req)
			return
		}

		logstream := make(chan *Log)
		defer close(logstream)

		var closer <-chan bool
		if req.Header.Get("Upgrade") == "websocket" {
			closerBi := make(chan bool)
			go websocketStreamer(w, req, logstream, closerBi)
			closer = closerBi
		} else {
			go httpStreamer(w, req, logstream, source.All() || source.Filter != "")
			closer = w.(http.CloseNotifier).CloseNotify()
		}

		attacher.Listen(source, logstream, closer)
	})

	m.Get("/routes", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Add("Content-Type", "application/json")
		routes, _ := router.GetAll()
		w.Write(append(marshal(routes), '\n'))
	})

	m.Post("/routes", func(w http.ResponseWriter, req *http.Request) (int, string) {
		route := new(Route)
		if err := unmarshal(req.Body, route); err != nil {
			return http.StatusBadRequest, "Bad request: " + err.Error()
		}

		// TODO: validate?
		router.Add(route)

		w.Header().Add("Content-Type", "application/json")
		return http.StatusCreated, string(append(marshal(route), '\n'))
	})

	m.Get("/routes/:id", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		route, _ := router.Get(params["id"])
		if route == nil {
			http.NotFound(w, req)
			return
		}
		w.Write(append(marshal(route), '\n'))
	})

	m.Delete("/routes/:id", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		if ok := router.Remove(params["id"]); !ok {
			http.NotFound(w, req)
		}
	})

	log.Println("logspout serving http on :" + port)
	log.Fatal(http.ListenAndServe(":"+port, m))
}
<|endoftext|>


<commit_before>package version

// Version of the program
const Version = `0.3.0`
<commit_msg>Bumping version 0.3.1<commit_after>package version

// Version of the program
const Version = `0.3.1`
<|endoftext|>


<commit_before>package version

const (
	// Version is the current File Browser version.
	Version = "(untracked)"
)
<commit_msg>chore: version v2.0.3<commit_after>package version

const (
	// Version is the current File Browser version.
	Version = "v2.0.3"
)
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-rc4"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bumping version to 0.6.0-dev<commit_after>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator 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 version

var (
	Version = "0.4.2"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<commit_msg>version: bump to 0.4.2+git<commit_after>// Copyright 2016 The etcd-operator 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 version

var (
	Version = "0.4.2+git"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.2.4"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<commit_msg>hub 2.2.5<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.2.5"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google, Inc. All rights reserved.

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 version

import "fmt"

// Bump this on release
var version = "v0.15.0"

// When built using `make` this is overridden via -ldflags
var gitVersion = "(unknown)"

// returns just the vX.Y.Z version suitable for `make release`
func GetShortVersion() string {
	return version
}

func GetVersion() string {
	return fmt.Sprintf("%s built from git %s", version, gitVersion)
}
<commit_msg>Cut version 0.17.0<commit_after>/*
Copyright 2018 Google, Inc. All rights reserved.

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 version

import "fmt"

// Bump this on release
var version = "v0.17.0"

// When built using `make` this is overridden via -ldflags
var gitVersion = "(unknown)"

// returns just the vX.Y.Z version suitable for `make release`
func GetShortVersion() string {
	return version
}

func GetVersion() string {
	return fmt.Sprintf("%s built from git %s", version, gitVersion)
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 core

import (
	"fmt"
	"time"
)

type AggregationType string

var (
	AggregationTypeAverage      AggregationType = "average"
	AggregationTypeMaximum      AggregationType = "max"
	AggregationTypeMinimum      AggregationType = "min"
	AggregationTypeMedian       AggregationType = "median"
	AggregationTypeCount        AggregationType = "count"
	AggregationTypePercentile50 AggregationType = "50-perc"
	AggregationTypePercentile95 AggregationType = "95-perc"
	AggregationTypePercentile99 AggregationType = "99-perc"
)

// MultiTypedAggregations is the list of aggregations that can be either float or int
var MultiTypedAggregations = []AggregationType{
	AggregationTypeAverage,
	AggregationTypeMaximum,
	AggregationTypeMinimum,
	AggregationTypeMedian,
	AggregationTypePercentile50,
	AggregationTypePercentile95,
	AggregationTypePercentile99,
}

// AllAggregations is the set of all supported aggregations
var AllAggregations = map[AggregationType]bool{
	AggregationTypeAverage:      true,
	AggregationTypeMaximum:      true,
	AggregationTypeMinimum:      true,
	AggregationTypeMedian:       true,
	AggregationTypePercentile50: true,
	AggregationTypePercentile95: true,
	AggregationTypePercentile99: true,
	AggregationTypeCount:        true,
}

// TimestampedMetricValue is a metric value with an associated timestamp
type TimestampedMetricValue struct {
	MetricValue
	Timestamp time.Time
}

// AggregationValue is a description of aggregated MetricValues over time
type AggregationValue struct {
	Count *uint64

	Aggregations map[AggregationType]MetricValue
}

// TimestampedAggregationValue is an aggregation value with an associated timestamp
// and bucket size
type TimestampedAggregationValue struct {
	// Timestamp is the start time of the bucket
	Timestamp time.Time

	// BucketSize is the duration of the bucket
	BucketSize time.Duration

	AggregationValue
}

// HistoricalKey is an identifier pointing to a particular object.
// Is is composed of an object type (pod, namespace, container, etc) as well
// as a series of fields which identify that object.
type HistoricalKey struct {
	// ObjectType specifies which type of object this is for (pod, namespace, etc)
	// It should be one of the MetricSetType* labels.
	ObjectType string

	// NodeName is used for node and system-container metrics
	NodeName string
	// NamespaceName is used for namespace, pod, and pod-container metrics
	NamespaceName string
	// PodName is used for pod and pod-container metrics
	PodName string
	// ContainerName is used for system-container and pod-container metrics
	ContainerName string
	// PodId may be used in place of the combination of PodName and NamespaceName for pod and pod-container metrics
	PodId string
}

func (key *HistoricalKey) String() string {
	prefix := fmt.Sprintf("(%s)", key.ObjectType)

	var path string = "[unknown type]"
	switch key.ObjectType {
	case MetricSetTypeSystemContainer:
		path = fmt.Sprintf("node:%s/container:%s", key.NodeName, key.ContainerName)
	case MetricSetTypePodContainer:
		if key.PodId != "" {
			path = fmt.Sprintf("poduid:%s/container:%s", key.PodId, key.ContainerName)
		} else {
			path = fmt.Sprintf("ns:%s/pod:%s/container:%s", key.NamespaceName, key.PodName, key.ContainerName)
		}
	case MetricSetTypePod:
		if key.PodId != "" {
			path = fmt.Sprintf("poduid:%s", key.PodId)
		} else {
			path = fmt.Sprintf("ns:%s/pod:%s", key.NamespaceName, key.PodName)
		}
	case MetricSetTypeNamespace:
		path = fmt.Sprintf("ns:%s", key.NamespaceName)
	case MetricSetTypeNode:
		path = fmt.Sprintf("node:%s", key.NodeName)
	case MetricSetTypeCluster:
		path = "[cluster]"
	}

	return prefix + path
}

// HistoricalSource allows for retrieval of historical metrics and aggregations from sinks
type HistoricalSource interface {
	// GetMetric retrieves the given metric for one or more objects (specified by metricKeys) of
	// the same type, within the given time interval.  A start time of zero indicates no starting bound,
	// while an end time of zero indicates no ending bound.
	GetMetric(metricName string, metricKeys []HistoricalKey, start, end time.Time) (map[HistoricalKey][]TimestampedMetricValue, error)

	// GetLabeledMetric retrieves the given labeled metric.  Otherwise, it functions identically to GetMetric.
	GetLabeledMetric(metricName string, labels map[string]string, metricKeys []HistoricalKey, start, end time.Time) (map[HistoricalKey][]TimestampedMetricValue, error)

	// GetAggregation fetches the given aggregations for one or more objects (specified by metricKeys) of
	// the same type, within the given time interval, calculated over a series of buckets.  The start time,
	// end time, and bucket size may be zero.  A start time of zero indicates no starting bound, while and
	// end time of zero indicates no ending bound (effectively meaning up to the latest metrics, but not metrics
	// from the future).  A bucket size of zero indicates that only a single bucket spanning the entire specified
	// time range should be returned.
	GetAggregation(metricName string, aggregations []AggregationType, metricKeys []HistoricalKey, start, end time.Time, bucketSize time.Duration) (map[HistoricalKey][]TimestampedAggregationValue, error)

	// GetLabeledAggregation fetches a the given aggregations for a labeled metric instead of a normal metric.
	// Otherwise, it functions identically to GetAggregation.
	GetLabeledAggregation(metricName string, labels map[string]string, aggregations []AggregationType, metricKeys []HistoricalKey, start, end time.Time, bucketSize time.Duration) (map[HistoricalKey][]TimestampedAggregationValue, error)

	// GetMetricNames retrieves the available metric names for the given object
	GetMetricNames(metricKey HistoricalKey) ([]string, error)

	// GetNodes retrieves the list of nodes in the cluster
	GetNodes() ([]string, error)
	// GetNamespaces retrieves the list of namespaces in the cluster
	GetNamespaces() ([]string, error)
	// GetPodsFromNamespace retrieves the list of pods in a given namespace
	GetPodsFromNamespace(namespace string) ([]string, error)
	// GetSystemContainersFromNode retrieves the list of free containers for a given node
	GetSystemContainersFromNode(node string) ([]string, error)
}

// AsHistoricalSource represents sinks which support a historical access interface
type AsHistoricalSource interface {
	// Historical returns the historical data access interface for this sink
	Historical() HistoricalSource
}
<commit_msg>Remove unused historical types<commit_after><|endoftext|>


<commit_before>package sync

import (
	"net"
	"sync"
	"testing"
	"time"
)

// TestThreadGroup tests normal operation of a ThreadGroup.
func TestThreadGroup(t *testing.T) {
	var tg ThreadGroup
	for i := 0; i < 10; i++ {
		err := tg.Add()
		if err != nil {
			t.Fatal(err)
		}

		go func() {
			defer tg.Done()
			select {
			case <-time.After(1 * time.Second):
			case <-tg.StopChan():
			}
		}()
	}
	start := time.Now()
	err := tg.Stop()
	elapsed := time.Since(start)
	if err != nil {
		t.Fatal(err)
	} else if elapsed > 100*time.Millisecond {
		t.Fatal("Stop did not interrupt goroutines")
	}
}

// TestThreadGroupStop tests the behavior of a ThreadGroup after Stop has been
// called.
func TestThreadGroupStop(t *testing.T) {
	var tg ThreadGroup

	// IsStopped should return false
	if tg.IsStopped() {
		t.Error("IsStopped returns true on unstopped ThreadGroup")
	}

	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}

	// IsStopped should return true
	if !tg.IsStopped() {
		t.Error("IsStopped returns false on stopped ThreadGroup")
	}

	// Add, Stop, and RegisterCloser should return errors
	err = tg.Add()
	if err != ErrStopped {
		t.Error("expected ErrStopped, got", err)
	}
	err = tg.Stop()
	if err != ErrStopped {
		t.Error("expected ErrStopped, got", err)
	}
	err = tg.OnStop(nil)
	if err != ErrStopped {
		t.Error("expected ErrStopped, got", err)
	}
}

// TestThreadGroupConcurrentAdd tests that Add can be called concurrently with Stop.
func TestThreadGroupConcurrentAdd(t *testing.T) {
	var tg ThreadGroup
	for i := 0; i < 10; i++ {
		go func() {
			err := tg.Add()
			if err != nil {
				return
			}
			defer tg.Done()

			select {
			case <-time.After(1 * time.Second):
			case <-tg.StopChan():
			}
		}()
	}
	time.Sleep(10 * time.Millisecond) // wait for at least one Add
	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}
}

// TestThreadGroupOnce tests that a zero-valued ThreadGroup's stopChan is
// properly initialized.
func TestThreadGroupOnce(t *testing.T) {
	tg := new(ThreadGroup)
	if tg.stopChan != nil {
		t.Error("expected nil stopChan")
	}

	// these methods should cause stopChan to be initialized
	tg.StopChan()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by StopChan")
	}

	tg = new(ThreadGroup)
	tg.IsStopped()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by IsStopped")
	}

	tg = new(ThreadGroup)
	tg.Add()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by Add")
	}

	tg = new(ThreadGroup)
	tg.Stop()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by Stop")
	}
}

// TestThreadGroupOnStop tests that Stop calls functions registered with
// OnStop.
func TestThreadGroupOnStop(t *testing.T) {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}

	// create ThreadGroup and register the closer
	var tg ThreadGroup
	err = tg.OnStop(func() { l.Close() })
	if err != nil {
		t.Fatal(err)
	}

	// send on channel when listener is closed
	var closed bool
	tg.Add()
	go func() {
		defer tg.Done()
		_, err := l.Accept()
		closed = err != nil
	}()

	tg.Stop()
	if !closed {
		t.Fatal("Stop did not close listener")
	}
}

// TestThreadGroupRace tests that calling ThreadGroup methods concurrently
// does not trigger the race detector.
func TestThreadGroupRace(t *testing.T) {
	var tg ThreadGroup
	go tg.IsStopped()
	go tg.StopChan()
	go func() {
		if tg.Add() == nil {
			tg.Done()
		}
	}()
	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}
}

func BenchmarkThreadGroup(b *testing.B) {
	var tg ThreadGroup
	for i := 0; i < b.N; i++ {
		tg.Add()
		go tg.Done()
	}
	tg.Stop()
}

func BenchmarkWaitGroup(b *testing.B) {
	var wg sync.WaitGroup
	for i := 0; i < b.N; i++ {
		wg.Add(1)
		go wg.Done()
	}
	wg.Wait()
}
<commit_msg>update tests that use OnStop<commit_after>package sync

import (
	"net"
	"sync"
	"testing"
	"time"
)

// TestThreadGroup tests normal operation of a ThreadGroup.
func TestThreadGroup(t *testing.T) {
	var tg ThreadGroup
	for i := 0; i < 10; i++ {
		err := tg.Add()
		if err != nil {
			t.Fatal(err)
		}

		go func() {
			defer tg.Done()
			select {
			case <-time.After(1 * time.Second):
			case <-tg.StopChan():
			}
		}()
	}
	start := time.Now()
	err := tg.Stop()
	elapsed := time.Since(start)
	if err != nil {
		t.Fatal(err)
	} else if elapsed > 100*time.Millisecond {
		t.Fatal("Stop did not interrupt goroutines")
	}
}

// TestThreadGroupStop tests the behavior of a ThreadGroup after Stop has been
// called.
func TestThreadGroupStop(t *testing.T) {
	var tg ThreadGroup

	// IsStopped should return false
	if tg.IsStopped() {
		t.Error("IsStopped returns true on unstopped ThreadGroup")
	}

	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}

	// IsStopped should return true
	if !tg.IsStopped() {
		t.Error("IsStopped returns false on stopped ThreadGroup")
	}

	// Add and Stop should return errors
	err = tg.Add()
	if err != ErrStopped {
		t.Error("expected ErrStopped, got", err)
	}
	err = tg.Stop()
	if err != ErrStopped {
		t.Error("expected ErrStopped, got", err)
	}
}

// TestThreadGroupConcurrentAdd tests that Add can be called concurrently with Stop.
func TestThreadGroupConcurrentAdd(t *testing.T) {
	var tg ThreadGroup
	for i := 0; i < 10; i++ {
		go func() {
			err := tg.Add()
			if err != nil {
				return
			}
			defer tg.Done()

			select {
			case <-time.After(1 * time.Second):
			case <-tg.StopChan():
			}
		}()
	}
	time.Sleep(10 * time.Millisecond) // wait for at least one Add
	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}
}

// TestThreadGroupOnce tests that a zero-valued ThreadGroup's stopChan is
// properly initialized.
func TestThreadGroupOnce(t *testing.T) {
	tg := new(ThreadGroup)
	if tg.stopChan != nil {
		t.Error("expected nil stopChan")
	}

	// these methods should cause stopChan to be initialized
	tg.StopChan()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by StopChan")
	}

	tg = new(ThreadGroup)
	tg.IsStopped()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by IsStopped")
	}

	tg = new(ThreadGroup)
	tg.Add()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by Add")
	}

	tg = new(ThreadGroup)
	tg.Stop()
	if tg.stopChan == nil {
		t.Error("stopChan should have been initialized by Stop")
	}
}

// TestThreadGroupOnStop tests that Stop calls functions registered with
// OnStop.
func TestThreadGroupOnStop(t *testing.T) {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}

	// create ThreadGroup and register the closer
	var tg ThreadGroup
	tg.OnStop(func() { l.Close() })

	// send on channel when listener is closed
	var closed bool
	tg.Add()
	go func() {
		defer tg.Done()
		_, err := l.Accept()
		closed = err != nil
	}()

	tg.Stop()
	if !closed {
		t.Fatal("Stop did not close listener")
	}
}

// TestThreadGroupRace tests that calling ThreadGroup methods concurrently
// does not trigger the race detector.
func TestThreadGroupRace(t *testing.T) {
	var tg ThreadGroup
	go tg.IsStopped()
	go tg.StopChan()
	go func() {
		if tg.Add() == nil {
			tg.Done()
		}
	}()
	err := tg.Stop()
	if err != nil {
		t.Fatal(err)
	}
}

func BenchmarkThreadGroup(b *testing.B) {
	var tg ThreadGroup
	for i := 0; i < b.N; i++ {
		tg.Add()
		go tg.Done()
	}
	tg.Stop()
}

func BenchmarkWaitGroup(b *testing.B) {
	var wg sync.WaitGroup
	for i := 0; i < b.N; i++ {
		wg.Add(1)
		go wg.Done()
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>// Package vsphere provides a small set of the vSphere Web Services API.
package vsphere // import "bosun.org/vsphere"

import (
	"bytes"
	"crypto/tls"
	"encoding/xml"
	"fmt"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)

// Vsphere holds connection state for a vSphere session.
type Vsphere struct {
	url     *url.URL
	header  http.Header
	cookies http.CookieJar
	client  *http.Client
}

// Connect connects and logs in to a vSphere host.
func Connect(host, user, pwd string) (*Vsphere, error) {
	header := http.Header{
		"Content-Type": []string{`text/xml; charset=UTF-8`},
		"SOAPAction":   []string{`"urn:vim25/5.5"`},
	}
	jar, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}
	v := &Vsphere{
		url: &url.URL{
			Scheme: "https",
			Host:   host,
			Path:   "/sdk",
		},
		header: header,
		client: &http.Client{
			Timeout: time.Minute,
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		},
		cookies: jar,
	}
	uuid := struct {
		UUID string `xml:"Body>RetrieveServiceContentResponse>returnval>about>instanceUuid"`
	}{}
	if err := v.call(soapConnect, &uuid); err != nil {
		return nil, err
	}
	if uuid.UUID == "" {
		return nil, fmt.Errorf("vsphere: no UUID during connect")
	}
	if err := v.call(fmt.Sprintf(soapLogin, user, pwd), nil); err != nil {
		return nil, err
	}
	return v, nil
}

// Result contains requested data about vSphere objects.
type Result struct {
	ID    string `xml:"obj"`
	Props []struct {
		Name string `xml:"name"`
		Val  struct {
			Type  string `xml:"type,attr"`
			Inner string `xml:",innerxml"`
		} `xml:"val"`
	} `xml:"propSet"`
}

// Info queries listed properties of all objects of the specified Type.
func (v *Vsphere) Info(Type string, properties []string) ([]*Result, error) {
	var props struct {
		Folder string `xml:"Body>RetrievePropertiesResponse>returnval>propSet>val>rootFolder"`
	}
	if err := v.call(soapRetrieveServiceInstance, &props); err != nil {
		return nil, err
	}
	var view struct {
		Session string `xml:"Body>CreateContainerViewResponse>returnval"`
	}
	for i, v := range properties {
		properties[i] = fmt.Sprintf("<pathSet>%s</pathSet>", v)
	}
	if err := v.call(fmt.Sprintf(soapCreateContainerView, props.Folder, Type), &view); err != nil {
		return nil, err
	}
	var vms struct {
		Results []*Result `xml:"Body>RetrievePropertiesResponse>returnval"`
	}
	if err := v.call(fmt.Sprintf(soapRetrieve, Type, strings.Join(properties, ""), view.Session), &vms); err != nil {
		return nil, err
	}
	return vms.Results, nil
}

func (v *Vsphere) call(body string, dst interface{}) error {
	buf := new(bytes.Buffer)
	buf.WriteString(soapPre)
	buf.WriteString(body)
	buf.WriteString(soapPost)
	req, err := http.NewRequest("POST", v.url.String(), buf)
	if err != nil {
		return err
	}
	for k, v := range v.header {
		req.Header[k] = v
	}
	for _, c := range v.cookies.Cookies(v.url) {
		req.AddCookie(c)
	}
	resp, err := v.client.Do(req)
	if err != nil {
		return err
	}
	v.cookies.SetCookies(v.url, resp.Cookies())
	defer resp.Body.Close()
	if resp.StatusCode == 500 {
		var e Error
		if err := xml.NewDecoder(resp.Body).Decode(&e); err != nil {
			return fmt.Errorf("vsphere: bad response, could not decode error: %v", err)
		}
		return e
	} else if resp.StatusCode != 200 {
		return fmt.Errorf("vsphere: bad status code %v", resp.Status)
	}
	if dst != nil {
		return xml.NewDecoder(resp.Body).Decode(dst)
	}
	return nil
}

// Error can be returned from any call to a Vsphere object, including Connect.
type Error struct {
	Code   string `xml:"Body>Fault>faultcode"`
	String string `xml:"Body>Fault>faultstring"`
	Detail struct {
		Inner string `xml:",innerxml"`
	} `xml:"Body>Fault>detail"`
}

func (e Error) Error() string {
	if e.String != "" {
		return e.String
	}
	return e.Detail.Inner
}

const (
	soapPre  = `<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>`
	soapPost = `</soapenv:Body></soapenv:Envelope>`

	soapConnect                 = `<RetrieveServiceContent xmlns="urn:vim25"><_this type="ServiceInstance">ServiceInstance</_this></RetrieveServiceContent>`
	soapLogin                   = `<Login xmlns="urn:vim25"><_this type="SessionManager">SessionManager</_this><userName>%s</userName><password>%s</password></Login>`
	soapRetrieveServiceInstance = `<RetrieveProperties xmlns="urn:vim25"><_this type="PropertyCollector">propertyCollector</_this><specSet><propSet><type>ServiceInstance</type><all>false</all><pathSet>content</pathSet></propSet><objectSet><obj type="ServiceInstance">ServiceInstance</obj><skip>false</skip></objectSet></specSet></RetrieveProperties>`
	soapCreateContainerView     = `<CreateContainerView xmlns="urn:vim25"><_this type="ViewManager">ViewManager</_this><container type="Folder">%s</container><type>%s</type><recursive>true</recursive></CreateContainerView>`
	soapRetrieve                = `<RetrieveProperties xmlns="urn:vim25"><_this type="PropertyCollector">propertyCollector</_this><specSet><propSet><type>%s</type>%s</propSet><objectSet><obj type="ContainerView">%s</obj><skip>true</skip><selectSet xsi:type="TraversalSpec"><name>traverseEntities</name><type>ContainerView</type><path>view</path><skip>false</skip></selectSet></objectSet></specSet></RetrieveProperties>`
)
<commit_msg>Escape soapLogin credentials<commit_after>// Package vsphere provides a small set of the vSphere Web Services API.
package vsphere // import "bosun.org/vsphere"

import (
	"bytes"
	"crypto/tls"
	"encoding/xml"
	"fmt"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)

// Vsphere holds connection state for a vSphere session.
type Vsphere struct {
	url     *url.URL
	header  http.Header
	cookies http.CookieJar
	client  *http.Client
}

// Connect connects and logs in to a vSphere host.
func Connect(host, user, pwd string) (*Vsphere, error) {
	header := http.Header{
		"Content-Type": []string{`text/xml; charset=UTF-8`},
		"SOAPAction":   []string{`"urn:vim25/5.5"`},
	}
	jar, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}
	v := &Vsphere{
		url: &url.URL{
			Scheme: "https",
			Host:   host,
			Path:   "/sdk",
		},
		header: header,
		client: &http.Client{
			Timeout: time.Minute,
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		},
		cookies: jar,
	}
	uuid := struct {
		UUID string `xml:"Body>RetrieveServiceContentResponse>returnval>about>instanceUuid"`
	}{}
	if err := v.call(soapConnect, &uuid); err != nil {
		return nil, err
	}
	if uuid.UUID == "" {
		return nil, fmt.Errorf("vsphere: no UUID during connect")
	}
	userbuf := new(bytes.Buffer)
	pwdbuf := new(bytes.Buffer)
	xml.EscapeText(userbuf, []byte(user))
	xml.EscapeText(pwdbuf, []byte(pwd))
	if err := v.call(fmt.Sprintf(soapLogin, userbuf, pwdbuf), nil); err != nil {
		return nil, err
	}
	return v, nil
}

// Result contains requested data about vSphere objects.
type Result struct {
	ID    string `xml:"obj"`
	Props []struct {
		Name string `xml:"name"`
		Val  struct {
			Type  string `xml:"type,attr"`
			Inner string `xml:",innerxml"`
		} `xml:"val"`
	} `xml:"propSet"`
}

// Info queries listed properties of all objects of the specified Type.
func (v *Vsphere) Info(Type string, properties []string) ([]*Result, error) {
	var props struct {
		Folder string `xml:"Body>RetrievePropertiesResponse>returnval>propSet>val>rootFolder"`
	}
	if err := v.call(soapRetrieveServiceInstance, &props); err != nil {
		return nil, err
	}
	var view struct {
		Session string `xml:"Body>CreateContainerViewResponse>returnval"`
	}
	for i, v := range properties {
		properties[i] = fmt.Sprintf("<pathSet>%s</pathSet>", v)
	}
	if err := v.call(fmt.Sprintf(soapCreateContainerView, props.Folder, Type), &view); err != nil {
		return nil, err
	}
	var vms struct {
		Results []*Result `xml:"Body>RetrievePropertiesResponse>returnval"`
	}
	if err := v.call(fmt.Sprintf(soapRetrieve, Type, strings.Join(properties, ""), view.Session), &vms); err != nil {
		return nil, err
	}
	return vms.Results, nil
}

func (v *Vsphere) call(body string, dst interface{}) error {
	buf := new(bytes.Buffer)
	buf.WriteString(soapPre)
	buf.WriteString(body)
	buf.WriteString(soapPost)
	req, err := http.NewRequest("POST", v.url.String(), buf)
	if err != nil {
		return err
	}
	for k, v := range v.header {
		req.Header[k] = v
	}
	for _, c := range v.cookies.Cookies(v.url) {
		req.AddCookie(c)
	}
	resp, err := v.client.Do(req)
	if err != nil {
		return err
	}
	v.cookies.SetCookies(v.url, resp.Cookies())
	defer resp.Body.Close()
	if resp.StatusCode == 500 {
		var e Error
		if err := xml.NewDecoder(resp.Body).Decode(&e); err != nil {
			return fmt.Errorf("vsphere: bad response, could not decode error: %v", err)
		}
		return e
	} else if resp.StatusCode != 200 {
		return fmt.Errorf("vsphere: bad status code %v", resp.Status)
	}
	if dst != nil {
		return xml.NewDecoder(resp.Body).Decode(dst)
	}
	return nil
}

// Error can be returned from any call to a Vsphere object, including Connect.
type Error struct {
	Code   string `xml:"Body>Fault>faultcode"`
	String string `xml:"Body>Fault>faultstring"`
	Detail struct {
		Inner string `xml:",innerxml"`
	} `xml:"Body>Fault>detail"`
}

func (e Error) Error() string {
	if e.String != "" {
		return e.String
	}
	return e.Detail.Inner
}

const (
	soapPre  = `<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>`
	soapPost = `</soapenv:Body></soapenv:Envelope>`

	soapConnect                 = `<RetrieveServiceContent xmlns="urn:vim25"><_this type="ServiceInstance">ServiceInstance</_this></RetrieveServiceContent>`
	soapLogin                   = `<Login xmlns="urn:vim25"><_this type="SessionManager">SessionManager</_this><userName>%s</userName><password>%s</password></Login>`
	soapRetrieveServiceInstance = `<RetrieveProperties xmlns="urn:vim25"><_this type="PropertyCollector">propertyCollector</_this><specSet><propSet><type>ServiceInstance</type><all>false</all><pathSet>content</pathSet></propSet><objectSet><obj type="ServiceInstance">ServiceInstance</obj><skip>false</skip></objectSet></specSet></RetrieveProperties>`
	soapCreateContainerView     = `<CreateContainerView xmlns="urn:vim25"><_this type="ViewManager">ViewManager</_this><container type="Folder">%s</container><type>%s</type><recursive>true</recursive></CreateContainerView>`
	soapRetrieve                = `<RetrieveProperties xmlns="urn:vim25"><_this type="PropertyCollector">propertyCollector</_this><specSet><propSet><type>%s</type>%s</propSet><objectSet><obj type="ContainerView">%s</obj><skip>true</skip><selectSet xsi:type="TraversalSpec"><name>traverseEntities</name><type>ContainerView</type><path>view</path><skip>false</skip></selectSet></objectSet></specSet></RetrieveProperties>`
)
<|endoftext|>


<commit_before>package dh

import (
	"encoding/json"
	"fmt"
	"github.com/devicehive/devicehive-go/internal/transport"
	"strconv"
	"strings"
)

type Client struct {
	tsp          transport.Transporter
	accessToken  string
	refreshToken string
	login        string
	password     string
}

func (c *Client) authenticate(token string) (result bool, err *Error) {
	if c.tsp.IsHTTP() {
		c.accessToken = token
		return true, nil
	} else {
		_, err := c.request("auth", map[string]interface{}{
			"token": token,
		})

		if err != nil {
			return false, err
		}

		return true, nil
	}
}

func (c *Client) subscribe(resourceName string, params *SubscribeParams) (tspChan chan []byte, subscriptionId string, err *Error) {
	if params == nil {
		params = &SubscribeParams{}
	}

	data, jsonErr := params.Map()

	if jsonErr != nil {
		return nil, "", &Error{name: InvalidRequestErr, reason: jsonErr.Error()}
	}

	rawRes, err := c.request(resourceName, data)

	if err != nil {
		return nil, "", err
	}

	type subsId struct {
		Value int64 `json:"subscriptionId"`
	}
	id := &subsId{}

	parseErr := json.Unmarshal(rawRes, id)

	if parseErr != nil {
		return nil, "", newJSONErr()
	}

	subscriptionId = strconv.FormatInt(id.Value, 10)

	return c.tsp.Subscribe(subscriptionId), subscriptionId, nil
}

func (c *Client) unsubscribe(resourceName, subscriptionId string) *Error {
	_, err := c.request(resourceName, map[string]interface{}{
		"subscriptionId": subscriptionId,
	})

	if err != nil {
		return err
	}

	c.tsp.Unsubscribe(subscriptionId)

	return nil
}

func (c *Client) request(resourceName string, data map[string]interface{}) (resBytes []byte, err *Error) {
	resource, method := c.resolveResource(resourceName)

	if resource == "" {
		return nil, &Error{name: InvalidRequestErr, reason: "unknown resource name"}
	}

	tspReqParams := &transport.RequestParams{
		Data: make(map[string]interface{}),
	}

	if c.tsp.IsHTTP() {
		if method != "" {
			tspReqParams.Method = method
		}

		tspReqParams.AccessToken = c.accessToken
	}

	for k, v := range data {
		tspReqParams.Data[k] = v
	}

	resBytes, tspErr := c.tsp.Request(resource, tspReqParams, Timeout)

	if tspErr != nil {
		return nil, newTransportErr(tspErr)
	}

	err = c.handleResponse(resBytes)

	return resBytes, err
}

func (c *Client) handleResponse(resBytes []byte) (err *Error) {
	// @TODO Refactor this conditions
	if c.tsp.IsWS() {
		res := &response{}
		parseErr := json.Unmarshal(resBytes, res)

		if parseErr != nil {
			return newJSONErr()
		}

		if res.Status == "error" {
			errMsg := strings.ToLower(res.Error)
			errCode := res.Code
			r := fmt.Sprintf("%d %s", errCode, errMsg)
			return &Error{name: ServiceErr, reason: r}
		}
	} else {
		res := &httpResponse{}

		parseErr := json.Unmarshal(resBytes, res)

		if parseErr != nil {
			return newJSONErr()
		}

		if res.Status >= 400 {
			errMsg := strings.ToLower(res.Error)
			errCode := res.Status
			r := fmt.Sprintf("%d %s", errCode, errMsg)
			return &Error{name: ServiceErr, reason: r}
		}
	}

	return nil
}
<commit_msg>Move request params creation to separate method of Client<commit_after>package dh

import (
	"encoding/json"
	"fmt"
	"github.com/devicehive/devicehive-go/internal/transport"
	"strconv"
	"strings"
)

type Client struct {
	tsp          transport.Transporter
	accessToken  string
	refreshToken string
	login        string
	password     string
}

func (c *Client) authenticate(token string) (result bool, err *Error) {
	if c.tsp.IsHTTP() {
		c.accessToken = token
		return true, nil
	} else {
		_, err := c.request("auth", map[string]interface{}{
			"token": token,
		})

		if err != nil {
			return false, err
		}

		return true, nil
	}
}

func (c *Client) subscribe(resourceName string, params *SubscribeParams) (tspChan chan []byte, subscriptionId string, err *Error) {
	if params == nil {
		params = &SubscribeParams{}
	}

	data, jsonErr := params.Map()

	if jsonErr != nil {
		return nil, "", &Error{name: InvalidRequestErr, reason: jsonErr.Error()}
	}

	rawRes, err := c.request(resourceName, data)

	if err != nil {
		return nil, "", err
	}

	type subsId struct {
		Value int64 `json:"subscriptionId"`
	}
	id := &subsId{}

	parseErr := json.Unmarshal(rawRes, id)

	if parseErr != nil {
		return nil, "", newJSONErr()
	}

	subscriptionId = strconv.FormatInt(id.Value, 10)

	return c.tsp.Subscribe(subscriptionId), subscriptionId, nil
}

func (c *Client) unsubscribe(resourceName, subscriptionId string) *Error {
	_, err := c.request(resourceName, map[string]interface{}{
		"subscriptionId": subscriptionId,
	})

	if err != nil {
		return err
	}

	c.tsp.Unsubscribe(subscriptionId)

	return nil
}

func (c *Client) request(resourceName string, data map[string]interface{}) (resBytes []byte, err *Error) {
	resource, method := c.resolveResource(resourceName)

	if resource == "" {
		return nil, &Error{name: InvalidRequestErr, reason: "unknown resource name"}
	}

	tspReqParams := c.createRequestParams(method, data)

	resBytes, tspErr := c.tsp.Request(resource, tspReqParams, Timeout)

	if tspErr != nil {
		return nil, newTransportErr(tspErr)
	}

	err = c.handleResponse(resBytes)

	return resBytes, err
}

func (c *Client) handleResponse(resBytes []byte) (err *Error) {
	// @TODO Refactor this conditions
	if c.tsp.IsWS() {
		res := &response{}
		parseErr := json.Unmarshal(resBytes, res)

		if parseErr != nil {
			return newJSONErr()
		}

		if res.Status == "error" {
			errMsg := strings.ToLower(res.Error)
			errCode := res.Code
			r := fmt.Sprintf("%d %s", errCode, errMsg)
			return &Error{name: ServiceErr, reason: r}
		}
	} else {
		res := &httpResponse{}

		parseErr := json.Unmarshal(resBytes, res)

		if parseErr != nil {
			return newJSONErr()
		}

		if res.Status >= 400 {
			errMsg := strings.ToLower(res.Error)
			errCode := res.Status
			r := fmt.Sprintf("%d %s", errCode, errMsg)
			return &Error{name: ServiceErr, reason: r}
		}
	}

	return nil
}

func (c *Client) createRequestParams(method string, data map[string]interface{}) *transport.RequestParams {
	tspReqParams := &transport.RequestParams{
		Data: make(map[string]interface{}),
	}

	if c.tsp.IsHTTP() {
		if method != "" {
			tspReqParams.Method = method
		}

		tspReqParams.AccessToken = c.accessToken
	}

	for k, v := range data {
		tspReqParams.Data[k] = v
	}

	return tspReqParams
}
<|endoftext|>


<commit_before>package amqputil

import (
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/fsouza/go-dockerclient"
)

var (
	dockerClient *docker.Client
)

func TestMain(m *testing.M) {
	var err error

	fmt.Printf("Starting backends\n")
	endpoint := "unix:///var/run/docker.sock"
	dockerClient, err = docker.NewClient(endpoint)

	if err != nil {
		fmt.Printf("Error connecting to docker daemon...")
		os.Exit(1)
	}

	rmRabbit()

	status := m.Run()

	rmRabbit()

	os.Exit(status)
}
func rmRabbit() {
	fmt.Printf("Removing rabbitmq backend\n")
	rmCtnOpt := docker.RemoveContainerOptions{
		ID:            "rabbitmq-tests",
		RemoveVolumes: true,
		Force:         true,
	}

	_ = dockerClient.RemoveContainer(rmCtnOpt)
}

func pullRabbit() error {
	pullOpts := docker.PullImageOptions{
		Repository:   "rabbitmq",
		Tag:          "latest",
		OutputStream: os.Stdout,
	}

	err := dockerClient.PullImage(pullOpts, docker.AuthConfiguration{})

	if err != nil {
		return err
	}

	return nil
}

func runRabbit() (*docker.Container, error) {
	var pulled bool
try:
	opts := docker.CreateContainerOptions{
		Name: "rabbitmq-tests",
		Config: &docker.Config{
			Image: "rabbitmq",
			ExposedPorts: map[docker.Port]struct{}{
				"5672/tcp": {},
			},
		},
		HostConfig: &docker.HostConfig{
			PortBindings: map[docker.Port][]docker.PortBinding{
				"5672/tcp": []docker.PortBinding{docker.PortBinding{HostPort: "5672"}}},
			PublishAllPorts: true,
			Privileged:      false,
		},
	}

	rabbitCtn, err := dockerClient.CreateContainer(opts)

	if err != nil {
		if !pulled {
			err = pullRabbit()

			if err != nil {
				return nil, err
			}

			pulled = true
			goto try
		}

		return nil, err
	}

	err = dockerClient.StartContainer(rabbitCtn.ID, nil)

	if err != nil {
		return nil, err
	}

	return rabbitCtn, nil
}

func TestDial(t *testing.T) {
	conn := New()
	err := conn.Dial("amqp://guest:guest@localhost:5672/%2f")

	if err == nil {
		t.Error("No backend started... Should fail")
		return
	}

	rabbitCtn, err := runRabbit()
	if err != nil {
		t.Error(err)
	}

	// Wait a few seconds to rabbitmq finish the setup
	time.Sleep(3 * time.Second)

	err = conn.Dial("amqp://guest:guest@localhost:5672/%2f")

	if err != nil {
		t.Error(err)
		return
	}

	conn.AutoRedial()

	dockerClient.StopContainer(rabbitCtn.ID, 3)

	time.Sleep(10 * time.Second)

	err = dockerClient.StartContainer(rabbitCtn.ID, nil)

	if err != nil {
		t.Error(err)
		return
	}

	time.Sleep(3 * time.Second)

	fmt.Println(rabbitCtn)
}
<commit_msg>[CHANGE] added delay to reconnect<commit_after>package amqputil

import (
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/fsouza/go-dockerclient"
)

var (
	dockerClient *docker.Client
)

func TestMain(m *testing.M) {
	var err error

	fmt.Printf("Starting backends\n")
	endpoint := "unix:///var/run/docker.sock"
	dockerClient, err = docker.NewClient(endpoint)

	if err != nil {
		fmt.Printf("Error connecting to docker daemon...")
		os.Exit(1)
	}

	rmRabbit()

	status := m.Run()

	rmRabbit()

	os.Exit(status)
}
func rmRabbit() {
	fmt.Printf("Removing rabbitmq backend\n")
	rmCtnOpt := docker.RemoveContainerOptions{
		ID:            "rabbitmq-tests",
		RemoveVolumes: true,
		Force:         true,
	}

	_ = dockerClient.RemoveContainer(rmCtnOpt)
}

func pullRabbit() error {
	pullOpts := docker.PullImageOptions{
		Repository:   "rabbitmq",
		Tag:          "latest",
		OutputStream: os.Stdout,
	}

	err := dockerClient.PullImage(pullOpts, docker.AuthConfiguration{})

	if err != nil {
		return err
	}

	return nil
}

func runRabbit() (*docker.Container, error) {
	var pulled bool
try:
	opts := docker.CreateContainerOptions{
		Name: "rabbitmq-tests",
		Config: &docker.Config{
			Image: "rabbitmq",
			ExposedPorts: map[docker.Port]struct{}{
				"5672/tcp": {},
			},
		},
		HostConfig: &docker.HostConfig{
			PortBindings: map[docker.Port][]docker.PortBinding{
				"5672/tcp": []docker.PortBinding{docker.PortBinding{HostPort: "5672"}}},
			PublishAllPorts: true,
			Privileged:      false,
		},
	}

	rabbitCtn, err := dockerClient.CreateContainer(opts)

	if err != nil {
		if !pulled {
			err = pullRabbit()

			if err != nil {
				return nil, err
			}

			pulled = true
			goto try
		}

		return nil, err
	}

	err = dockerClient.StartContainer(rabbitCtn.ID, nil)

	if err != nil {
		return nil, err
	}

	return rabbitCtn, nil
}

func TestDial(t *testing.T) {
	conn := New()
	err := conn.Dial("amqp://guest:guest@localhost:5672/%2f")

	if err == nil {
		t.Error("No backend started... Should fail")
		return
	}

	rabbitCtn, err := runRabbit()
	if err != nil {
		t.Error(err)
	}

	// Wait a few seconds to rabbitmq finish the setup
	time.Sleep(3 * time.Second)

	err = conn.Dial("amqp://guest:guest@localhost:5672/%2f")

	if err != nil {
		t.Error(err)
		return
	}

	conn.AutoRedial()

	dockerClient.StopContainer(rabbitCtn.ID, 3)

	time.Sleep(10 * time.Second)

	err = dockerClient.StartContainer(rabbitCtn.ID, nil)

	if err != nil {
		t.Error(err)
		return
	}

	time.Sleep(5 * time.Second)

	conn.Conn.Close()
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 main

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/concurrent"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/sys"
	"log"
	"runtime"
	"sync"
)

var g_dirSaverOnce sync.Once
var g_dirSaver backup.DirectorySaver

func initDirSaver() {
	blobStore := getBlobStore()

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalln("Creating user registry:", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalln("Creating group registry:", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalln("Creating file system:", err)
	}

	// Create the file saver.
	const chunkSize = 1 << 24 // 16 MiB
	numFileSaverWorkers := runtime.NumCPU()

	fileSaver, err := backup.NewFileSaver(
		blobStore,
		chunkSize,
		concurrent.NewExecutor(numFileSaverWorkers),
	)

	if err != nil {
		log.Fatalln("Creating file saver:", err)
	}

	// Create the directory saver.
	g_dirSaver, err = backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalln("Creating directory saver:", err)
	}
}

func getDirSaver() backup.DirectorySaver {
	g_dirSaverOnce.Do(initDirSaver)
	return g_dirSaver
}
<commit_msg>Don't forget to set GOMAXPROCS.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 main

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/concurrent"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/sys"
	"log"
	"runtime"
	"sync"
)

var g_dirSaverOnce sync.Once
var g_dirSaver backup.DirectorySaver

func initDirSaver() {
	blobStore := getBlobStore()

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalln("Creating user registry:", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalln("Creating group registry:", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalln("Creating file system:", err)
	}

	// Set up parallelism. Leave one CPU alone, if possible.
	numCPUs := runtime.NumCPU()

	numFileSaverWorkers := numCPUs
	if numCPUs > 1 {
		numFileSaverWorkers--
	}

	runtime.GOMAXPROCS(numFileSaverWorkers)

	// Create the file saver.
	const chunkSize = 1 << 24 // 16 MiB

	fileSaver, err := backup.NewFileSaver(
		blobStore,
		chunkSize,
		concurrent.NewExecutor(numFileSaverWorkers),
	)

	if err != nil {
		log.Fatalln("Creating file saver:", err)
	}

	// Create the directory saver.
	g_dirSaver, err = backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalln("Creating directory saver:", err)
	}
}

func getDirSaver() backup.DirectorySaver {
	g_dirSaverOnce.Do(initDirSaver)
	return g_dirSaver
}
<|endoftext|>


<commit_before>// Lib to handle any disk related operations, including mounting .dmg files, etc

package macosutils

import (
	"github.com/groob/plist"
	"log"
	"os/exec"
)

type SystemEntities struct {
	Disks []DiskEntries `plist:"system-entities"`
}

type DiskEntries struct {
	Disk *string `plist:"mount-point"`
}

func MountDmg(dmgPath string) string {
	args := []string{"attach", dmgPath, "-mountRandom", "/tmp", "-nobrowse", "-plist"}
	out, err := exec.Command("/usr/bin/hdiutil", args...).Output()
	if err != nil {
		log.Fatal(err)
	}

	var mountinfo SystemEntities
	err = plist.Unmarshal(out, &mountinfo)
	if err != nil {
		log.Fatal(err)
	}

	mount := MountPoint(mountinfo)
	return mount
}

func UnmountDmg(dmgPath string) bool {
	args := []string{"detach", dmgPath}
	_, err := exec.Command("/usr/bin/hdiutil", args...).Output()
	if err != nil {
		log.Fatal(err)
		return false
	} else {
		return true
	}
}

func MountPoint(mountinfo SystemEntities) string {
	for _, v := range mountinfo.Disks {
		if v.Disk != nil {
			return *v.Disk
		}
	}
	return ""
}
<commit_msg>Made a dmg struct and added functions to it<commit_after>// Lib to handle any disk related operations, including mounting .dmg files, etc

package macosutils

import (
	"fmt"
	"github.com/groob/plist"
	"log"
	"os/exec"
)

type DMG struct {
	MountPoint string
}

type SystemEntities struct {
	Disks []DiskEntries `plist:"system-entities"`
}

type DiskEntries struct {
	Disk *string `plist:"mount-point"`
}

func (d *DMG) Mount(dmgPath string) {
	fmt.Printf("Mounting dmg located at %v\n", dmgPath)
	args := []string{"attach", dmgPath, "-mountRandom", "/tmp", "-nobrowse", "-plist"}
	out, err := exec.Command("/usr/bin/hdiutil", args...).Output()
	if err != nil {
		log.Fatal(err)
	}

	var mountinfo SystemEntities
	err = plist.Unmarshal(out, &mountinfo)
	if err != nil {
		log.Fatal(err)
	}

	d.MountPoint = MountPoint(mountinfo)
	fmt.Printf("DMG mounted at %v\n", d.MountPoint)
}

func (d *DMG) Unmount(dmgPath string) bool {
	args := []string{"detach", dmgPath}
	_, err := exec.Command("/usr/bin/hdiutil", args...).Output()
	if err != nil {
		log.Fatal(err)
	}
	return true
}

func MountPoint(mountinfo SystemEntities) string {
	for _, v := range mountinfo.Disks {
		if v.Disk != nil {
			return *v.Disk
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package kcp

import (
	"crypto/cipher"
	"crypto/rand"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/transport/internet"
)

type PacketReader interface {
	Read([]byte) []Segment
}

type PacketWriter interface {
	Overhead() int
	io.Writer
}

type KCPPacketReader struct {
	Security cipher.AEAD
	Header   internet.PacketHeader
}

func (r *KCPPacketReader) Read(b []byte) []Segment {
	if r.Header != nil {
		b = b[r.Header.Size():]
	}
	if r.Security != nil {
		nonceSize := r.Security.NonceSize()
		overhead := r.Security.Overhead()
		if len(b) <= nonceSize+overhead {
			return nil
		}
		out, err := r.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)
		if err != nil {
			return nil
		}
		b = out
	}
	var result []Segment
	for len(b) > 0 {
		seg, x := ReadSegment(b)
		if seg == nil {
			break
		}
		result = append(result, seg)
		b = x
	}
	return result
}

type KCPPacketWriter struct {
	Header   internet.PacketHeader
	Security cipher.AEAD
	Writer   io.Writer
}

func (w *KCPPacketWriter) Overhead() int {
	overhead := 0
	if w.Header != nil {
		overhead += int(w.Header.Size())
	}
	if w.Security != nil {
		overhead += w.Security.Overhead()
	}
	return overhead
}

func (w *KCPPacketWriter) Write(b []byte) (int, error) {
	bb := buf.StackNew()
	defer bb.Release()

	if w.Header != nil {
		w.Header.Serialize(bb.Extend(w.Header.Size()))
	}
	if w.Security != nil {
		nonceSize := w.Security.NonceSize()
		common.Must2(bb.ReadFullFrom(rand.Reader, int32(nonceSize)))
		nonce := bb.BytesFrom(int32(-nonceSize))

		encrypted := bb.Extend(int32(w.Security.Overhead() + len(b)))
		w.Security.Seal(encrypted[:0], nonce, b, nil)
	} else {
		bb.Write(b)
	}

	_, err := w.Writer.Write(bb.Bytes())
	return len(b), err
}
<commit_msg>fix #1477<commit_after>package kcp

import (
	"crypto/cipher"
	"crypto/rand"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/transport/internet"
)

type PacketReader interface {
	Read([]byte) []Segment
}

type PacketWriter interface {
	Overhead() int
	io.Writer
}

type KCPPacketReader struct {
	Security cipher.AEAD
	Header   internet.PacketHeader
}

func (r *KCPPacketReader) Read(b []byte) []Segment {
	if r.Header != nil {
		if int32(len(b)) <= r.Header.Size() {
			return nil
		}
		b = b[r.Header.Size():]
	}
	if r.Security != nil {
		nonceSize := r.Security.NonceSize()
		overhead := r.Security.Overhead()
		if len(b) <= nonceSize+overhead {
			return nil
		}
		out, err := r.Security.Open(b[nonceSize:nonceSize], b[:nonceSize], b[nonceSize:], nil)
		if err != nil {
			return nil
		}
		b = out
	}
	var result []Segment
	for len(b) > 0 {
		seg, x := ReadSegment(b)
		if seg == nil {
			break
		}
		result = append(result, seg)
		b = x
	}
	return result
}

type KCPPacketWriter struct {
	Header   internet.PacketHeader
	Security cipher.AEAD
	Writer   io.Writer
}

func (w *KCPPacketWriter) Overhead() int {
	overhead := 0
	if w.Header != nil {
		overhead += int(w.Header.Size())
	}
	if w.Security != nil {
		overhead += w.Security.Overhead()
	}
	return overhead
}

func (w *KCPPacketWriter) Write(b []byte) (int, error) {
	bb := buf.StackNew()
	defer bb.Release()

	if w.Header != nil {
		w.Header.Serialize(bb.Extend(w.Header.Size()))
	}
	if w.Security != nil {
		nonceSize := w.Security.NonceSize()
		common.Must2(bb.ReadFullFrom(rand.Reader, int32(nonceSize)))
		nonce := bb.BytesFrom(int32(-nonceSize))

		encrypted := bb.Extend(int32(w.Security.Overhead() + len(b)))
		w.Security.Seal(encrypted[:0], nonce, b, nil)
	} else {
		bb.Write(b)
	}

	_, err := w.Writer.Write(bb.Bytes())
	return len(b), err
}
<|endoftext|>