<commit_before>package action

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/Masterminds/glide/cfg"
	"github.com/Masterminds/glide/msg"
	gpath "github.com/Masterminds/glide/path"
)

// EnsureConfig loads and returns a config file.
//
// Any error will cause an immediate exit, with an error printed to Stderr.
func EnsureConfig() *cfg.Config {
	yamlpath, err := gpath.Glide()
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to find %s file in directory tree: %s", gpath.GlideFile, err)
	}

	yml, err := ioutil.ReadFile(yamlpath)
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to load %s: %s", yamlpath, err)
	}
	conf, err := cfg.ConfigFromYaml(yml)
	if err != nil {
		msg.ExitCode(3)
		msg.Die("Failed to parse %s: %s", yamlpath, err)
	}

	return conf
}

func EnsureCacheDir() {
	msg.Warn("ensure.go: ensureCacheDir is not implemented.")
}

// EnsureGoVendor ensures that the Go version is correct.
func EnsureGoVendor() {
	// 6l was removed in 1.5, when vendoring was introduced.
	cmd := exec.Command("go", "tool", "6l")
	if _, err := cmd.CombinedOutput(); err == nil {
		msg.Warn("You must install the Go 1.5 or greater toolchain to work with Glide.\n")
		os.Exit(1)
	}
	if os.Getenv("GO15VENDOREXPERIMENT") != "1" {
		msg.Warn("To use Glide, you must set GO15VENDOREXPERIMENT=1\n")
		os.Exit(1)
	}

	// Verify the setup isn't for the old version of glide. That is, this is
	// no longer assuming the _vendor directory as the GOPATH. Inform of
	// the change.
	if _, err := os.Stat("_vendor/"); err == nil {
		msg.Warn(`Your setup appears to be for the previous version of Glide.
Previously, vendor packages were stored in _vendor/src/ and
_vendor was set as your GOPATH. As of Go 1.5 the go tools
recognize the vendor directory as a location for these
files. Glide has embraced this. Please remove the _vendor
directory or move the _vendor/src/ directory to vendor/.` + "\n")
		os.Exit(1)
	}
}

// EnsureVendorDir ensures that a vendor/ directory is present in the cwd.
func EnsureVendorDir() {
	fi, err := os.Stat(gpath.VendorDir)
	if err != nil {
		msg.Debug("Creating %s", gpath.VendorDir)
		if err := os.MkdirAll(gpath.VendorDir, os.ModeDir|0755); err != nil {
			msg.Die("Could not create %s: %s", gpath.VendorDir, err)
		}
	} else if !fi.IsDir() {
		msg.Die("Vendor is not a directory")
	}
}

// EnsureGopath fails if GOPATH is not set, or if $GOPATH/src is missing.
//
// Otherwise it returns the value of GOPATH.
func EnsureGopath() string {
	gps := gpath.Gopaths()
	if len(gps) == 0 {
		msg.Die("$GOPATH is not set.")
	}

	for _, gp := range gps {
		_, err := os.Stat(path.Join(gp, "src"))
		if err != nil {
			msg.Warn("%s", err)
			continue
		}
		return gp
	}

	msg.Error("Could not find any of %s/src.\n", strings.Join(gps, "/src, "))
	msg.Info("As of Glide 0.5/Go 1.5, this is required.\n")
	msg.Die("Wihtout src, cannot continue.")
	return ""
}
<commit_msg>Handle GO15VENDOREXPERIMENT flag for >=Go 1.6<commit_after>package action

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/Masterminds/glide/cfg"
	"github.com/Masterminds/glide/msg"
	gpath "github.com/Masterminds/glide/path"
)

// EnsureConfig loads and returns a config file.
//
// Any error will cause an immediate exit, with an error printed to Stderr.
func EnsureConfig() *cfg.Config {
	yamlpath, err := gpath.Glide()
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to find %s file in directory tree: %s", gpath.GlideFile, err)
	}

	yml, err := ioutil.ReadFile(yamlpath)
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to load %s: %s", yamlpath, err)
	}
	conf, err := cfg.ConfigFromYaml(yml)
	if err != nil {
		msg.ExitCode(3)
		msg.Die("Failed to parse %s: %s", yamlpath, err)
	}

	return conf
}

func EnsureCacheDir() {
	msg.Warn("ensure.go: ensureCacheDir is not implemented.")
}

// EnsureGoVendor ensures that the Go version is correct.
func EnsureGoVendor() {
	// 6l was removed in 1.5, when vendoring was introduced.
	cmd := exec.Command("go", "tool", "6l")
	if _, err := cmd.CombinedOutput(); err == nil {
		msg.Warn("You must install the Go 1.5 or greater toolchain to work with Glide.\n")
		os.Exit(1)
	}

	// This works with 1.5 and >=1.6.
	cmd = exec.Command("go", "env", "GO15VENDOREXPERIMENT")
	if out, err := cmd.CombinedOutput(); err != nil {
		msg.Error("Error looking for $GOVENDOREXPERIMENT: %s.\n", err)
		os.Exit(1)
	} else if strings.TrimSpace(string(out)) != "1" {
		msg.Warn("To use Glide, you must set GO15VENDOREXPERIMENT=1\n")
		os.Exit(1)
	}

	// Verify the setup isn't for the old version of glide. That is, this is
	// no longer assuming the _vendor directory as the GOPATH. Inform of
	// the change.
	if _, err := os.Stat("_vendor/"); err == nil {
		msg.Warn(`Your setup appears to be for the previous version of Glide.
Previously, vendor packages were stored in _vendor/src/ and
_vendor was set as your GOPATH. As of Go 1.5 the go tools
recognize the vendor directory as a location for these
files. Glide has embraced this. Please remove the _vendor
directory or move the _vendor/src/ directory to vendor/.` + "\n")
		os.Exit(1)
	}
}

// EnsureVendorDir ensures that a vendor/ directory is present in the cwd.
func EnsureVendorDir() {
	fi, err := os.Stat(gpath.VendorDir)
	if err != nil {
		msg.Debug("Creating %s", gpath.VendorDir)
		if err := os.MkdirAll(gpath.VendorDir, os.ModeDir|0755); err != nil {
			msg.Die("Could not create %s: %s", gpath.VendorDir, err)
		}
	} else if !fi.IsDir() {
		msg.Die("Vendor is not a directory")
	}
}

// EnsureGopath fails if GOPATH is not set, or if $GOPATH/src is missing.
//
// Otherwise it returns the value of GOPATH.
func EnsureGopath() string {
	gps := gpath.Gopaths()
	if len(gps) == 0 {
		msg.Die("$GOPATH is not set.")
	}

	for _, gp := range gps {
		_, err := os.Stat(path.Join(gp, "src"))
		if err != nil {
			msg.Warn("%s", err)
			continue
		}
		return gp
	}

	msg.Error("Could not find any of %s/src.\n", strings.Join(gps, "/src, "))
	msg.Info("As of Glide 0.5/Go 1.5, this is required.\n")
	msg.Die("Wihtout src, cannot continue.")
	return ""
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/stormforger/cli/buildinfo"
)

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

func newDialer(fingerprint []byte, skipCAVerification bool) dialer {
	return func(network, addr string) (net.Conn, error) {
		c, err := tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: skipCAVerification})
		if err != nil {
			return c, err
		}

		if addr != "api.stormforger.com:443" {
			return c, nil
		} else {
			connstate := c.ConnectionState()
			keyPinValid := false
			for _, peercert := range connstate.PeerCertificates {
				der, err := x509.MarshalPKIXPublicKey(peercert.PublicKey)
				hash := sha256.Sum256(der)
				// log.Println(peercert.Issuer)
				// log.Printf("%#v\n\n", hash)
				if err != nil {
					log.Fatal(err)
				}
				if bytes.Compare(hash[0:], fingerprint) == 0 {
					// log.Println("Pinned Key found")
					keyPinValid = true
				}
			}
			if keyPinValid == false {
				log.Fatal("TLS Public Key could not be verified!")
			}
			return c, nil
		}
	}
}

func defaultHTTPClient() *http.Client {
	fingerprint := []byte{0x5b, 0x15, 0x6c, 0xda, 0x7b, 0xc3, 0xd, 0x8b, 0xe8, 0x88, 0x57, 0x75, 0xbc, 0x30, 0xc1, 0x84, 0x18, 0x75, 0x6f, 0x2d, 0x3b, 0x81, 0x91, 0xff, 0x34, 0x10, 0xda, 0x13, 0x4a, 0x83, 0x23, 0x9d}

	tr := &http.Transport{
		MaxIdleConns:    10,
		IdleConnTimeout: 30 * time.Second,
		DialTLS:         newDialer(fingerprint, false),
		Proxy:           http.ProxyURL(getHTTPProxy()),
	}

	return &http.Client{
		Transport: tr,
		Timeout:   2 * time.Minute,
	}
}

func getHTTPProxy() *url.URL {
	httpProxyURL := os.Getenv("HTTP_PROXY")

	if httpProxyURL == "" {
		return nil
	}

	proxyURL, err := url.Parse(httpProxyURL)
	if err != nil {
		log.Fatal(err)
	}

	return proxyURL
}

// Client represents the API client
type Client struct {
	HTTPClient  *http.Client
	APIEndpoint string
	JWT         string
	UserAgent   string
}

// NewClient returns a new initialized API client
func NewClient(apiEndpoint, jwtToken string) *Client {
	return &Client{
		HTTPClient:  defaultHTTPClient(),
		APIEndpoint: apiEndpoint,
		JWT:         jwtToken,
		UserAgent:   fmt.Sprintf("StormForger-CLI/%v (%v; +https://github.com/stormforger/cli)", buildinfo.BuildInfo.Version, buildinfo.BuildInfo.Commit),
	}
}

// Ping performs an authenticated ping to check if the API
// is working and the user is properly authenticated.
func (c *Client) Ping() (bool, []byte, error) {
	return c.fetch("/authenticated_ping")
}

// PingUnauthenticated performs an unauthenticated ping. This
// can be used to see if a connection is possible and/or the API
// is up in general.
func (c *Client) PingUnauthenticated() (bool, []byte, error) {
	return c.fetch("/ping")
}

func newPatchRequest(uri string, params map[string]string) (*http.Request, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	err := writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("PATCH", uri, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

// createGZIPFormFile creates a "mime/multipart".Writer header similar to CreateFormFile but with content-encoding=gzip.
func createGZIPFormFile(w *multipart.Writer, fieldname, filename, contenttype string) (io.Writer, error) {
	replacer := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")

	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition",
		fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
			replacer.Replace(fieldname), replacer.Replace(filename)))
	h.Set("Content-Type", contenttype)
	h.Set("Content-Encoding", "gzip")

	return w.CreatePart(h)
}

func fileUploadRequest(uri, method string, params url.Values, fileParamName, fileName, mimeType string, data io.Reader) (*http.Request, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	part, err := createGZIPFormFile(writer, fileParamName, fileName, mimeType)
	if err != nil {
		return nil, err
	}

	gzipWriter := gzip.NewWriter(part)
	if _, err = io.Copy(gzipWriter, data); err != nil {
		return nil, err
	}
	if err := gzipWriter.Close(); err != nil {
		return nil, err
	}

	for key, valueList := range params {
		for _, value := range valueList {
			_ = writer.WriteField(key, value)
		}
	}
	err = writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, uri, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, err
}

func (c *Client) addDefaultHeaders(request *http.Request) {
	request.Header.Set("Authorization", "Bearer "+c.JWT)
	c.setUserAgent(request)
}

func (c *Client) setUserAgent(request *http.Request) {
	request.Header.Set("User-Agent", c.UserAgent)
}

func (c *Client) doRequestRaw(request *http.Request) (*http.Response, error) {
	c.addDefaultHeaders(request)

	response, err := c.HTTPClient.Do(request)
	if err != nil {
		return nil, err
	}

	return response, nil
}

// LookupAndFetchResource tries to download a given resource from the API
func (c *Client) LookupAndFetchResource(resourceType, input string) (bool, []byte, error) {
	return c.FetchResource("/lookup?type=" + resourceType + "&q=" + input)
}

// FetchResource tries to download a given resource from the API
func (c *Client) FetchResource(path string) (bool, []byte, error) {
	return c.fetch(path)
}

func (c *Client) fetch(path string) (bool, []byte, error) {
	req, err := http.NewRequest("GET", c.APIEndpoint+path, nil)
	if err != nil {
		return false, nil, err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, nil, err
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, nil, err
	}

	if response.StatusCode != 200 {
		return false, body, nil
	}

	return true, body, nil
}

func close(c io.Closer) {
	err := c.Close()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>fix: panic on test-case launch (#262)<commit_after>package api

import (
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/stormforger/cli/buildinfo"
)

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

func newDialer(fingerprint []byte, skipCAVerification bool) dialer {
	return func(network, addr string) (net.Conn, error) {
		c, err := tls.Dial(network, addr, &tls.Config{InsecureSkipVerify: skipCAVerification})
		if err != nil {
			return c, err
		}

		if addr != "api.stormforger.com:443" {
			return c, nil
		} else {
			connstate := c.ConnectionState()
			keyPinValid := false
			for _, peercert := range connstate.PeerCertificates {
				der, err := x509.MarshalPKIXPublicKey(peercert.PublicKey)
				hash := sha256.Sum256(der)
				// log.Println(peercert.Issuer)
				// log.Printf("%#v\n\n", hash)
				if err != nil {
					log.Fatal(err)
				}
				if bytes.Compare(hash[0:], fingerprint) == 0 {
					// log.Println("Pinned Key found")
					keyPinValid = true
				}
			}
			if keyPinValid == false {
				log.Fatal("TLS Public Key could not be verified!")
			}
			return c, nil
		}
	}
}

func defaultHTTPClient() *http.Client {
	fingerprint := []byte{0x5b, 0x15, 0x6c, 0xda, 0x7b, 0xc3, 0xd, 0x8b, 0xe8, 0x88, 0x57, 0x75, 0xbc, 0x30, 0xc1, 0x84, 0x18, 0x75, 0x6f, 0x2d, 0x3b, 0x81, 0x91, 0xff, 0x34, 0x10, 0xda, 0x13, 0x4a, 0x83, 0x23, 0x9d}

	tr := &http.Transport{
		MaxIdleConns:    10,
		IdleConnTimeout: 30 * time.Second,
		DialTLS:         newDialer(fingerprint, false),
		Proxy:           http.ProxyURL(getHTTPProxy()),
	}

	return &http.Client{
		Transport: tr,
		Timeout:   2 * time.Minute,
	}
}

func getHTTPProxy() *url.URL {
	httpProxyURL := os.Getenv("HTTP_PROXY")

	if httpProxyURL == "" {
		return nil
	}

	proxyURL, err := url.Parse(httpProxyURL)
	if err != nil {
		log.Fatal(err)
	}

	return proxyURL
}

// Client represents the API client
type Client struct {
	HTTPClient  *http.Client
	APIEndpoint string
	JWT         string
	UserAgent   string
}

// NewClient returns a new initialized API client
func NewClient(apiEndpoint, jwtToken string) *Client {
	return &Client{
		HTTPClient:  defaultHTTPClient(),
		APIEndpoint: apiEndpoint,
		JWT:         jwtToken,
		UserAgent:   fmt.Sprintf("StormForger-CLI/%v (%v; +https://github.com/stormforger/cli)", buildinfo.BuildInfo.Version, buildinfo.BuildInfo.Commit),
	}
}

// Ping performs an authenticated ping to check if the API
// is working and the user is properly authenticated.
func (c *Client) Ping() (bool, []byte, error) {
	return c.fetch("/authenticated_ping")
}

// PingUnauthenticated performs an unauthenticated ping. This
// can be used to see if a connection is possible and/or the API
// is up in general.
func (c *Client) PingUnauthenticated() (bool, []byte, error) {
	return c.fetch("/ping")
}

func newPatchRequest(uri string, params map[string]string) (*http.Request, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	err := writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("PATCH", uri, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, nil
}

// createGZIPFormFile creates a "mime/multipart".Writer header similar to CreateFormFile but with content-encoding=gzip.
func createGZIPFormFile(w *multipart.Writer, fieldname, filename, contenttype string) (io.Writer, error) {
	replacer := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")

	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition",
		fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
			replacer.Replace(fieldname), replacer.Replace(filename)))
	h.Set("Content-Type", contenttype)
	h.Set("Content-Encoding", "gzip")

	return w.CreatePart(h)
}

func fileUploadRequest(uri, method string, params url.Values, fileParamName, fileName, mimeType string, data io.Reader) (*http.Request, error) {
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	part, err := createGZIPFormFile(writer, fileParamName, fileName, mimeType)
	if err != nil {
		return nil, err
	}

	gzipWriter := gzip.NewWriter(part)
	if _, err = io.Copy(gzipWriter, data); err != nil {
		return nil, err
	}
	if err := gzipWriter.Close(); err != nil {
		return nil, err
	}

	for key, valueList := range params {
		for _, value := range valueList {
			_ = writer.WriteField(key, value)
		}
	}

	if err := writer.Close(); err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, uri, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return req, nil
}

func (c *Client) addDefaultHeaders(request *http.Request) {
	request.Header.Set("Authorization", "Bearer "+c.JWT)
	c.setUserAgent(request)
}

func (c *Client) setUserAgent(request *http.Request) {
	request.Header.Set("User-Agent", c.UserAgent)
}

func (c *Client) doRequestRaw(request *http.Request) (*http.Response, error) {
	c.addDefaultHeaders(request)

	response, err := c.HTTPClient.Do(request)
	if err != nil {
		return nil, err
	}

	return response, nil
}

// LookupAndFetchResource tries to download a given resource from the API
func (c *Client) LookupAndFetchResource(resourceType, input string) (bool, []byte, error) {
	return c.FetchResource("/lookup?type=" + resourceType + "&q=" + input)
}

// FetchResource tries to download a given resource from the API
func (c *Client) FetchResource(path string) (bool, []byte, error) {
	return c.fetch(path)
}

func (c *Client) fetch(path string) (bool, []byte, error) {
	req, err := http.NewRequest("GET", c.APIEndpoint+path, nil)
	if err != nil {
		return false, nil, err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, nil, err
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, nil, err
	}

	if response.StatusCode != 200 {
		return false, body, nil
	}

	return true, body, nil
}

func close(c io.Closer) {
	err := c.Close()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
)

type Client struct {
	MgmtUrl  string
	Username string
	Password string
}

func (c Client) makeRequest(method string, endpoint string) *http.Response {
	client := &http.Client{}

	url := fmt.Sprintf("http://%s", path.Join(c.MgmtUrl, "api", endpoint))
	req, _ := http.NewRequest(method, url, nil)
	req.SetBasicAuth(c.Username, c.Password)
	resp, err := client.Do(req)
	if err != nil {
		log.Panic(err)
	}

	log.Printf("Request: %s (Status: %d)\n", url, resp.StatusCode)

	return resp
}

func processResponse(response *http.Response, target interface{}) error {
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}

	if response.StatusCode < 200 || response.StatusCode > 299 {
		return errors.New(fmt.Sprintf("Bad Request: %s (Status Code %d). %s", response.Request.URL, response.StatusCode, body))
	}

	err = json.Unmarshal(body, &target)
	if err != nil {
		return err
	}

	return nil

}

func (c Client) GetOverview() (Overview, error) {
	r := c.makeRequest("GET", "overview")
	o := Overview{}
	err := processResponse(r, &o)
	return o, err
}

func (c Client) GetClusterName() (string, error) {
	r := c.makeRequest("GET", "cluster-name")
	type result struct {
		Name string `json:"name"`
	}
	res := result{}
	err := processResponse(r, &res)
	return res.Name, err

}

func (c Client) GetNodes() ([]Node, error) {
	r := c.makeRequest("GET", "nodes")
	var n []Node
	err := processResponse(r, &n)
	return n, err
}

func (c Client) GetNode(node string) (Node, error) {
	nodeStr := url.QueryEscape(node)
	r := c.makeRequest("GET", fmt.Sprintf("nodes/%s", nodeStr))
	n := Node{}
	err := processResponse(r, &n)
	return n, err
}

func (c Client) GetExchanges() ([]Exchange, error) {
	r := c.makeRequest("GET", "exchanges")
	var e []Exchange
	err := processResponse(r, &e)
	return e, err
}

func (c Client) GetExchangesOnVhost(vhost string) ([]Exchange, error) {
	vhostStr := escapeVhost(vhost)
	r := c.makeRequest("GET", fmt.Sprintf("exchanges/%s", vhostStr))
	var e []Exchange
	err := processResponse(r, &e)
	return e, err
}
<commit_msg>Adds methods for different types of requests<commit_after>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path"
)

type Client struct {
	MgmtUrl  string
	Username string
	Password string
}

func (c Client) makeRequest(method string, endpoint string) *http.Response {
	client := &http.Client{}

	url := fmt.Sprintf("http://%s", path.Join(c.MgmtUrl, "api", endpoint))
	req, _ := http.NewRequest(method, url, nil)
	req.SetBasicAuth(c.Username, c.Password)
	resp, err := client.Do(req)
	if err != nil {
		log.Panic(err)
	}

	log.Printf("Request: %s (Status: %d)\n", url, resp.StatusCode)

	return resp
}

func (c Client) get(endpoint string) *http.Response {
	return c.makeRequest("GET", endpoint)
}

func (c Client) delete(endpoint string) *http.Response {
	return c.makeRequest("DELETE", endpoint)
}

func (c Client) put(endpoint string, data interface{}) *http.Response {
	return c.makeRequest("PUT", endpoint)
}

func (c Client) post(endpoint string, data interface{}) *http.Response {
	return c.makeRequest("POST", endpoint)
}

func processResponse(response *http.Response, target interface{}) error {
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}

	if response.StatusCode < 200 || response.StatusCode > 299 {
		return errors.New(fmt.Sprintf("Bad Request: %s (Status Code %d). %s", response.Request.URL, response.StatusCode, body))
	}

	err = json.Unmarshal(body, &target)
	if err != nil {
		return err
	}

	return nil

}

func (c Client) GetOverview() (Overview, error) {
	r := c.get("overview")
	o := Overview{}
	err := processResponse(r, &o)
	return o, err
}

func (c Client) GetClusterName() (string, error) {
	r := c.get("cluster-name")
	type result struct {
		Name string `json:"name"`
	}
	res := result{}
	err := processResponse(r, &res)
	return res.Name, err

}

func (c Client) GetNodes() ([]Node, error) {
	r := c.get("nodes")
	var n []Node
	err := processResponse(r, &n)
	return n, err
}

func (c Client) GetNode(node string) (Node, error) {
	nodeStr := url.QueryEscape(node)
	r := c.get(fmt.Sprintf("nodes/%s", nodeStr))
	n := Node{}
	err := processResponse(r, &n)
	return n, err
}

func (c Client) GetExchanges() ([]Exchange, error) {
	r := c.get("exchanges")
	var e []Exchange
	err := processResponse(r, &e)
	return e, err
}

func (c Client) GetExchangesOnVhost(vhost string) ([]Exchange, error) {
	vhostStr := escapeVhost(vhost)
	r := c.makeRequest("GET", fmt.Sprintf("exchanges/%s", vhostStr))
	var e []Exchange
	err := processResponse(r, &e)
	return e, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/d2r2/go-dht"
)

func main() {
	// read DHT11 sensor data from pin 4, retrying 10 times in case of failure.
	// enable "boost GPIO performance" parameter, if your device is old as Raspberry BI 1
	// (this require root privileges)
	sensorType := dht.DHT22
	temperature, humidity, retried, err :=
		dht.ReadDHTxxWithRetry(sensorType, 4, false, 10)
	if err != nil {
		log.Fatal(err)
	}
	// print temperature and humidity
	fmt.Printf("Sensor = %v: Temperature = %v*C, Humidity = %v%% (retried %d times)\n",
		sensorType, temperature, humidity, retried)
}
<commit_msg>Update test1.go<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/d2r2/go-dht"
)

func main() {
	// Read DHT11 sensor data from pin 4, retrying 10 times in case of failure.
	// You may enable "boost GPIO performance" parameter, if your device is old
	// as Raspberry PI 1 (this will require root privileges). You can switch off
	// "boost GPIO performance" parameter for old devices, but it may increase
	// retry attempts. Play with this parameter.
	sensorType := dht.DHT22
	temperature, humidity, retried, err :=
		dht.ReadDHTxxWithRetry(sensorType, 4, false, 10)
	if err != nil {
		log.Fatal(err)
	}
	// print temperature and humidity
	fmt.Printf("Sensor = %v: Temperature = %v*C, Humidity = %v%% (retried %d times)\n",
		sensorType, temperature, humidity, retried)
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "flag"
    "bitbucket.org/mikespook/goemphp/php"
)

var (
    info = flag.Bool("i", false, "Display phpinfo")
    file = flag.String("f", "", "Execute the file")
    run = flag.String("r", "", "Execute the script")
)

func init() {
    flag.Parse()
}

func main() {
    p := php.NewPHP()
    p.Startup()
    defer p.Close()
    if *info {
        if err := p.Eval("phpinfo();"); err != nil {
            log.Fatal(err)
        }
        return
    }
    if *file != "" {
        if err := p.Exec(*file); err != nil {
            log.Fatal(err)
        }
        return
    }
    if *run != "" {
        if err := p.Eval(*run); err != nil {
            log.Fatal(err)
        }
        return
    }
    flag.Usage()
}
<commit_msg>update examples<commit_after>package main

import (
    "log"
    "flag"
    "github.com/mikespook/goemphp/php"
)

var (
    info = flag.Bool("i", false, "Display phpinfo")
    file = flag.String("f", "", "Execute the file")
    run = flag.String("r", "", "Execute the script")
)

func init() {
    flag.Parse()
}

func main() {
    p := php.New()
    p.Startup()
    defer p.Close()
    if *info {
        if err := p.Eval("phpinfo();"); err != nil {
            log.Fatal(err)
        }
        return
    }
    if *file != "" {
        if err := p.Exec(*file); err != nil {
            log.Fatal(err)
        }
        return
    }
    if *run != "" {
        if err := p.Eval(*run); err != nil {
            log.Fatal(err)
        }
        return
    }
    flag.Usage()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/jessevdk/go-flags"
	"os"
	"strconv"
	"strings"
)

type EditorOptions struct {
	Input  flags.Filename `short:"i" long:"input" description:"Input file" default:"-"`
	Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"`
}

type Point struct {
	X, Y int
}

func (p *Point) UnmarshalFlag(value string) error {
	parts := strings.Split(value, ",")

	if len(parts) != 2 {
		return errors.New("expected two numbers separated by a ,")
	}

	x, err := strconv.ParseInt(parts[0], 10, 32)

	if err != nil {
		return err
	}

	y, err := strconv.ParseInt(parts[1], 10, 32)

	if err != nil {
		return err
	}

	p.X = int(x)
	p.Y = int(y)

	return nil
}

func (p Point) MarshalFlag() (string, error) {
	return fmt.Sprintf("%d,%d", p.X, p.Y), nil
}

type Options struct {
	// Example of verbosity with level
	Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`

	// Example of optional value
	User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"`

	// Example of map with multiple default values
	Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"`

	// Example of option group
	Editor EditorOptions `group:"Editor Options"`

	// Example of custom type Marshal/Unmarshal
	Point Point `long:"point" description:"A x,y point" default:"1,2"`
}

var options Options

var parser = flags.NewParser(&options, flags.Default)

func main() {
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>Show how to exit(0) on --help in example<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/jessevdk/go-flags"
	"os"
	"strconv"
	"strings"
)

type EditorOptions struct {
	Input  flags.Filename `short:"i" long:"input" description:"Input file" default:"-"`
	Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"`
}

type Point struct {
	X, Y int
}

func (p *Point) UnmarshalFlag(value string) error {
	parts := strings.Split(value, ",")

	if len(parts) != 2 {
		return errors.New("expected two numbers separated by a ,")
	}

	x, err := strconv.ParseInt(parts[0], 10, 32)

	if err != nil {
		return err
	}

	y, err := strconv.ParseInt(parts[1], 10, 32)

	if err != nil {
		return err
	}

	p.X = int(x)
	p.Y = int(y)

	return nil
}

func (p Point) MarshalFlag() (string, error) {
	return fmt.Sprintf("%d,%d", p.X, p.Y), nil
}

type Options struct {
	// Example of verbosity with level
	Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`

	// Example of optional value
	User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"`

	// Example of map with multiple default values
	Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"`

	// Example of option group
	Editor EditorOptions `group:"Editor Options"`

	// Example of custom type Marshal/Unmarshal
	Point Point `long:"point" description:"A x,y point" default:"1,2"`
}

var options Options

var parser = flags.NewParser(&options, flags.Default)

func main() {
	if _, err := parser.Parse(); err != nil {
		if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
			os.Exit(0)
		} else {
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package algorithm

import (
	"fmt"
)

type BinarySearchTree struct {
	root    *node
	compare func(a interface{}, b interface{}) int

	insert func(p **node, v interface{}) bool
}

type node struct {
	value interface{}

	left  *node
	right *node

	extra interface{} // for extend
}

func NewBinarySearchTree() *BinarySearchTree {
	t := new(BinarySearchTree)
	t.root = nil
	t.compare = CompareInt
	t.insert = t._insert
	return t
}

func (t *BinarySearchTree) Insert(v interface{}) bool {
	return t.insert(&t.root, v)
}

func (t *BinarySearchTree) _insert(p **node, v interface{}) bool {
	if *p == nil {
		*p = t.newNode(v)
		return true
	}

	c := t.compare(v, (*p).value)

	if c == 0 {
		(*p).value = v
		return false
	} else if c < 0 {
		return t.insert(&((*p).left), v)
	} else {
		return t.insert(&((*p).right), v)
	}
}

func (t *BinarySearchTree) Find(v interface{}) (interface{}, bool) {
	n, ok := t.find(t.root, v)
	if !ok {
		return nil, false
	}
	return n.value, true
}

func (t *BinarySearchTree) find(n *node, v interface{}) (*node, bool) {
	if n == nil {
		return nil, false
	}

	c := t.compare(v, n.value)

	if c == 0 {
		return n, true
	} else if c < 0 {
		return t.find(n.left, v)
	} else {
		return t.find(n.right, v)
	}
}

func (t *BinarySearchTree) Delete(v interface{}) bool {
	return t.delete(&t.root, v)
}

func (t *BinarySearchTree) delete(p **node, v interface{}) bool {
	n := *p
	if n == nil {
		return false
	}

	c := t.compare(v, n.value)

	if c == 0 { // delete current node
		t.del_node(p)
		return true
	} else if c < 0 {
		return t.delete(&n.left, v)
	} else {
		return t.delete(&n.right, v)
	}
}

func (t *BinarySearchTree) del_node(p **node) {
	if *p == nil {
		return
	}
	n := *p

	q := t.min(&n.right) // find the minimum node from the right.

	if q == nil { // if has no right subtree.
		*p = n.left // use the left subtree as replacement.
		return
	} else { // use the minimun node from the right subtree as replacement.
		(*p).value = (*q).value // replace
		t.del_node(q)           // delete the replacement node from its original place.
	}
}

func (t *BinarySearchTree) min(p **node) **node {
	if *p == nil {
		return nil
	}
	for {
		if (*p).left != nil {
			p = &((*p).left)
		} else {
			return p
		}
	}
}

func (t *BinarySearchTree) String() string {
	return t.toString(t.root)
}

func (t *BinarySearchTree) toString(n *node) string {
	if n == nil {
		return ""
	}
	l := t.toString(n.left)
	r := t.toString(n.right)
	return fmt.Sprintf("[%s] %v [%s]", l, n.value, r)
}

func (t *BinarySearchTree) newNode(v interface{}) *node {
	n := new(node)
	n.value = v
	n.left = nil
	n.right = nil
	return n
}

func CompareInt(a interface{}, b interface{}) int {
	x := a.(int)
	y := b.(int)
	return x - y
}
<commit_msg>rebuild bst.delete<commit_after>package algorithm

import (
	"fmt"
)

type BinarySearchTree struct {
	root    *node
	compare func(a interface{}, b interface{}) int

	insert func(p **node, v interface{}) bool
}

type node struct {
	value interface{}

	left  *node
	right *node

	extra interface{} // for extend
}

func NewBinarySearchTree() *BinarySearchTree {
	t := new(BinarySearchTree)
	t.root = nil
	t.compare = CompareInt
	t.insert = t._insert
	return t
}

func (t *BinarySearchTree) Insert(v interface{}) bool {
	return t.insert(&t.root, v)
}

func (t *BinarySearchTree) _insert(p **node, v interface{}) bool {
	if *p == nil {
		*p = t.newNode(v)
		return true
	}

	c := t.compare(v, (*p).value)

	if c == 0 {
		(*p).value = v
		return false
	} else if c < 0 {
		return t.insert(&((*p).left), v)
	} else {
		return t.insert(&((*p).right), v)
	}
}

func (t *BinarySearchTree) Find(v interface{}) (interface{}, bool) {
	n, ok := t.find(t.root, v)
	if !ok {
		return nil, false
	}
	return n.value, true
}

func (t *BinarySearchTree) find(n *node, v interface{}) (*node, bool) {
	if n == nil {
		return nil, false
	}

	c := t.compare(v, n.value)

	if c == 0 {
		return n, true
	} else if c < 0 {
		return t.find(n.left, v)
	} else {
		return t.find(n.right, v)
	}
}

func (t *BinarySearchTree) Delete(v interface{}) bool {
	return t.delete(&t.root, v)
}

func (t *BinarySearchTree) delete(p **node, v interface{}) bool {
	n := *p
	if n == nil {
		return false
	}

	c := t.compare(v, n.value)

	if c == 0 { // delete current node
		t.del_node(p)
		return true
	} else if c < 0 {
		return t.delete(&n.left, v)
	} else {
		return t.delete(&n.right, v)
	}
}

func (t *BinarySearchTree) del_node(p **node) *node {
	if *p == nil {
		return nil
	}
	n := *p
	defer func() {
		n.right, n.left = nil, nil
	}()

	if n.right == nil { // if has no right subtree.
		*p = n.left // use the left subtree as replacement.
		return n
	}

	// use the minimun node from the right subtree as replacement.
	min := t.del_min(&(*p).right)
	min.left = n.left
	min.right = n.right
	(*p) = min
	return n
}

func (t *BinarySearchTree) del_min(p **node) *node {
	if (*p).left != nil {
		return t.del_min(&(*p).left)
	}
	return t.del_node(p)
}

func (t *BinarySearchTree) String() string {
	return t.toString(t.root)
}

func (t *BinarySearchTree) toString(n *node) string {
	if n == nil {
		return ""
	}
	l := t.toString(n.left)
	r := t.toString(n.right)
	return fmt.Sprintf("[%s] %v [%s]", l, n.value, r)
}

func (t *BinarySearchTree) newNode(v interface{}) *node {
	n := new(node)
	n.value = v
	n.left = nil
	n.right = nil
	return n
}

func CompareInt(a interface{}, b interface{}) int {
	x := a.(int)
	y := b.(int)
	return x - y
}
<|endoftext|>


<commit_before>package hyperloglog

import (
	"bufio"
	"fmt"
	"hash/fnv"
	"io"
	"math"
	"os"
	"testing"
)

// Return a dictionary up to n words. If n is zero, return the entire
// dictionary.
func dictionary(n int) []string {
	var words []string
	dict := "/usr/share/dict/words"
	f, err := os.Open(dict)
	if err != nil {
		fmt.Printf("can't open dictionary file '%s': %v\n", dict, err)
		os.Exit(1)
	}
	count := 0
	buf := bufio.NewReader(f)
	for {
		if n != 0 && count >= n {
			break
		}
		word, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			continue
		}
		words = append(words, word)
		count++
	}
	f.Close()
	return words
}

func geterror(actual uint64, estimate uint64) (result float64) {
	return (float64(estimate) - float64(actual)) / float64(actual)
}

func testHyperLogLog(t *testing.T, n, low_b, high_b int) {
	words := dictionary(n)
	bad := 0
	n_words := uint64(len(words))
	for i := low_b; i < high_b; i++ {
		m := uint(math.Pow(2, float64(i)))

		h, err := New(m)
		if err != nil {
			t.Fatalf("can't make New(%d): %v", m, err)
		}

		hash := fnv.New32()
		for _, word := range words {
			hash.Write([]byte(word))
			h.Add(hash.Sum32())
			hash.Reset()
		}

		expected_error := 1.04 / math.Sqrt(float64(m))
		actual_error := math.Abs(geterror(n_words, h.Count()))

		if actual_error > expected_error {
			bad++
			t.Logf("m=%d: error=%.5f, expected <%.5f; actual=%d, estimated=%d\n",
				m, actual_error, expected_error, n_words, h.Count())
		}

	}
	t.Logf("%d of %d tests exceeded estimated error", bad, high_b-low_b)
}

func TestHyperLogLogSmall(t *testing.T) {
	testHyperLogLog(t, 5, 4, 17)
}

func TestHyperLogLogBig(t *testing.T) {
	testHyperLogLog(t, 0, 4, 17)
}

func benchmarkCount(b *testing.B, registers int) {
	words := dictionary(0)
	m := uint(math.Pow(2, float64(registers)))

	h, err := New(m)
	if err != nil {
		return
	}

	hash := fnv.New32()
	for _, word := range words {
		hash.Write([]byte(word))
		h.Add(hash.Sum32())
		hash.Reset()
	}

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		h.Count()
	}
}

func BenchmarkCount4(b *testing.B) {
	benchmarkCount(b, 4)
}

func BenchmarkCount5(b *testing.B) {
	benchmarkCount(b, 5)
}

func BenchmarkCount6(b *testing.B) {
	benchmarkCount(b, 6)
}

func BenchmarkCount7(b *testing.B) {
	benchmarkCount(b, 7)
}

func BenchmarkCount8(b *testing.B) {
	benchmarkCount(b, 8)
}

func BenchmarkCount9(b *testing.B) {
	benchmarkCount(b, 9)
}

func BenchmarkCount10(b *testing.B) {
	benchmarkCount(b, 10)
}
<commit_msg>Begin intersect test<commit_after>package hyperloglog

import (
	"bufio"
	"fmt"
	"hash/fnv"
	"io"
	"math"
	"os"
	"log"
	"testing"
)

// Return a dictionary up to n words. If n is zero, return the entire
// dictionary.
func dictionary(n int) []string {
	var words []string
	dict := "/usr/share/dict/words"
	f, err := os.Open(dict)
	if err != nil {
		fmt.Printf("can't open dictionary file '%s': %v\n", dict, err)
		os.Exit(1)
	}
	count := 0
	buf := bufio.NewReader(f)
	for {
		if n != 0 && count >= n {
			break
		}
		word, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			continue
		}
		words = append(words, word)
		count++
	}
	f.Close()
	return words
}

func geterror(actual uint64, estimate uint64) (result float64) {
	return (float64(estimate) - float64(actual)) / float64(actual)
}

func testHyperLogLog(t *testing.T, n, low_b, high_b int) {
	words := dictionary(n)
	bad := 0
	n_words := uint64(len(words))
	for i := low_b; i < high_b; i++ {
		m := uint(math.Pow(2, float64(i)))

		h, err := New(m)
		if err != nil {
			t.Fatalf("can't make New(%d): %v", m, err)
		}

		hash := fnv.New32()
		for _, word := range words {
			hash.Write([]byte(word))
			h.Add(hash.Sum32())
			hash.Reset()
		}

		expected_error := 1.04 / math.Sqrt(float64(m))
		actual_error := math.Abs(geterror(n_words, h.Count()))

		if actual_error > expected_error {
			bad++
			t.Logf("m=%d: error=%.5f, expected <%.5f; actual=%d, estimated=%d\n",
				m, actual_error, expected_error, n_words, h.Count())
		}

	}
	t.Logf("%d of %d tests exceeded estimated error", bad, high_b-low_b)
}

func TestHyperLogLogSmall(t *testing.T) {
	testHyperLogLog(t, 5, 4, 17)
}

func TestHyperLogLogBig(t *testing.T) {
	testHyperLogLog(t, 0, 4, 17)
}

func TestHyperLogLogIntersect(t *testing.T) {
	a, _ := New(2048)
	b, _ := New(2048)

	hash := fnv.New32()

	// Apple in both
	hash.Write([]byte("apple"))
	s := hash.Sum32()
	a.Add(s)
	b.Add(s)
	hash.Reset()

	// Banana in a
	hash.Write([]byte("banana"))
	s = hash.Sum32()
	a.Add(s)
	hash.Reset()

	// Pineapple in a
	hash.Write([]byte("pineapple"))
	s = hash.Sum32()
	b.Add(s)
	hash.Reset()

	intersected, _ := a.Intersect(b)
	if intersected != nil {
		// @todo finish
		log.Printf("%d", intersected.Count())
	}
}

func benchmarkCount(b *testing.B, registers int) {
	words := dictionary(0)
	m := uint(math.Pow(2, float64(registers)))

	h, err := New(m)
	if err != nil {
		return
	}

	hash := fnv.New32()
	for _, word := range words {
		hash.Write([]byte(word))
		h.Add(hash.Sum32())
		hash.Reset()
	}

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		h.Count()
	}
}

func BenchmarkCount4(b *testing.B) {
	benchmarkCount(b, 4)
}

func BenchmarkCount5(b *testing.B) {
	benchmarkCount(b, 5)
}

func BenchmarkCount6(b *testing.B) {
	benchmarkCount(b, 6)
}

func BenchmarkCount7(b *testing.B) {
	benchmarkCount(b, 7)
}

func BenchmarkCount8(b *testing.B) {
	benchmarkCount(b, 8)
}

func BenchmarkCount9(b *testing.B) {
	benchmarkCount(b, 9)
}

func BenchmarkCount10(b *testing.B) {
	benchmarkCount(b, 10)
}
<|endoftext|>


<commit_before>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

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

	"github.com/foursquare/fsgo/concurrent/atomicbool"
)

type Adminz struct {
	// keep track of killfile state
	Killed *atomicbool.AtomicBool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	resume func() error

	// pause is called when the server is killed
	pause func() error

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool
}

// Creates a new Adminz "builder". Not safe to use until Build() is called.
func New() *Adminz {
	return &Adminz{
		Killed: atomicbool.New(),
	}
}

// Resume is called when the server is unkilled
func (a *Adminz) Resume(resume func() error) *Adminz {
	a.resume = resume
	return a
}

// pause is called when the server is killed
func (a *Adminz) Pause(pause func() error) *Adminz {
	a.pause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Build initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Build() *Adminz {
	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		go a.killfileLoop()
	} else {
		log.Print("Not checking killfiles.")
	}

	http.HandleFunc("/healthz", a.healthzHandler)
	http.HandleFunc("/servicez", a.servicezHandler)

	log.Print("adminz registered")
	log.Print("Watching paths for killfile: ", a.killfilePaths)
	return a
}

func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...string) []string {
	// the number of ports + the "all" killfile
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%s", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			return true
		}
	}
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		current := a.Killed.Get()
		next := a.checkKillfiles()
		if current == false && next == true {
			// If we are currently running and a killfile is dropped, call pause()
			if a.pause != nil {
				a.pause()
			}
			a.Killed.Set(next)
		} else if current == true && next == false {
			// If we are currently not running and the killfile is removed, call resume()
			if a.resume != nil {
				a.resume()
			}
			a.Killed.Set(next)
		}
		// If we hit neither of those, no state changed.
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string
	if !a.Killed.Get() && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
	}
	log.Print("Healthz returning ", ret)
	w.Write(([]byte)(ret))
}

func (a *Adminz) servicezHandler(w http.ResponseWriter, r *http.Request) {
	if a.servicez == nil {
		return
	}

	bytes, err := json.Marshal(a.servicez())
	if err == nil {
		w.Header().Add("Content-Type", "text/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}
<commit_msg>support GC on demand<commit_after>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/foursquare/fsgo/concurrent/atomicbool"
)

type Adminz struct {
	// keep track of killfile state
	Killed *atomicbool.AtomicBool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	resume func() error

	// pause is called when the server is killed
	pause func() error

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool
}

// Creates a new Adminz "builder". Not safe to use until Build() is called.
func New() *Adminz {
	return &Adminz{
		Killed: atomicbool.New(),
	}
}

// Resume is called when the server is unkilled
func (a *Adminz) Resume(resume func() error) *Adminz {
	a.resume = resume
	return a
}

// pause is called when the server is killed
func (a *Adminz) Pause(pause func() error) *Adminz {
	a.pause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Build initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Build() *Adminz {
	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		go a.killfileLoop()
	} else {
		log.Print("Not checking killfiles.")
	}

	http.HandleFunc("/healthz", a.healthzHandler)
	http.HandleFunc("/servicez", a.servicezHandler)
	http.HandleFunc("/gc", a.gcHandler)

	log.Print("adminz registered")
	log.Print("Watching paths for killfile: ", a.killfilePaths)
	return a
}

func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...string) []string {
	// the number of ports + the "all" killfile
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%s", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			return true
		}
	}
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		current := a.Killed.Get()
		next := a.checkKillfiles()
		if current == false && next == true {
			// If we are currently running and a killfile is dropped, call pause()
			if a.pause != nil {
				a.pause()
			}
			a.Killed.Set(next)
		} else if current == true && next == false {
			// If we are currently not running and the killfile is removed, call resume()
			if a.resume != nil {
				a.resume()
			}
			a.Killed.Set(next)
		}
		// If we hit neither of those, no state changed.
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string
	if !a.Killed.Get() && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
	}
	log.Print("Healthz returning ", ret)
	w.Write(([]byte)(ret))
}

func (a *Adminz) servicezHandler(w http.ResponseWriter, r *http.Request) {
	if a.servicez == nil {
		return
	}

	bytes, err := json.Marshal(a.servicez())
	if err == nil {
		w.Header().Add("Content-Type", "text/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}

func (a *Adminz) gcHandler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats

	mb := uint64(1024 * 1024)
	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "Before")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	runtime.GC()

	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "After")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	w.Write([]byte("OK"))
}
<|endoftext|>


<commit_before>package hide

import (
	"errors"
	"math/big"
)

// Hide stores primes and inverses used to obfuscate/deobfuscate different
// integer types
type Hide struct {
	int32prime    *big.Int
	int32inverse  *big.Int
	int32xor      *big.Int
	int64prime    *big.Int
	int64inverse  *big.Int
	int64xor      *big.Int
	uint32prime   *big.Int
	uint32inverse *big.Int
	uint32xor     *big.Int
	uint64prime   *big.Int
	uint64inverse *big.Int
	uint64xor     *big.Int
}

var (
	Default Hide

	bigOne = big.NewInt(1)

	// maximum value for each type
	int32Max  = big.NewInt(2147483647)                       // 2^31-1
	int64Max  = big.NewInt(9223372036854775807)              // 2^63 -1
	uint32Max = new(big.Int).SetUint64(4294967295)           // 2^32 -1
	uint64Max = new(big.Int).SetUint64(18446744073709551615) // 2^64 -1

	ErrNil        = errors.New("prime is nil")
	ErrOutOfRange = errors.New("prime is greater than max value for the type")
	ErrNotAPrime  = errors.New("it is not a prime number")
)

func modularMultiplicativeInverse(val, prime, max *big.Int) {
	if prime == nil {
		panic(ErrNil)
	}

	val.Mul(val, prime)
	val.And(val, max)
}

func (h *Hide) SetInt32(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(int32Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.int32prime = prime
	inverse := *prime

	var plusOne big.Int
	h.int32inverse = inverse.ModInverse(&inverse, plusOne.Add(int32Max, bigOne))

	return nil
}

func (h *Hide) SetInt64(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(int64Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.int64prime = prime
	inverse := *prime

	var plusOne big.Int
	h.int64inverse = inverse.ModInverse(&inverse, plusOne.Add(int64Max, bigOne))

	return nil
}

func (h *Hide) SetXor(xor *big.Int) error {
	if xor == nil {
		return ErrNil
	}

	int32xor := *xor
	int32xor.And(&int32xor, int32Max)
	h.int32xor = &int32xor

	int64xor := *xor
	int64xor.And(&int64xor, int64Max)
	h.int64xor = &int64xor

	uint32xor := *xor
	uint32xor.And(&uint32xor, uint32Max)
	h.uint32xor = &uint32xor

	uint64xor := *xor
	uint64xor.And(&uint64xor, uint64Max)
	h.uint64xor = &uint64xor

	return nil
}

func (h *Hide) SetUint32(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(uint32Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.uint32prime = prime
	inverse := *prime

	var plusOne big.Int
	h.uint32inverse = inverse.ModInverse(&inverse, plusOne.Add(uint32Max, bigOne))

	return nil
}

func (h *Hide) SetUint64(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(uint64Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.uint64prime = prime
	inverse := *prime

	var plusOne big.Int
	h.uint64inverse = inverse.ModInverse(&inverse, plusOne.Add(uint64Max, bigOne))

	return nil
}

func (h *Hide) Int32Obfuscate(i int32) int32 {
	return Int32Obfuscate(i, h.int32prime, h.int32xor)
}

func (h *Hide) Int32Deobfuscate(i int32) int32 {
	return Int32Deobfuscate(i, h.int32inverse, h.int32xor)
}

func (h *Hide) Int64Obfuscate(i int64) int64 {
	return Int64Obfuscate(i, h.int64prime, h.int64xor)
}

func (h *Hide) Int64Deobfuscate(i int64) int64 {
	return Int64Deobfuscate(i, h.int64inverse, h.int64xor)
}

func (h *Hide) Uint32Obfuscate(i uint32) uint32 {
	return Uint32Obfuscate(i, h.uint32prime, h.uint32xor)
}

func (h *Hide) Uint32Deobfuscate(i uint32) uint32 {
	return Uint32Deobfuscate(i, h.uint32inverse, h.uint32xor)
}

func (h *Hide) Uint64Obfuscate(i uint64) uint64 {
	return Uint64Obfuscate(i, h.uint64prime, h.uint64xor)
}

func (h *Hide) Uint64Deobfuscate(i uint64) uint64 {
	return Uint64Deobfuscate(i, h.uint64inverse, h.uint64xor)
}
<commit_msg>fix: fix issue caused by shallow copy in go 1.11<commit_after>package hide

import (
	"errors"
	"math/big"
)

// Hide stores primes and inverses used to obfuscate/deobfuscate different
// integer types
type Hide struct {
	int32prime    *big.Int
	int32inverse  *big.Int
	int32xor      *big.Int
	int64prime    *big.Int
	int64inverse  *big.Int
	int64xor      *big.Int
	uint32prime   *big.Int
	uint32inverse *big.Int
	uint32xor     *big.Int
	uint64prime   *big.Int
	uint64inverse *big.Int
	uint64xor     *big.Int
}

var (
	Default Hide

	bigOne = big.NewInt(1)

	// maximum value for each type
	int32Max  = big.NewInt(2147483647)                       // 2^31-1
	int64Max  = big.NewInt(9223372036854775807)              // 2^63 -1
	uint32Max = new(big.Int).SetUint64(4294967295)           // 2^32 -1
	uint64Max = new(big.Int).SetUint64(18446744073709551615) // 2^64 -1

	ErrNil        = errors.New("prime is nil")
	ErrOutOfRange = errors.New("prime is greater than max value for the type")
	ErrNotAPrime  = errors.New("it is not a prime number")
)

func modularMultiplicativeInverse(val, prime, max *big.Int) {
	if prime == nil {
		panic(ErrNil)
	}

	val.Mul(val, prime)
	val.And(val, max)
}

func (h *Hide) SetInt32(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(int32Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.int32prime = prime
	var inverse big.Int
	inverse.Set(prime)

	var plusOne big.Int
	h.int32inverse = inverse.ModInverse(&inverse, plusOne.Add(int32Max, bigOne))

	return nil
}

func (h *Hide) SetInt64(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(int64Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.int64prime = prime
	var inverse big.Int
	inverse.Set(prime)

	var plusOne big.Int
	h.int64inverse = inverse.ModInverse(&inverse, plusOne.Add(int64Max, bigOne))

	return nil
}

func (h *Hide) SetXor(xor *big.Int) error {
	if xor == nil {
		return ErrNil
	}

	int32xor := *xor
	int32xor.And(&int32xor, int32Max)
	h.int32xor = &int32xor

	int64xor := *xor
	int64xor.And(&int64xor, int64Max)
	h.int64xor = &int64xor

	uint32xor := *xor
	uint32xor.And(&uint32xor, uint32Max)
	h.uint32xor = &uint32xor

	uint64xor := *xor
	uint64xor.And(&uint64xor, uint64Max)
	h.uint64xor = &uint64xor

	return nil
}

func (h *Hide) SetUint32(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(uint32Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.uint32prime = prime
	var inverse big.Int
	inverse.Set(prime)

	var plusOne big.Int
	h.uint32inverse = inverse.ModInverse(&inverse, plusOne.Add(uint32Max, bigOne))

	return nil
}

func (h *Hide) SetUint64(prime *big.Int) error {
	if prime == nil {
		return ErrNil
	}

	if prime.Cmp(uint64Max) > 0 {
		return ErrOutOfRange
	}

	if !prime.ProbablyPrime(100) {
		return ErrNotAPrime
	}

	h.uint64prime = prime
	var inverse big.Int
	inverse.Set(prime)

	var plusOne big.Int
	h.uint64inverse = inverse.ModInverse(&inverse, plusOne.Add(uint64Max, bigOne))

	return nil
}

func (h *Hide) Int32Obfuscate(i int32) int32 {
	return Int32Obfuscate(i, h.int32prime, h.int32xor)
}

func (h *Hide) Int32Deobfuscate(i int32) int32 {
	return Int32Deobfuscate(i, h.int32inverse, h.int32xor)
}

func (h *Hide) Int64Obfuscate(i int64) int64 {
	return Int64Obfuscate(i, h.int64prime, h.int64xor)
}

func (h *Hide) Int64Deobfuscate(i int64) int64 {
	return Int64Deobfuscate(i, h.int64inverse, h.int64xor)
}

func (h *Hide) Uint32Obfuscate(i uint32) uint32 {
	return Uint32Obfuscate(i, h.uint32prime, h.uint32xor)
}

func (h *Hide) Uint32Deobfuscate(i uint32) uint32 {
	return Uint32Deobfuscate(i, h.uint32inverse, h.uint32xor)
}

func (h *Hide) Uint64Obfuscate(i uint64) uint64 {
	return Uint64Obfuscate(i, h.uint64prime, h.uint64xor)
}

func (h *Hide) Uint64Deobfuscate(i uint64) uint64 {
	return Uint64Deobfuscate(i, h.uint64inverse, h.uint64xor)
}
<|endoftext|>


<commit_before>package rpcd

import (
	"encoding/gob"
	"errors"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/proto/imageserver"
)

func (t *srpcType) DeleteImage(conn *srpc.Conn) error {
	defer conn.Flush()
	var request imageserver.DeleteImageRequest
	var response imageserver.DeleteImageResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if err := t.deleteImage(request, &response); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if _, err := conn.WriteString("\n"); err != nil {
		return err
	}
	return gob.NewEncoder(conn).Encode(response)
}

func (t *srpcType) deleteImage(request imageserver.DeleteImageRequest,
	reply *imageserver.DeleteImageResponse) error {
	var response imageserver.DeleteImageResponse
	if t.replicationMaster != "" {
		return errors.New(replicationMessage + t.replicationMaster)
	}
	err := t.imageDataBase.DeleteImage(request.ImageName)
	if err == nil {
		response.Success = true
	} else {
		response.Success = false
		response.ErrorString = err.Error()
	}
	*reply = response
	return nil
}
<commit_msg>Add logging for DeleteImage() RPC.<commit_after>package rpcd

import (
	"encoding/gob"
	"errors"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/proto/imageserver"
)

func (t *srpcType) DeleteImage(conn *srpc.Conn) error {
	defer conn.Flush()
	var request imageserver.DeleteImageRequest
	var response imageserver.DeleteImageResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if err := t.deleteImage(request, &response); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if _, err := conn.WriteString("\n"); err != nil {
		return err
	}
	return gob.NewEncoder(conn).Encode(response)
}

func (t *srpcType) deleteImage(request imageserver.DeleteImageRequest,
	reply *imageserver.DeleteImageResponse) error {
	var response imageserver.DeleteImageResponse
	if t.replicationMaster != "" {
		return errors.New(replicationMessage + t.replicationMaster)
	}
	t.logger.Printf("DeleteImage(%s)\n", request.ImageName)
	err := t.imageDataBase.DeleteImage(request.ImageName)
	if err == nil {
		response.Success = true
	} else {
		response.Success = false
		response.ErrorString = err.Error()
	}
	*reply = response
	return nil
}
<|endoftext|>


<commit_before>package fdfs

import (
	"fmt"
	"github.com/ctripcorp/ghost/pool"
	"net"
	"time"
)

type poolInfo struct {
	host     string
	port     int
	minConns int
	maxConns int
}

func (this *poolInfo) makeConn() (net.Conn, error) {
	addr := fmt.Sprintf("%s:%d", this.host, this.port)
	conn, err := net.DialTimeout("tcp", addr, 30*time.Second)
	if err != nil {
		return nil, err
	}
	return conn, nil
}

func (this *poolInfo) newPool() (pool.Pool, error) {
	p, err := pool.NewBlockingPool(this.minConns, this.maxConns, this.makeConn)
	if err != nil {
		return nil, err
	}
	return p, nil
}
<commit_msg>add fdfs dial cat event<commit_after>package fdfs

import (
	"fmt"
	"github.com/ctripcorp/cat"
	"github.com/ctripcorp/ghost/pool"
	"net"
	"time"
)

type poolInfo struct {
	host     string
	port     int
	minConns int
	maxConns int
}

func (this *poolInfo) makeConn() (net.Conn, error) {
	Cat := cat.Instance()
	addr := fmt.Sprintf("%s:%d", this.host, this.port)
	conn, err := net.DialTimeout("tcp", addr, 30*time.Second)
	if err != nil {
		event := Cat.NewEvent("DialFdfs", "Fail")
		event.AddData("detail", err.Error())
		event.SetStatus("ERROR")
		event.Complete()
		return nil, err
	}
	event := Cat.NewEvent("DialFdfs", "Success")
	event.SetStatus("0")
	event.Complete()
	return nil, err
	return conn, nil
}

func (this *poolInfo) newPool() (pool.Pool, error) {
	p, err := pool.NewBlockingPool(this.minConns, this.maxConns, this.makeConn)
	if err != nil {
		return nil, err
	}
	return p, nil
}
<|endoftext|>


<commit_before>package hcs

import "C"

// This import is needed to make the library compile as CGO because HCSSHIM
// only works with CGO due to callbacks from HCS comming back from a C thread
// which is not supported without CGO. See https://github.com/golang/go/issues/10973
<commit_msg>HCS: Remove not anymore needed CGO dependency<commit_after><|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func makeTestDir() (string, error) {
	dir := filepath.Join(os.TempDir(), "testdir")

	mkErr := os.Mkdir(dir, 0777)
	if mkErr != nil {
		return "", mkErr
	}

	return dir, nil
}

func TestGetTextForKeyReturnsRightText(t *testing.T) {
	// arrange
	key := "testkey"
	dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

	filename := filepath.Join(dir, key)
	contents := []byte("Test string")
	writeErr := ioutil.WriteFile(filename, contents, 0777)
	if writeErr != nil {
		t.Errorf(writeErr.Error())
	}

	// act
	text, err := getTextForKey(dir, key)

	// assert
	if err != nil {
		t.Errorf(err.Error())
	} else if text != string(contents) {
		t.Errorf("Did not get back expected contents.")
	}
}

func TestGetTextForKeyReturnsError(t *testing.T) {
	dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

	text, getErr := getTextForKey(dir, "doesnotexist")
	if text != "" {
		t.Errorf(
			"Did not get back empty string from erroenous getTextForKey call")
	}
	if getErr == nil {
		t.Errorf("Did not get back error from erroneous getTextForKey call")
	}
}

func TestHash(t *testing.T) {
	data := []byte("GoPaste")
	hashed := hash(data)
	exp := "a06ee3951803be4f2be2cdb880a36b123620f87083fd8354bdc8f8fa79b17386"
	if hashed != exp {
		t.Errorf("Hash function did not return expected digest")
	}
}
<commit_msg>Add two tests for savePaste()<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func makeTestDir() (string, error) {
	dir := filepath.Join(os.TempDir(), "testdir")

	mkErr := os.Mkdir(dir, 0777)
	if mkErr != nil {
		return "", mkErr
	}

	return dir, nil
}

func TestGetTextForKeyReturnsRightText(t *testing.T) {
	// arrange
	key := "testkey"
	dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

	filename := filepath.Join(dir, key)
	contents := []byte("Test string")
	writeErr := ioutil.WriteFile(filename, contents, 0777)
	if writeErr != nil {
		t.Errorf(writeErr.Error())
	}

	// act
	text, err := getTextForKey(dir, key)

	// assert
	if err != nil {
		t.Errorf(err.Error())
	} else if text != string(contents) {
		t.Errorf("Did not get back expected contents.")
	}
}

func TestGetTextForKeyReturnsError(t *testing.T) {
	dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

	text, getErr := getTextForKey(dir, "doesnotexist")
	if text != "" {
		t.Errorf(
			"Did not get back empty string from erroenous getTextForKey call")
	}
	if getErr == nil {
		t.Errorf("Did not get back error from erroneous getTextForKey call")
	}
}

func TestSavePasteCreatesRightKey(t *testing.T) {
    dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

    testText := []byte("GoPaste")
    key, saveErr := savePaste(dir, string(testText))
    if saveErr != nil {
        t.Errorf(saveErr.Error())
    }
    if key != hash(testText) {
        t.Errorf("savePaste did not correctly create key.")
    }
}

func TestSavePasteSavesPaste(t *testing.T) {
    dir, mkDirErr := makeTestDir()
	if mkDirErr != nil {
		t.Errorf(mkDirErr.Error())
	}
	defer os.RemoveAll(dir)

    testText := "GoPaste"
    key, saveErr := savePaste(dir, testText)
    if saveErr != nil {
        t.Errorf(saveErr.Error())
    }

    path := filepath.Join(dir, key)
    text, readErr := ioutil.ReadFile(path)
    if readErr != nil {
        t.Errorf(readErr.Error())
    }
    if string(text) != testText {
        t.Errorf("Did not find expected text in saved paste")
    }
}

func TestHash(t *testing.T) {
	data := []byte("GoPaste")
	hashed := hash(data)
	exp := "a06ee3951803be4f2be2cdb880a36b123620f87083fd8354bdc8f8fa79b17386"
	if hashed != exp {
		t.Errorf("Hash function did not return expected digest")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

//go:build !windows
// +build !windows

package interp

import (
	"bufio"
	"context"
	"io"
	"os"
	"os/exec"
	"strings"
	"testing"

	"github.com/creack/pty"
)

func TestRunnerTerminalStdIO(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name  string
		files func(*testing.T) (secondary io.Writer, primary io.Reader)
		want  string
	}{
		{"Nil", func(t *testing.T) (io.Writer, io.Reader) {
			return nil, strings.NewReader("\n")
		}, "\n"},
		{"Pipe", func(t *testing.T) (io.Writer, io.Reader) {
			pr, pw := io.Pipe()
			return pw, pr
		}, "end\n"},
		{"Pseudo", func(t *testing.T) (io.Writer, io.Reader) {
			primary, secondary, err := pty.Open()
			if err != nil {
				t.Fatal(err)
			}
			return secondary, primary
		}, "012end\r\n"},
	}
	file := parse(t, nil, `
		for n in 0 1 2 3; do if [[ -t $n ]]; then echo -n $n; fi; done; echo end
	`)
	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			secondary, primary := test.files(t)
			// some secondary ends can be used as stdin too
			secondaryReader, _ := secondary.(io.Reader)

			r, _ := New(StdIO(secondaryReader, secondary, secondary))
			go func() {
				// To mimic os/exec.Cmd.Start, use a goroutine.
				if err := r.Run(context.Background(), file); err != nil {
					t.Error(err)
				}
			}()

			got, err := bufio.NewReader(primary).ReadString('\n')
			if err != nil {
				t.Fatal(err)
			}
			if got != test.want {
				t.Fatalf("\nwant: %q\ngot:  %q", test.want, got)
			}
			if closer, ok := secondary.(io.Closer); ok {
				if err := closer.Close(); err != nil {
					t.Fatal(err)
				}
			}
			if closer, ok := primary.(io.Closer); ok {
				if err := closer.Close(); err != nil {
					t.Fatal(err)
				}
			}
		})
	}
}

func TestRunnerTerminalExec(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name  string
		start func(*testing.T, *exec.Cmd) io.Reader
		want  string
	}{
		{"Nil", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			if err := cmd.Start(); err != nil {
				t.Fatal(err)
			}
			return strings.NewReader("\n")
		}, "\n"},
		{"Pipe", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			out, err := cmd.StdoutPipe()
			if err != nil {
				t.Fatal(err)
			}
			cmd.Stderr = cmd.Stdout
			if err := cmd.Start(); err != nil {
				t.Fatal(err)
			}
			return out
		}, "end\n"},
		{"Pseudo", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			// Note that we avoid pty.Start,
			// as it closes the secondary terminal via a defer,
			// possibly before the command has finished.
			// That can lead to "signal: hangup" flakes.
			primary, secondary, err := pty.Open()
			if err != nil {
				t.Fatal(err)
			}
			cmd.Stdin = secondary
			cmd.Stdout = secondary
			cmd.Stderr = secondary
			if err := cmd.Start(); err != nil {
				t.Fatal(err)
			}
			return primary
		}, "012end\r\n"},
	}
	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			cmd := exec.Command(os.Getenv("GOSH_PROG"),
				"for n in 0 1 2 3; do if [[ -t $n ]]; then echo -n $n; fi; done; echo end")
			primary := test.start(t, cmd)

			got, err := bufio.NewReader(primary).ReadString('\n')
			if err != nil {
				t.Fatal(err)
			}
			if got != test.want {
				t.Fatalf("\nwant: %q\ngot:  %q", test.want, got)
			}
			if closer, ok := primary.(io.Closer); ok {
				if err := closer.Close(); err != nil {
					t.Fatal(err)
				}
			}
			if err := cmd.Wait(); err != nil {
				t.Fatal(err)
			}
		})
	}
}

func shortPathName(path string) (string, error) {
	panic("only works on windows")
}
<commit_msg>interp: start using pty.Start again<commit_after>// Copyright (c) 2019, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

//go:build !windows
// +build !windows

package interp

import (
	"bufio"
	"context"
	"errors"
	"io"
	"os"
	"os/exec"
	"strings"
	"testing"

	"github.com/creack/pty"
)

func TestRunnerTerminalStdIO(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name  string
		files func(*testing.T) (secondary io.Writer, primary io.Reader)
		want  string
	}{
		{"Nil", func(t *testing.T) (io.Writer, io.Reader) {
			return nil, strings.NewReader("\n")
		}, "\n"},
		{"Pipe", func(t *testing.T) (io.Writer, io.Reader) {
			pr, pw := io.Pipe()
			return pw, pr
		}, "end\n"},
		{"Pseudo", func(t *testing.T) (io.Writer, io.Reader) {
			primary, secondary, err := pty.Open()
			if err != nil {
				t.Fatal(err)
			}
			return secondary, primary
		}, "012end\r\n"},
	}
	file := parse(t, nil, `
		for n in 0 1 2 3; do if [[ -t $n ]]; then echo -n $n; fi; done; echo end
	`)
	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			secondary, primary := test.files(t)
			// some secondary ends can be used as stdin too
			secondaryReader, _ := secondary.(io.Reader)

			r, _ := New(StdIO(secondaryReader, secondary, secondary))
			go func() {
				// To mimic os/exec.Cmd.Start, use a goroutine.
				if err := r.Run(context.Background(), file); err != nil {
					t.Error(err)
				}
			}()

			got, err := bufio.NewReader(primary).ReadString('\n')
			if err != nil {
				t.Fatal(err)
			}
			if got != test.want {
				t.Fatalf("\nwant: %q\ngot:  %q", test.want, got)
			}
			if closer, ok := secondary.(io.Closer); ok {
				if err := closer.Close(); err != nil {
					t.Fatal(err)
				}
			}
			if closer, ok := primary.(io.Closer); ok {
				if err := closer.Close(); err != nil {
					t.Fatal(err)
				}
			}
		})
	}
}

func TestRunnerTerminalExec(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name  string
		start func(*testing.T, *exec.Cmd) io.Reader
		want  string
	}{
		{"Nil", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			if err := cmd.Start(); err != nil {
				t.Fatal(err)
			}
			return strings.NewReader("\n")
		}, "\n"},
		{"Pipe", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			out, err := cmd.StdoutPipe()
			if err != nil {
				t.Fatal(err)
			}
			cmd.Stderr = cmd.Stdout
			if err := cmd.Start(); err != nil {
				t.Fatal(err)
			}
			return out
		}, "end\n"},
		{"Pseudo", func(t *testing.T, cmd *exec.Cmd) io.Reader {
			primary, err := pty.Start(cmd)
			if err != nil {
				t.Fatal(err)
			}
			return primary
		}, "012end\r\n"},
	}
	for _, test := range tests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			cmd := exec.Command(os.Getenv("GOSH_PROG"),
				"for n in 0 1 2 3; do if [[ -t $n ]]; then echo -n $n; fi; done; echo end")
			primary := test.start(t, cmd)

			got, err := bufio.NewReader(primary).ReadString('\n')
			if err != nil {
				t.Fatal(err)
			}
			if got != test.want {
				t.Fatalf("\nwant: %q\ngot:  %q", test.want, got)
			}
			if err := cmd.Wait(); err != nil {
				t.Fatal(err)
			}
			// Close the primary after we've waited for the process to stop.
			// Otherwise, the child process might see "signal: hangup",
			// as it unexpectedly finds its terminal to be closed too early.
			if closer, ok := primary.(io.Closer); ok {
				// Sometimes we'll get a "file already closed" error.
				// Presumably, this is because the other end may be closed first.
				if err := closer.Close(); err != nil && !errors.Is(err, os.ErrClosed) {
					t.Fatal(err)
				}
			}
		})
	}
}

func shortPathName(path string) (string, error) {
	panic("only works on windows")
}
<|endoftext|>


<commit_before>package cla

import (
	"github.com/google/go-github/github"
	"github.com/hansrodtang/pull"
)

type CheckerFunc func(username, email string) bool

func New(signed CheckerFunc) pull.Middleware {
	return func(client *github.Client, event *github.PullRequest) {
		user, repo, number := pull.Data(event)

		commits, _, _ := client.PullRequests.ListCommits(user, repo, number, nil)

		for _, c := range commits {
			var message *github.RepoStatus
			if signed(*c.Author.Login, *c.Commit.Author.Email) {
				message = pull.Success("", "CLA signed", "cla")
			} else {
				message = pull.Failure("", "CLA not signed", "cla")
			}
			client.Repositories.CreateStatus(user, repo, *c.SHA, message)
		}
	}
}
<commit_msg>Rename function.<commit_after>package cla

import (
	"github.com/google/go-github/github"
	"github.com/hansrodtang/pull"
)

type CLAFunc func(username, email string) bool

func New(signed CLAFunc) pull.Middleware {
	return func(client *github.Client, event *github.PullRequest) {
		user, repo, number := pull.Data(event)

		commits, _, _ := client.PullRequests.ListCommits(user, repo, number, nil)

		for _, c := range commits {
			var message *github.RepoStatus
			if signed(*c.Author.Login, *c.Commit.Author.Email) {
				message = pull.Success("", "CLA signed", "cla")
			} else {
				message = pull.Failure("", "CLA not signed", "cla")
			}
			client.Repositories.CreateStatus(user, repo, *c.SHA, message)
		}
	}
}
<|endoftext|>


<commit_before>// Package cli implements a colored text handler suitable for command-line interfaces.
package cli

import (
	"fmt"
	"io"
	"os"
	"sync"
	"time"

	"github.com/apex/log"
	"github.com/fatih/color"
)

// Default handler outputting to stderr.
var Default = New(os.Stderr)

// start time.
var start = time.Now()

var bold = color.New(color.Bold)

// colors.
const (
	none   = 0
	red    = 31
	green  = 32
	yellow = 33
	blue   = 34
	gray   = 37
)

// Colors mapping.
var Colors = [...]color.Attribute{
	log.DebugLevel: color.Attribute(gray),
	log.InfoLevel:  color.Attribute(blue),
	log.WarnLevel:  color.Attribute(yellow),
	log.ErrorLevel: color.Attribute(red),
	log.FatalLevel: color.Attribute(red),
}

// Strings mapping.
var Strings = [...]string{
	log.DebugLevel: "•",
	log.InfoLevel:  "•",
	log.WarnLevel:  "•",
	log.ErrorLevel: "⨯",
	log.FatalLevel: "⨯",
}

// Handler implementation.
type Handler struct {
	mu      sync.Mutex
	Writer  io.Writer
	Padding int
}

// New handler.
func New(w io.Writer) *Handler {
	return &Handler{
		Writer:  w,
		Padding: 3,
	}
}

// HandleLog implements log.Handler.
func (h *Handler) HandleLog(e *log.Entry) error {
	fg := color.New(Colors[e.Level])
	level := Strings[e.Level]
	names := e.Fields.Names()

	h.mu.Lock()
	defer h.mu.Unlock()

	fg.Fprintf(h.Writer, "%s %-25s", bold.Sprintf("%*s", h.Padding+1, level), e.Message)

	for _, name := range names {
		if name == "source" {
			continue
		}
		fmt.Fprintf(h.Writer, " %s=%s", fg.Sprint(name), e.Fields.Get(name))
	}

	fmt.Fprintln(h.Writer)

	return nil
}
<commit_msg>improved<commit_after>// Package cli implements a colored text handler suitable for command-line interfaces.
package cli

import (
	"fmt"
	"io"
	"os"
	"sync"
	"time"

	"github.com/apex/log"
	"github.com/fatih/color"
)

// Default handler outputting to stderr.
var Default = New(os.Stderr)

// start time.
var start = time.Now()

var bold = color.New(color.Bold)

// colors.
const (
	none   = 0
	red    = 31
	green  = 32
	yellow = 33
	blue   = 34
	gray   = 37
)

// Colors mapping.
var Colors = [...]*color.Color{
	log.DebugLevel: color.New(color.Attribute(gray)),
	log.InfoLevel:  color.New(color.Attribute(blue)),
	log.WarnLevel:  color.New(color.Attribute(yellow)),
	log.ErrorLevel: color.New(color.Attribute(red)),
	log.FatalLevel: color.New(color.Attribute(red)),
}

// Strings mapping.
var Strings = [...]string{
	log.DebugLevel: "•",
	log.InfoLevel:  "•",
	log.WarnLevel:  "•",
	log.ErrorLevel: "⨯",
	log.FatalLevel: "⨯",
}

// Handler implementation.
type Handler struct {
	mu      sync.Mutex
	Writer  io.Writer
	Padding int
}

// New handler.
func New(w io.Writer) *Handler {
	return &Handler{
		Writer:  w,
		Padding: 3,
	}
}

// HandleLog implements log.Handler.
func (h *Handler) HandleLog(e *log.Entry) error {
	color := Colors[e.Level]
	level := Strings[e.Level]
	names := e.Fields.Names()

	h.mu.Lock()
	defer h.mu.Unlock()

	color.Fprintf(h.Writer, "%s %-25s", bold.Sprintf("%*s", h.Padding+1, level), e.Message)

	for _, name := range names {
		if name == "source" {
			continue
		}
		fmt.Fprintf(h.Writer, " %s=%s", color.Sprint(name), e.Fields.Get(name))
	}

	fmt.Fprintln(h.Writer)

	return nil
}
<|endoftext|>


<commit_before>/*
	Package mtgox provides a streaming implementation of Mt. Gox's bitcoin trading API.
*/
package mtgox

import (
	"code.google.com/p/go.net/websocket"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"github.com/yanatan16/golang-mtgox/jsonws"
	"github.com/yanatan16/golang-mtgox/msgwatch"
	"strings"
	"fmt"
	"io/ioutil"
	"time"
	exq "github.com/yanatan16/exchequer"
)

type StreamType string
type OrderType string

const (
	api_host      string = "wss://websocket.mtgox.com:443"
	api_path      string = "/mtgox"
	http_endpoint string = "http://mtgox.com/api/2"
	origin_url    string = "http://localhost"

	TICKER StreamType = "ticker"
	DEPTH  StreamType = "depth"
	TRADES StreamType = "trades"

	BID OrderType = "bid"
	ASK OrderType = "ask"
)

var (
	// TODO: use https://mtgox.com/api/2/stream/list_public
	channels map[string]string = make(map[string]string)
	randStr  chan string
)

type StreamingApi struct {
	*msgwatch.MsgWatcher
	ws     *jsonws.JsonWebsocket
	key    []byte
	secret []byte
}

type Config struct {
	Currencies []string
	Key        string
	Secret     string
}

type CallResult struct {
	Result map[string]interface{}
	Success bool
	Error string
}

func NewFromConfig(cfgfile string) (*StreamingApi, error) {
	file, err := ioutil.ReadFile(cfgfile)
	if err != nil {
		return nil, err
	}

	m := new(Config)
	err = json.Unmarshal(file, m)
	if err != nil {
		return nil, err
	}

	return New(m.Key, m.Secret, m.Currencies...)
}

func New(key, secret string, currencies ...string) (*StreamingApi, error) {
	url := fmt.Sprintf("%s%s?Currency=%s", api_host, api_path, strings.Join(currencies, ","))
	config, _ := websocket.NewConfig(url, origin_url)
	ws, err := jsonws.New(config)

	if err != nil {
		return nil, err
	}

	api := &StreamingApi{
		MsgWatcher: msgwatch.New(ws.RecvForever()),
		ws:         ws,
	}

	api.key, err = hex.DecodeString(strings.Replace(key, "-", "", -1))
	if err != nil {
		return nil, err
	}

	api.secret, err = base64.StdEncoding.DecodeString(secret)
	if err != nil {
		return nil, err
	}

	remarks := api.Listen("remark")
	go func() {
		for remark := range remarks {
			fmt.Println("Remark:", remark)
		}
	}()

	return api, err
}

func (api *StreamingApi) Close() error {
	return api.ws.Close()
}

// Unsubscribe from a named channel
func (api *StreamingApi) Unsubscribe(name string) error {
	if key, ok := api.Channels[name]; ok {
		return api.ws.Send(map[string]interface{}{
			"op":      "unsubscribe",
			"channel": key,
		})
	}

	return errors.New("No channel with name " + name + ".")
}

// Subscribe to a type of channel. Returns the Listen(typ) listener.
func (api *StreamingApi) Subscribe(typs ...StreamType) (chan map[string]interface{}, error) {
	names := make([]string, len(typs))
	for i, typ := range typs {
		err := api.ws.Send(map[string]interface{}{
			"op":   "mtgox.subscribe",
			"type": string(typ),
		})

		if err != nil {
			return nil, err
		}
		names[i] = string(typ)
	}

	return api.Listen(names...), nil
}

func (api *StreamingApi) sign(body []byte) ([]byte, error) {
	mac := hmac.New(sha512.New, api.secret)
	_, err := mac.Write(body)
	if err != nil {
		return nil, err
	}

	return mac.Sum(nil), nil
}

func (api *StreamingApi) authenticatedSend(msg map[string]interface{}) error {
	if api.key == nil || api.secret == nil {
		return errors.New("API Key or secret is invalid or missing.")
	}

	req, err := json.Marshal(msg)
	if err != nil {
		return err
	}

	signedReq, err := api.sign(req)
	if err != nil {
		return err
	}

	reqid := msg["id"]

	fullReq := append(append(api.key, signedReq...), req...)
	encodedReq := base64.StdEncoding.EncodeToString(fullReq)

	fmt.Println("Request:", string(req))
	return api.ws.Send(map[string]interface{}{
		"op":      "call",
		"id":      reqid,
		"call":    encodedReq,
		"context": "mtgox.com",
	})
}

func (api *StreamingApi) call(endpoint string, params map[string]interface{}) (chan *CallResult, error) {
	if params == nil {
		params = make(map[string]interface{})
	}
	msg := map[string]interface{}{
		"call":   endpoint,
		"item":   "BTC",
		"params": params,
		"id":     <-ids,
		"nonce":  <-nonces,
	}

	err := api.authenticatedSend(msg)
	if err != nil {
		return nil, err
	}

	out := interpretResult(api.ListenResult(msg["id"].(string)))

	return out, nil
}

func interpretResult(in chan map[string]interface{}) (chan *CallResult) {
	out := make(chan *CallResult)
	go func () {
		res := <- in
		if op, err := exq.String(res, "op"); err == nil {
			if op == "remark" {
				out <- &CallResult{
					Success: false,
					Error: res["remark"].(string),
				}
			} else if op == "result" {
				out <- &CallResult{
					Success: true,
					Result: res["result"].(map[string]interface{}),
				}
			} else {
				out <- &CallResult{
					Success: false,
					Error: fmt.Sprintf("Don't know how to interpret: %s", res),
				}
			}
		} else {
			out <- &CallResult{
				Success: false,
				Error: fmt.Sprintf("Error accessing object: %s", err.Error()),
			}
		}
	}()
	return out
}

func (api *StreamingApi) Info() (chan *CallResult, error) {
	return api.call("private/info", nil)
}

func (api *StreamingApi) Address(description string) (chan *CallResult, error) {
	m := make(map[string]interface{})
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/address", m)
}

func (api *StreamingApi) AddPrivateKey(key string, desc string) (chan *CallResult, error) {
	return api.call("bitcoin/addpriv", map[string]interface{}{
		"key":         key,
		"keytype":     "auto",
		"description": desc,
	})
}

func (api *StreamingApi) AddWallet(walletdat, description string) (chan *CallResult, error) {
	m := map[string]interface{}{
		"wallet": walletdat,
	}
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/wallet_add", m)
}

func (api *StreamingApi) Send(addr string, amount_int uint64) (chan *CallResult, error) {
	return api.call("bitcoin/send_simple", map[string]interface{}{
		"address":    addr,
		"amount_int": amount_int,
	})
}

func (api *StreamingApi) IdKey() (chan *CallResult, error) {
	return api.call("private/idkey", nil)
}

func (api *StreamingApi) FullHistory(currency string, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) QueryHistory(currency string, typ string, begin, end *time.Time, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if typ != "" {
		m["type"] = typ
	}
	if begin != nil {
		m["date_start"] = begin.String()
	}
	if end != nil {
		m["date_end"] = end.String()
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) SubmitOrder(typ string, amount, price uint64) (chan *CallResult, error) {
	return api.call("order/add", map[string]interface{}{
		"type":       typ,
		"amount_int": amount,
		"price_int":  price,
	})
}

func (api *StreamingApi) CancelOrder(oid string) (chan *CallResult, error) {
	return api.call("order/cancel", map[string]interface{}{
		"oid": oid,
	})
}

func (api *StreamingApi) Orders() (chan *CallResult, error) {
	return api.call("private/orders", nil)
}

func (api *StreamingApi) OrderResult(oid string) (chan *CallResult, error) {
	return api.call("order/result", map[string]interface{}{"oid": oid})
}

func (api *StreamingApi) AddressDetails(addr string) (chan *CallResult, error) {
	return api.call("bitcoin/addr_details", map[string]interface{}{"hash": addr})
}

func (api *StreamingApi) Lag() (chan *CallResult, error) {
	return api.call("order/lag", nil)
}
<commit_msg>document NewFromConfig<commit_after>/*
	Package mtgox provides a streaming implementation of Mt. Gox's bitcoin trading API.
*/
package mtgox

import (
	"code.google.com/p/go.net/websocket"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"github.com/yanatan16/golang-mtgox/jsonws"
	"github.com/yanatan16/golang-mtgox/msgwatch"
	"strings"
	"fmt"
	"io/ioutil"
	"time"
	exq "github.com/yanatan16/exchequer"
)

type StreamType string
type OrderType string

const (
	api_host      string = "wss://websocket.mtgox.com:443"
	api_path      string = "/mtgox"
	http_endpoint string = "http://mtgox.com/api/2"
	origin_url    string = "http://localhost"

	TICKER StreamType = "ticker"
	DEPTH  StreamType = "depth"
	TRADES StreamType = "trades"

	BID OrderType = "bid"
	ASK OrderType = "ask"
)

var (
	// TODO: use https://mtgox.com/api/2/stream/list_public
	channels map[string]string = make(map[string]string)
	randStr  chan string
)

type StreamingApi struct {
	*msgwatch.MsgWatcher
	ws     *jsonws.JsonWebsocket
	key    []byte
	secret []byte
}

type Config struct {
	Currencies []string
	Key        string
	Secret     string
}

type CallResult struct {
	Result map[string]interface{}
	Success bool
	Error string
}

// Initialize a StreamingApi based on a json file unmarshalled into a Config object
func NewFromConfig(cfgfile string) (*StreamingApi, error) {
	file, err := ioutil.ReadFile(cfgfile)
	if err != nil {
		return nil, err
	}

	m := new(Config)
	err = json.Unmarshal(file, m)
	if err != nil {
		return nil, err
	}

	return New(m.Key, m.Secret, m.Currencies...)
}

func New(key, secret string, currencies ...string) (*StreamingApi, error) {
	url := fmt.Sprintf("%s%s?Currency=%s", api_host, api_path, strings.Join(currencies, ","))
	config, _ := websocket.NewConfig(url, origin_url)
	ws, err := jsonws.New(config)

	if err != nil {
		return nil, err
	}

	api := &StreamingApi{
		MsgWatcher: msgwatch.New(ws.RecvForever()),
		ws:         ws,
	}

	api.key, err = hex.DecodeString(strings.Replace(key, "-", "", -1))
	if err != nil {
		return nil, err
	}

	api.secret, err = base64.StdEncoding.DecodeString(secret)
	if err != nil {
		return nil, err
	}

	remarks := api.Listen("remark")
	go func() {
		for remark := range remarks {
			fmt.Println("Remark:", remark)
		}
	}()

	return api, err
}

func (api *StreamingApi) Close() error {
	return api.ws.Close()
}

// Unsubscribe from a named channel
func (api *StreamingApi) Unsubscribe(name string) error {
	if key, ok := api.Channels[name]; ok {
		return api.ws.Send(map[string]interface{}{
			"op":      "unsubscribe",
			"channel": key,
		})
	}

	return errors.New("No channel with name " + name + ".")
}

// Subscribe to a type of channel. Returns the Listen(typ) listener.
func (api *StreamingApi) Subscribe(typs ...StreamType) (chan map[string]interface{}, error) {
	names := make([]string, len(typs))
	for i, typ := range typs {
		err := api.ws.Send(map[string]interface{}{
			"op":   "mtgox.subscribe",
			"type": string(typ),
		})

		if err != nil {
			return nil, err
		}
		names[i] = string(typ)
	}

	return api.Listen(names...), nil
}

func (api *StreamingApi) sign(body []byte) ([]byte, error) {
	mac := hmac.New(sha512.New, api.secret)
	_, err := mac.Write(body)
	if err != nil {
		return nil, err
	}

	return mac.Sum(nil), nil
}

func (api *StreamingApi) authenticatedSend(msg map[string]interface{}) error {
	if api.key == nil || api.secret == nil {
		return errors.New("API Key or secret is invalid or missing.")
	}

	req, err := json.Marshal(msg)
	if err != nil {
		return err
	}

	signedReq, err := api.sign(req)
	if err != nil {
		return err
	}

	reqid := msg["id"]

	fullReq := append(append(api.key, signedReq...), req...)
	encodedReq := base64.StdEncoding.EncodeToString(fullReq)

	fmt.Println("Request:", string(req))
	return api.ws.Send(map[string]interface{}{
		"op":      "call",
		"id":      reqid,
		"call":    encodedReq,
		"context": "mtgox.com",
	})
}

func (api *StreamingApi) call(endpoint string, params map[string]interface{}) (chan *CallResult, error) {
	if params == nil {
		params = make(map[string]interface{})
	}
	msg := map[string]interface{}{
		"call":   endpoint,
		"item":   "BTC",
		"params": params,
		"id":     <-ids,
		"nonce":  <-nonces,
	}

	err := api.authenticatedSend(msg)
	if err != nil {
		return nil, err
	}

	out := interpretResult(api.ListenResult(msg["id"].(string)))

	return out, nil
}

func interpretResult(in chan map[string]interface{}) (chan *CallResult) {
	out := make(chan *CallResult)
	go func () {
		res := <- in
		if op, err := exq.String(res, "op"); err == nil {
			if op == "remark" {
				out <- &CallResult{
					Success: false,
					Error: res["remark"].(string),
				}
			} else if op == "result" {
				out <- &CallResult{
					Success: true,
					Result: res["result"].(map[string]interface{}),
				}
			} else {
				out <- &CallResult{
					Success: false,
					Error: fmt.Sprintf("Don't know how to interpret: %s", res),
				}
			}
		} else {
			out <- &CallResult{
				Success: false,
				Error: fmt.Sprintf("Error accessing object: %s", err.Error()),
			}
		}
	}()
	return out
}

func (api *StreamingApi) Info() (chan *CallResult, error) {
	return api.call("private/info", nil)
}

func (api *StreamingApi) Address(description string) (chan *CallResult, error) {
	m := make(map[string]interface{})
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/address", m)
}

func (api *StreamingApi) AddPrivateKey(key string, desc string) (chan *CallResult, error) {
	return api.call("bitcoin/addpriv", map[string]interface{}{
		"key":         key,
		"keytype":     "auto",
		"description": desc,
	})
}

func (api *StreamingApi) AddWallet(walletdat, description string) (chan *CallResult, error) {
	m := map[string]interface{}{
		"wallet": walletdat,
	}
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/wallet_add", m)
}

func (api *StreamingApi) Send(addr string, amount_int uint64) (chan *CallResult, error) {
	return api.call("bitcoin/send_simple", map[string]interface{}{
		"address":    addr,
		"amount_int": amount_int,
	})
}

func (api *StreamingApi) IdKey() (chan *CallResult, error) {
	return api.call("private/idkey", nil)
}

func (api *StreamingApi) FullHistory(currency string, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) QueryHistory(currency string, typ string, begin, end *time.Time, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if typ != "" {
		m["type"] = typ
	}
	if begin != nil {
		m["date_start"] = begin.String()
	}
	if end != nil {
		m["date_end"] = end.String()
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) SubmitOrder(typ string, amount, price uint64) (chan *CallResult, error) {
	return api.call("order/add", map[string]interface{}{
		"type":       typ,
		"amount_int": amount,
		"price_int":  price,
	})
}

func (api *StreamingApi) CancelOrder(oid string) (chan *CallResult, error) {
	return api.call("order/cancel", map[string]interface{}{
		"oid": oid,
	})
}

func (api *StreamingApi) Orders() (chan *CallResult, error) {
	return api.call("private/orders", nil)
}

func (api *StreamingApi) OrderResult(oid string) (chan *CallResult, error) {
	return api.call("order/result", map[string]interface{}{"oid": oid})
}

func (api *StreamingApi) AddressDetails(addr string) (chan *CallResult, error) {
	return api.call("bitcoin/addr_details", map[string]interface{}{"hash": addr})
}

func (api *StreamingApi) Lag() (chan *CallResult, error) {
	return api.call("order/lag", nil)
}
<|endoftext|>