<commit_before>package getter

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	urlhelper "github.com/hashicorp/go-getter/helper/url"
)

// Client is a client for downloading things.
//
// Top-level functions such as Get are shortcuts for interacting with a client.
// Using a client directly allows more fine-grained control over how downloading
// is done, as well as customizing the protocols supported.
type Client struct {
	// Src is the source URL to get.
	//
	// Dst is the path to save the downloaded thing as. If Dir is set to
	// true, then this should be a directory. If the directory doesn't exist,
	// it will be created for you.
	//
	// Pwd is the working directory for detection. If this isn't set, some
	// detection may fail. Client will not default pwd to the current
	// working directory for security reasons.
	Src string
	Dst string
	Pwd string

	// Dir, if true, tells the Client it is downloading a directory (versus
	// a single file). This distinction is necessary since filenames and
	// directory names follow the same format so disambiguating is impossible
	// without knowing ahead of time.
	Dir bool

	// Detectors is the list of detectors that are tried on the source.
	// If this is nil, then the default Detectors will be used.
	Detectors []Detector

	// Getters is the map of protocols supported by this client. If this
	// is nil, then the default Getters variable will be used.
	Getters map[string]Getter
}

// Get downloads the configured source to the destination.
func (c *Client) Get() error {
	// Detect the URL. This is safe if it is already detected.
	detectors := c.Detectors
	if detectors == nil {
		detectors = Detectors
	}
	src, err := Detect(c.Src, c.Pwd, detectors)
	if err != nil {
		return err
	}

	// Determine if we have a forced protocol, i.e. "git::http://..."
	force, src := getForcedGetter(src)

	// If there is a subdir component, then we download the root separately
	// and then copy over the proper subdir.
	var realDst string
	dst := c.Dst
	src, subDir := SourceDirSubdir(src)
	if subDir != "" {
		tmpDir, err := ioutil.TempDir("", "tf")
		if err != nil {
			return err
		}
		if err := os.RemoveAll(tmpDir); err != nil {
			return err
		}
		defer os.RemoveAll(tmpDir)

		realDst = dst
		dst = tmpDir
	}

	u, err := urlhelper.Parse(src)
	if err != nil {
		return err
	}
	if force == "" {
		force = u.Scheme
	}

	getters := c.Getters
	if getters == nil {
		getters = Getters
	}

	g, ok := getters[force]
	if !ok {
		return fmt.Errorf(
			"download not supported for scheme '%s'", force)
	}

	// We have magic query parameters that we use to signal different features
	q := u.Query()

	// Determine if we have an archive type
	archiveV := q.Get("archive")
	if archiveV == "" {
		// We don't appear to... but is it part of the filename?

	}

	// Determine if we have a checksum
	var checksumHash hash.Hash
	var checksumValue []byte
	if v := q.Get("checksum"); v != "" {
		// Delete the query parameter if we have it.
		q.Del("checksum")
		u.RawQuery = q.Encode()

		// If we're getting a directory, then this is an error. You cannot
		// checksum a directory. TODO: test
		if c.Dir {
			return fmt.Errorf(
				"checksum cannot be specified for directory download")
		}

		// Determine the checksum hash type
		checksumType := ""
		idx := strings.Index(v, ":")
		if idx > -1 {
			checksumType = v[:idx]
		}
		switch checksumType {
		case "md5":
			checksumHash = md5.New()
		case "sha1":
			checksumHash = sha1.New()
		case "sha256":
			checksumHash = sha256.New()
		case "sha512":
			checksumHash = sha512.New()
		default:
			return fmt.Errorf(
				"unsupported checksum type: %s", checksumType)
		}

		// Get the remainder of the value and parse it into bytes
		b, err := hex.DecodeString(v[idx+1:])
		if err != nil {
			return fmt.Errorf("invalid checksum: %s", err)
		}

		// Set our value
		checksumValue = b
	}

	// If we're not downloading a directory, then just download the file
	// and return.
	if !c.Dir {
		err := g.GetFile(dst, u)
		if err != nil {
			return err
		}

		if checksumHash != nil {
			return checksum(dst, checksumHash, checksumValue)
		}

		return nil
	}

	// We're downloading a directory, which might require a bit more work
	// if we're specifying a subdir.
	err = g.Get(dst, u)
	if err != nil {
		err = fmt.Errorf("error downloading '%s': %s", src, err)
		return err
	}

	// If we have a subdir, copy that over
	if subDir != "" {
		if err := os.RemoveAll(realDst); err != nil {
			return err
		}
		if err := os.MkdirAll(realDst, 0755); err != nil {
			return err
		}

		return copyDir(realDst, filepath.Join(dst, subDir), false)
	}

	return nil
}

// checksum is a simple method to compute the checksum of a source file
// and compare it to the given expected value.
func checksum(source string, h hash.Hash, v []byte) error {
	f, err := os.Open(source)
	if err != nil {
		return fmt.Errorf("Failed to open file for checksum: %s", err)
	}
	defer f.Close()

	if _, err := io.Copy(h, f); err != nil {
		return fmt.Errorf("Failed to hash: %s", err)
	}

	if actual := h.Sum(nil); !bytes.Equal(actual, v) {
		return fmt.Errorf(
			"Checksums did not match.\nExpected: %s\nGot: %s",
			hex.EncodeToString(v),
			hex.EncodeToString(actual))
	}

	return nil
}

var archiveMagic = map[string]struct{}{
	"tar.bz2": struct{}{},
	"tar":     struct{}{},
	"tar.gz":  struct{}{},
	"tbz2":    struct{}{},
	"tgz":     struct{}{},
	"zip":     struct{}{},
}
<commit_msg>unarchiving may work<commit_after>package getter

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	urlhelper "github.com/hashicorp/go-getter/helper/url"
)

// Client is a client for downloading things.
//
// Top-level functions such as Get are shortcuts for interacting with a client.
// Using a client directly allows more fine-grained control over how downloading
// is done, as well as customizing the protocols supported.
type Client struct {
	// Src is the source URL to get.
	//
	// Dst is the path to save the downloaded thing as. If Dir is set to
	// true, then this should be a directory. If the directory doesn't exist,
	// it will be created for you.
	//
	// Pwd is the working directory for detection. If this isn't set, some
	// detection may fail. Client will not default pwd to the current
	// working directory for security reasons.
	Src string
	Dst string
	Pwd string

	// Dir, if true, tells the Client it is downloading a directory (versus
	// a single file). This distinction is necessary since filenames and
	// directory names follow the same format so disambiguating is impossible
	// without knowing ahead of time.
	Dir bool

	// Detectors is the list of detectors that are tried on the source.
	// If this is nil, then the default Detectors will be used.
	Detectors []Detector

	// Decompressors is the map of decompressors supported by this client.
	// If this is nil, then the default value is the Decompressors global.
	Decompressors map[string]Decompressor

	// Getters is the map of protocols supported by this client. If this
	// is nil, then the default Getters variable will be used.
	Getters map[string]Getter
}

// Get downloads the configured source to the destination.
func (c *Client) Get() error {
	// Store this locally since there are cases we swap this
	dir := c.Dir

	// Default decompressor value
	decompressors := c.Decompressors
	if decompressors == nil {
		decompressors = Decompressors
	}

	// Detect the URL. This is safe if it is already detected.
	detectors := c.Detectors
	if detectors == nil {
		detectors = Detectors
	}
	src, err := Detect(c.Src, c.Pwd, detectors)
	if err != nil {
		return err
	}

	// Determine if we have a forced protocol, i.e. "git::http://..."
	force, src := getForcedGetter(src)

	// If there is a subdir component, then we download the root separately
	// and then copy over the proper subdir.
	var realDst string
	dst := c.Dst
	src, subDir := SourceDirSubdir(src)
	if subDir != "" {
		tmpDir, err := ioutil.TempDir("", "tf")
		if err != nil {
			return err
		}
		if err := os.RemoveAll(tmpDir); err != nil {
			return err
		}
		defer os.RemoveAll(tmpDir)

		realDst = dst
		dst = tmpDir
	}

	u, err := urlhelper.Parse(src)
	if err != nil {
		return err
	}
	if force == "" {
		force = u.Scheme
	}

	getters := c.Getters
	if getters == nil {
		getters = Getters
	}

	g, ok := getters[force]
	if !ok {
		return fmt.Errorf(
			"download not supported for scheme '%s'", force)
	}

	// We have magic query parameters that we use to signal different features
	q := u.Query()

	// Determine if we have an archive type
	archiveV := q.Get("archive")
	if archiveV != "" {
		q.Del("archive")
		u.RawQuery = q.Encode()
	}
	if archiveV == "" {
		// We don't appear to... but is it part of the filename?
		ext := filepath.Ext(u.Path)
		if _, ok := decompressors[ext]; ok {
			archiveV = ext
		}
	}

	// If we have a decompressor, then we need to change the destination
	// to download to a temporary path. We unarchive this into the final,
	// real path.
	var decompressDst string
	var decompressDir bool
	decompressor := decompressors[archiveV]
	if decompressor != nil {
		// Create a temporary directory to store our archive. We delete
		// this at the end of everything.
		td, err := ioutil.TempDir("", "getter")
		if err != nil {
			return fmt.Errorf(
				"Error creating temporary directory for archive: %s", err)
		}
		defer os.RemoveAll(td)

		// Swap the download directory to be our temporary path and
		// store the old values.
		decompressDst = dst
		decompressDir = dir
		dst = filepath.Join(td, "archive")
		dir = false
	}

	// Determine if we have a checksum
	var checksumHash hash.Hash
	var checksumValue []byte
	if v := q.Get("checksum"); v != "" {
		// Delete the query parameter if we have it.
		q.Del("checksum")
		u.RawQuery = q.Encode()

		// If we're getting a directory, then this is an error. You cannot
		// checksum a directory. TODO: test
		if dir {
			return fmt.Errorf(
				"checksum cannot be specified for directory download")
		}

		// Determine the checksum hash type
		checksumType := ""
		idx := strings.Index(v, ":")
		if idx > -1 {
			checksumType = v[:idx]
		}
		switch checksumType {
		case "md5":
			checksumHash = md5.New()
		case "sha1":
			checksumHash = sha1.New()
		case "sha256":
			checksumHash = sha256.New()
		case "sha512":
			checksumHash = sha512.New()
		default:
			return fmt.Errorf(
				"unsupported checksum type: %s", checksumType)
		}

		// Get the remainder of the value and parse it into bytes
		b, err := hex.DecodeString(v[idx+1:])
		if err != nil {
			return fmt.Errorf("invalid checksum: %s", err)
		}

		// Set our value
		checksumValue = b
	}

	// If we're not downloading a directory, then just download the file
	// and return.
	if !dir {
		err := g.GetFile(dst, u)
		if err != nil {
			return err
		}

		if checksumHash != nil {
			return checksum(dst, checksumHash, checksumValue)
		}

		if decompressor != nil {
			// We have a decompressor, so decompress the current destination
			// into the final destination with the proper mode.
			err := decompressor.Decompress(decompressDst, dst, decompressDir)
			if err != nil {
				return err
			}

			// Swap the information back
			dst = decompressDst
			dir = decompressDir
		}

		// We check the dir value again because it can be switched back
		// if we were unarchiving. If we're still only Get-ing a file, then
		// we're done.
		if !dir {
			return nil
		}
	}

	// If we're at this point we're either downloading a directory or we've
	// downloaded and unarchived a directory and we're just checking subdir.
	// In the case we have a decompressor we don't Get because it was Get
	// above.
	if decompressor == nil {
		// We're downloading a directory, which might require a bit more work
		// if we're specifying a subdir.
		err := g.Get(dst, u)
		if err != nil {
			err = fmt.Errorf("error downloading '%s': %s", src, err)
			return err
		}
	}

	// If we have a subdir, copy that over
	if subDir != "" {
		if err := os.RemoveAll(realDst); err != nil {
			return err
		}
		if err := os.MkdirAll(realDst, 0755); err != nil {
			return err
		}

		return copyDir(realDst, filepath.Join(dst, subDir), false)
	}

	return nil
}

// checksum is a simple method to compute the checksum of a source file
// and compare it to the given expected value.
func checksum(source string, h hash.Hash, v []byte) error {
	f, err := os.Open(source)
	if err != nil {
		return fmt.Errorf("Failed to open file for checksum: %s", err)
	}
	defer f.Close()

	if _, err := io.Copy(h, f); err != nil {
		return fmt.Errorf("Failed to hash: %s", err)
	}

	if actual := h.Sum(nil); !bytes.Equal(actual, v) {
		return fmt.Errorf(
			"Checksums did not match.\nExpected: %s\nGot: %s",
			hex.EncodeToString(v),
			hex.EncodeToString(actual))
	}

	return nil
}

var archiveMagic = map[string]struct{}{
	"tar.bz2": struct{}{},
	"tar":     struct{}{},
	"tar.gz":  struct{}{},
	"tbz2":    struct{}{},
	"tgz":     struct{}{},
	"zip":     struct{}{},
}
<|endoftext|>


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

// Package docker provides a client for the Docker remote API.
//
// See http://goo.gl/mxyql for more details on the remote API.
package docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/fsouza/go-dockerclient/term"
	"github.com/fsouza/go-dockerclient/utils"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"reflect"
	"strconv"
	"strings"
)

const userAgent = "go-dockerclient"

var (
	// ErrInvalidEndpoint is returned when the endpoint is not a valid HTTP URL.
	ErrInvalidEndpoint = errors.New("Invalid endpoint")

	// ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
	ErrConnectionRefused = errors.New("Cannot connect to Docker endpoint")
)

// Client is the basic type of this package. It provides methods for
// interaction with the API.
type Client struct {
	endpoint    string
	endpointURL *url.URL
	client      *http.Client
}

// NewClient returns a Client instance ready for communication with the
// given server endpoint.
func NewClient(endpoint string) (*Client, error) {
	u, err := parseEndpoint(endpoint)
	if err != nil {
		return nil, err
	}
	return &Client{
		endpoint:    endpoint,
		endpointURL: u,
		client:      http.DefaultClient,
	}, nil
}

func (c *Client) do(method, path string, data interface{}) ([]byte, int, error) {
	var params io.Reader
	if data != nil {
		buf, err := json.Marshal(data)
		if err != nil {
			return nil, -1, err
		}
		params = bytes.NewBuffer(buf)
	}
	req, err := http.NewRequest(method, c.getURL(path), params)
	if err != nil {
		return nil, -1, err
	}
	req.Header.Set("User-Agent", userAgent)
	if data != nil {
		req.Header.Set("Content-Type", "application/json")
	} else if method == "POST" {
		req.Header.Set("Content-Type", "plain/text")
	}
	var resp *http.Response
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol == "unix" {
		dial, err := net.Dial(protocol, address)
		if err != nil {
			return nil, -1, err
		}
		clientconn := httputil.NewClientConn(dial, nil)
		resp, err = clientconn.Do(req)
		defer clientconn.Close()
	} else {
		resp, err = c.client.Do(req)
	}
	if err != nil {
		if strings.Contains(err.Error(), "connection refused") {
			return nil, -1, ErrConnectionRefused
		}
		return nil, -1, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, -1, err
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		return nil, resp.StatusCode, newError(resp.StatusCode, body)
	}
	return body, resp.StatusCode, nil
}

func (c *Client) stream(method, path string, headers map[string]string, in io.Reader, out io.Writer) error {
	if (method == "POST" || method == "PUT") && in == nil {
		in = bytes.NewReader(nil)
	}
	req, err := http.NewRequest(method, c.getURL(path), in)
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", userAgent)
	if method == "POST" {
		req.Header.Set("Content-Type", "plain/text")
	}
	for key, val := range headers {
		req.Header.Set(key, val)
	}
	var resp *http.Response
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if out == nil {
		out = ioutil.Discard
	}
	if protocol == "unix" {
		dial, err := net.Dial(protocol, address)
		if err != nil {
			return err
		}
		clientconn := httputil.NewClientConn(dial, nil)
		resp, err = clientconn.Do(req)
		defer clientconn.Close()
	} else {
		resp, err = c.client.Do(req)
	}
	if err != nil {
		if strings.Contains(err.Error(), "connection refused") {
			return ErrConnectionRefused
		}
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		return newError(resp.StatusCode, body)
	}
	if resp.Header.Get("Content-Type") == "application/json" {
		dec := json.NewDecoder(resp.Body)
		for {
			var m jsonMessage
			if err := dec.Decode(&m); err == io.EOF {
				break
			} else if err != nil {
				return err
			}
			if m.Stream != "" {
				fmt.Fprintln(out, m.Stream)
			} else if m.Progress != "" {
				fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
			} else if m.Error != "" {
				return errors.New(m.Error)
			} else {
				fmt.Fprintln(out, m.Status)
			}
		}
	} else {
		if _, err := io.Copy(out, resp.Body); err != nil {
			return err
		}
	}
	return nil
}

func (c *Client) hijack(method, path string, setRawTerminal bool, in io.Reader, errStream io.Writer, out io.Writer) error {
	req, err := http.NewRequest(method, c.getURL(path), nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "plain/text")
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol != "unix" {
		protocol = "tcp"
		address = c.endpointURL.Host
	}
	dial, err := net.Dial(protocol, address)
	if err != nil {
		return err
	}
	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)
	defer clientconn.Close()
	rwc, br := clientconn.Hijack()
	defer rwc.Close()
	errStdout := make(chan error, 1)
	go func() {
		var err error
		if setRawTerminal {
			_, err = io.Copy(out, br)
		} else {
			_, err = utils.StdCopy(out, errStream, br)
		}
		errStdout <- err
	}()
	if inFile, ok := in.(*os.File); ok && setRawTerminal && term.IsTerminal(inFile.Fd()) && os.Getenv("NORAW") == "" {
		oldState, err := term.SetRawTerminal(inFile.Fd())
		if err != nil {
			return err
		}
		defer term.RestoreTerminal(inFile.Fd(), oldState)
	}
	go func() {
		if in != nil {
			io.Copy(rwc, in)
		}
		if err := rwc.(interface {
			CloseWrite() error
		}).CloseWrite(); err != nil && errStream != nil {
			fmt.Fprintf(errStream, "Couldn't send EOF: %s\n", err)
		}
	}()
	if err := <-errStdout; err != nil {
		return err
	}
	return nil
}

func (c *Client) getURL(path string) string {
	urlStr := strings.TrimRight(c.endpoint, "/")
	if c.endpointURL.Scheme == "unix" {
		urlStr = ""
	}
	return fmt.Sprintf("%s%s", urlStr, path)
}

type jsonMessage struct {
	Status   string `json:"status,omitempty"`
	Progress string `json:"progress,omitempty"`
	Error    string `json:"error,omitempty"`
	Stream   string `json:"stream,omitempty"`
}

func queryString(opts interface{}) string {
	if opts == nil {
		return ""
	}
	value := reflect.ValueOf(opts)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.Struct {
		return ""
	}
	items := url.Values(map[string][]string{})
	for i := 0; i < value.NumField(); i++ {
		field := value.Type().Field(i)
		if field.PkgPath != "" {
			continue
		}
		key := field.Tag.Get("qs")
		if key == "" {
			key = strings.ToLower(field.Name)
		} else if key == "-" {
			continue
		}
		v := value.Field(i)
		switch v.Kind() {
		case reflect.Bool:
			if v.Bool() {
				items.Add(key, "1")
			}
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			if v.Int() > 0 {
				items.Add(key, strconv.FormatInt(v.Int(), 10))
			}
		case reflect.Float32, reflect.Float64:
			if v.Float() > 0 {
				items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64))
			}
		case reflect.String:
			if v.String() != "" {
				items.Add(key, v.String())
			}
		case reflect.Ptr:
			if !v.IsNil() {
				if b, err := json.Marshal(v.Interface()); err == nil {
					items.Add(key, string(b))
				}
			}
		}
	}
	return items.Encode()
}

// Error represents failures in the API. It represents a failure from the API.
type Error struct {
	Status  int
	Message string
}

func newError(status int, body []byte) *Error {
	return &Error{Status: status, Message: string(body)}
}

func (e *Error) Error() string {
	return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
}

func parseEndpoint(endpoint string) (*url.URL, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, ErrInvalidEndpoint
	}
	if u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "unix" {
		return nil, ErrInvalidEndpoint
	}
	if u.Scheme != "unix" {
		_, port, err := net.SplitHostPort(u.Host)
		if err != nil {
			if e, ok := err.(*net.AddrError); ok {
				if e.Err == "missing port in address" {
					return u, nil
				}
			}
			return nil, ErrInvalidEndpoint
		}
		number, err := strconv.ParseInt(port, 10, 64)
		if err == nil && number > 0 && number < 65536 {
			return u, nil
		}
	} else {
		return u, nil // we don't need port when using a unix socket
	}
	return nil, ErrInvalidEndpoint
}
<commit_msg>Write to output in DockerClient.stream using fmt.Fprint instead of fmt.Fprintln.<commit_after>// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package docker provides a client for the Docker remote API.
//
// See http://goo.gl/mxyql for more details on the remote API.
package docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/fsouza/go-dockerclient/term"
	"github.com/fsouza/go-dockerclient/utils"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"reflect"
	"strconv"
	"strings"
)

const userAgent = "go-dockerclient"

var (
	// ErrInvalidEndpoint is returned when the endpoint is not a valid HTTP URL.
	ErrInvalidEndpoint = errors.New("Invalid endpoint")

	// ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
	ErrConnectionRefused = errors.New("Cannot connect to Docker endpoint")
)

// Client is the basic type of this package. It provides methods for
// interaction with the API.
type Client struct {
	endpoint    string
	endpointURL *url.URL
	client      *http.Client
}

// NewClient returns a Client instance ready for communication with the
// given server endpoint.
func NewClient(endpoint string) (*Client, error) {
	u, err := parseEndpoint(endpoint)
	if err != nil {
		return nil, err
	}
	return &Client{
		endpoint:    endpoint,
		endpointURL: u,
		client:      http.DefaultClient,
	}, nil
}

func (c *Client) do(method, path string, data interface{}) ([]byte, int, error) {
	var params io.Reader
	if data != nil {
		buf, err := json.Marshal(data)
		if err != nil {
			return nil, -1, err
		}
		params = bytes.NewBuffer(buf)
	}
	req, err := http.NewRequest(method, c.getURL(path), params)
	if err != nil {
		return nil, -1, err
	}
	req.Header.Set("User-Agent", userAgent)
	if data != nil {
		req.Header.Set("Content-Type", "application/json")
	} else if method == "POST" {
		req.Header.Set("Content-Type", "plain/text")
	}
	var resp *http.Response
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol == "unix" {
		dial, err := net.Dial(protocol, address)
		if err != nil {
			return nil, -1, err
		}
		clientconn := httputil.NewClientConn(dial, nil)
		resp, err = clientconn.Do(req)
		defer clientconn.Close()
	} else {
		resp, err = c.client.Do(req)
	}
	if err != nil {
		if strings.Contains(err.Error(), "connection refused") {
			return nil, -1, ErrConnectionRefused
		}
		return nil, -1, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, -1, err
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		return nil, resp.StatusCode, newError(resp.StatusCode, body)
	}
	return body, resp.StatusCode, nil
}

func (c *Client) stream(method, path string, headers map[string]string, in io.Reader, out io.Writer) error {
	if (method == "POST" || method == "PUT") && in == nil {
		in = bytes.NewReader(nil)
	}
	req, err := http.NewRequest(method, c.getURL(path), in)
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", userAgent)
	if method == "POST" {
		req.Header.Set("Content-Type", "plain/text")
	}
	for key, val := range headers {
		req.Header.Set(key, val)
	}
	var resp *http.Response
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if out == nil {
		out = ioutil.Discard
	}
	if protocol == "unix" {
		dial, err := net.Dial(protocol, address)
		if err != nil {
			return err
		}
		clientconn := httputil.NewClientConn(dial, nil)
		resp, err = clientconn.Do(req)
		defer clientconn.Close()
	} else {
		resp, err = c.client.Do(req)
	}
	if err != nil {
		if strings.Contains(err.Error(), "connection refused") {
			return ErrConnectionRefused
		}
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		return newError(resp.StatusCode, body)
	}
	if resp.Header.Get("Content-Type") == "application/json" {
		dec := json.NewDecoder(resp.Body)
		for {
			var m jsonMessage
			if err := dec.Decode(&m); err == io.EOF {
				break
			} else if err != nil {
				return err
			}
			if m.Stream != "" {
				fmt.Fprint(out, m.Stream)
			} else if m.Progress != "" {
				fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
			} else if m.Error != "" {
				return errors.New(m.Error)
			} else {
				fmt.Fprintln(out, m.Status)
			}
		}
	} else {
		if _, err := io.Copy(out, resp.Body); err != nil {
			return err
		}
	}
	return nil
}

func (c *Client) hijack(method, path string, setRawTerminal bool, in io.Reader, errStream io.Writer, out io.Writer) error {
	req, err := http.NewRequest(method, c.getURL(path), nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "plain/text")
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol != "unix" {
		protocol = "tcp"
		address = c.endpointURL.Host
	}
	dial, err := net.Dial(protocol, address)
	if err != nil {
		return err
	}
	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)
	defer clientconn.Close()
	rwc, br := clientconn.Hijack()
	defer rwc.Close()
	errStdout := make(chan error, 1)
	go func() {
		var err error
		if setRawTerminal {
			_, err = io.Copy(out, br)
		} else {
			_, err = utils.StdCopy(out, errStream, br)
		}
		errStdout <- err
	}()
	if inFile, ok := in.(*os.File); ok && setRawTerminal && term.IsTerminal(inFile.Fd()) && os.Getenv("NORAW") == "" {
		oldState, err := term.SetRawTerminal(inFile.Fd())
		if err != nil {
			return err
		}
		defer term.RestoreTerminal(inFile.Fd(), oldState)
	}
	go func() {
		if in != nil {
			io.Copy(rwc, in)
		}
		if err := rwc.(interface {
			CloseWrite() error
		}).CloseWrite(); err != nil && errStream != nil {
			fmt.Fprintf(errStream, "Couldn't send EOF: %s\n", err)
		}
	}()
	if err := <-errStdout; err != nil {
		return err
	}
	return nil
}

func (c *Client) getURL(path string) string {
	urlStr := strings.TrimRight(c.endpoint, "/")
	if c.endpointURL.Scheme == "unix" {
		urlStr = ""
	}
	return fmt.Sprintf("%s%s", urlStr, path)
}

type jsonMessage struct {
	Status   string `json:"status,omitempty"`
	Progress string `json:"progress,omitempty"`
	Error    string `json:"error,omitempty"`
	Stream   string `json:"stream,omitempty"`
}

func queryString(opts interface{}) string {
	if opts == nil {
		return ""
	}
	value := reflect.ValueOf(opts)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.Struct {
		return ""
	}
	items := url.Values(map[string][]string{})
	for i := 0; i < value.NumField(); i++ {
		field := value.Type().Field(i)
		if field.PkgPath != "" {
			continue
		}
		key := field.Tag.Get("qs")
		if key == "" {
			key = strings.ToLower(field.Name)
		} else if key == "-" {
			continue
		}
		v := value.Field(i)
		switch v.Kind() {
		case reflect.Bool:
			if v.Bool() {
				items.Add(key, "1")
			}
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			if v.Int() > 0 {
				items.Add(key, strconv.FormatInt(v.Int(), 10))
			}
		case reflect.Float32, reflect.Float64:
			if v.Float() > 0 {
				items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64))
			}
		case reflect.String:
			if v.String() != "" {
				items.Add(key, v.String())
			}
		case reflect.Ptr:
			if !v.IsNil() {
				if b, err := json.Marshal(v.Interface()); err == nil {
					items.Add(key, string(b))
				}
			}
		}
	}
	return items.Encode()
}

// Error represents failures in the API. It represents a failure from the API.
type Error struct {
	Status  int
	Message string
}

func newError(status int, body []byte) *Error {
	return &Error{Status: status, Message: string(body)}
}

func (e *Error) Error() string {
	return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
}

func parseEndpoint(endpoint string) (*url.URL, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, ErrInvalidEndpoint
	}
	if u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "unix" {
		return nil, ErrInvalidEndpoint
	}
	if u.Scheme != "unix" {
		_, port, err := net.SplitHostPort(u.Host)
		if err != nil {
			if e, ok := err.(*net.AddrError); ok {
				if e.Err == "missing port in address" {
					return u, nil
				}
			}
			return nil, ErrInvalidEndpoint
		}
		number, err := strconv.ParseInt(port, 10, 64)
		if err == nil && number > 0 && number < 65536 {
			return u, nil
		}
	} else {
		return u, nil // we don't need port when using a unix socket
	}
	return nil, ErrInvalidEndpoint
}
<|endoftext|>


<commit_before>package turnpike

import (
	glog "log"
	"os"
)

var (
	logFlags = glog.Ldate | glog.Ltime | glog.Lshortfile
	log      Logger
)

// Logger is an interface compatible with log.Logger.
type Logger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

type noopLogger struct{}

func (n noopLogger) Println(v ...interface{})               {}
func (n noopLogger) Printf(format string, v ...interface{}) {}

// setup logger for package, noop by default
func init() {
	if os.Getenv("DEBUG") != "" {
		log = glog.New(os.Stderr, "", logFlags)
	} else {
		log = noopLogger{}
	}
}

// Debug changes the log output to stderr
func Debug() {
	log = glog.New(os.Stderr, "", logFlags)
}

// SetLogger allows users to inject their own logger instead of the default one.
func SetLogger(l Logger) {
	log = l
}

func logErr(err error) error {
	if err == nil {
		return nil
	}
	if l, ok := log.(*glog.Logger); ok {
		l.Output(2, err.Error())
	} else {
		log.Println(err)
	}
	return err
}
<commit_msg>Add DebugOff function to switch to noop logger<commit_after>package turnpike

import (
	glog "log"
	"os"
)

var (
	logFlags = glog.Ldate | glog.Ltime | glog.Lshortfile
	log      Logger
)

// Logger is an interface compatible with log.Logger.
type Logger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

type noopLogger struct{}

func (n noopLogger) Println(v ...interface{})               {}
func (n noopLogger) Printf(format string, v ...interface{}) {}

// setup logger for package, noop by default
func init() {
	if os.Getenv("DEBUG") != "" {
		log = glog.New(os.Stderr, "", logFlags)
	} else {
		log = noopLogger{}
	}
}

// Debug changes the log output to stderr
func Debug() {
	log = glog.New(os.Stderr, "", logFlags)
}

// DebugOff changes the log to a noop logger
func DebugOff() {
	log = noopLogger{}
}

// SetLogger allows users to inject their own logger instead of the default one.
func SetLogger(l Logger) {
	log = l
}

func logErr(err error) error {
	if err == nil {
		return nil
	}
	if l, ok := log.(*glog.Logger); ok {
		l.Output(2, err.Error())
	} else {
		log.Println(err)
	}
	return err
}
<|endoftext|>


<commit_before>package allscripts

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
)

const ehrtokenregex = "[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}"
const dateregex = `^(19|20)[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,2}`

func checkParamValid(validvals []string, passed string) (err error) {
	for _, p := range validvals {
		if p == passed {
			return
		}
	}
	return errors.New(fmt.Sprintf("%s is not a valid value", passed))
}

func checkDateValid(date string) (err error) {
	var matched bool
	matched, err = regexp.Match(dateregex, []byte(date))
	if err != nil || !matched {
		return errors.New("not a valid date")
	}

	return
}

func checkValid(val []byte, regex string) (err error) {
	var matched bool
	matched, err = regexp.Match(regex, val)
	if err != nil || !matched {
		return errors.New("not a valid value")
	}

	return
}

// Client is a HTTP client of the Allscripts Professional API.
type Client struct {
	Userid      string
	Appname     string
	Appusername string
	Apppassword string
	Endpoint    string
	Token       string
}

type magicJsonRequest struct {
	Userid  string `json:"AppUserID"`
	Action  string `json:"Action"`
	Appname string `json:"Appname"`
	Patient string `json:"PatientID"`
	Token   string `json:"Token"`
	Param1  string `json:"Parameter1`
	Param2  string `json:"Parameter2`
	Param3  string `json:"Parameter3`
	Param4  string `json:"Parameter4`
	Param5  string `json:"Parameter5`
	Param6  string `json:"Parameter6`
	Data    string `json:"Data"`
}

// TokenRequest is the JSON request body that accompanies /GetToken API
// requests.
type TokenRequest struct {
	Username string `json:"Username"`
	Password string `json:"Password"`
}

// NewClient creates a new Client and returns it.
func NewClient(userid string, appname string, appusername string,
	apppassword string, endpoint string) Client {
	return Client{userid, appname, appusername, apppassword, endpoint, ""}
}

func (c *Client) getToken() (token string, err error) {
	var (
		raw     []byte
		req     *http.Request
		res     *http.Response
		resRaw  []byte
		matched bool
	)

	tr := TokenRequest{
		c.Appusername,
		c.Apppassword,
	}

	raw, err = json.Marshal(tr)
	if err != nil {
		return "", errors.New("unable to get app token")
	}

	client := &http.Client{}
	req, err = http.NewRequest("POST", c.Endpoint+"/GetToken",
		bytes.NewReader(raw))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/json")

	res, err = client.Do(req)
	if err != nil {
		return "", err
	}

	resRaw, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	res.Body.Close()

	matched, err = regexp.Match(ehrtokenregex, resRaw)
	if err != nil || !matched {
		return "", errors.New("unable to fetch GRT token from Allscripts")
	}

	token = string(resRaw)

	return
}

func (c *Client) constructReq(action string, data map[string]string) (req magicJsonRequest,
	err error) {
	if c.Token == "" {
		var token string
		token, err = c.getToken()
		if err != nil {
			return
		}
		c.Token = token
	}

	req = magicJsonRequest{
		c.Userid,
		action,
		c.Appname,
		data["Patient"],
		c.Token,
		data["Param1"],
		data["Param2"],
		data["Param3"],
		data["Param4"],
		data["Param5"],
		data["Param6"],
		data["Data"],
	}

	return
}

func (c *Client) makeRequest(reqbody magicJsonRequest) (resp []byte,
	err error) {
	var (
		raw []byte
		req *http.Request
		res *http.Response
	)

	raw, err = json.Marshal(reqbody)
	if err != nil {
		return
	}

	client := &http.Client{}
	req, err = http.NewRequest("POST", c.Endpoint+"/MagicJson",
		bytes.NewReader(raw))
	if err != nil {
		return []byte(nil), err
	}
	req.Header.Add("Content-Type", "application/json")

	res, err = client.Do(req)
	if err != nil {
		return []byte(nil), err
	}

	resp, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return []byte(nil), err
	}
	res.Body.Close()

	return
}
<commit_msg>Setting TokenRequest struct to private<commit_after>package allscripts

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
)

const ehrtokenregex = "[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}"
const dateregex = `^(19|20)[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,2}`

func checkParamValid(validvals []string, passed string) (err error) {
	for _, p := range validvals {
		if p == passed {
			return
		}
	}
	return errors.New(fmt.Sprintf("%s is not a valid value", passed))
}

func checkDateValid(date string) (err error) {
	var matched bool
	matched, err = regexp.Match(dateregex, []byte(date))
	if err != nil || !matched {
		return errors.New("not a valid date")
	}

	return
}

func checkValid(val []byte, regex string) (err error) {
	var matched bool
	matched, err = regexp.Match(regex, val)
	if err != nil || !matched {
		return errors.New("not a valid value")
	}

	return
}

// Client is a HTTP client of the Allscripts Professional API.
type Client struct {
	Userid      string
	Appname     string
	Appusername string
	Apppassword string
	Endpoint    string
	Token       string
}

type magicJsonRequest struct {
	Userid  string `json:"AppUserID"`
	Action  string `json:"Action"`
	Appname string `json:"Appname"`
	Patient string `json:"PatientID"`
	Token   string `json:"Token"`
	Param1  string `json:"Parameter1`
	Param2  string `json:"Parameter2`
	Param3  string `json:"Parameter3`
	Param4  string `json:"Parameter4`
	Param5  string `json:"Parameter5`
	Param6  string `json:"Parameter6`
	Data    string `json:"Data"`
}

type tokenRequest struct {
	Username string `json:"Username"`
	Password string `json:"Password"`
}

// NewClient creates a new Client and returns it.
func NewClient(userid string, appname string, appusername string,
	apppassword string, endpoint string) Client {
	return Client{userid, appname, appusername, apppassword, endpoint, ""}
}

func (c *Client) getToken() (token string, err error) {
	var (
		raw     []byte
		req     *http.Request
		res     *http.Response
		resRaw  []byte
		matched bool
	)

	tr := tokenRequest{
		c.Appusername,
		c.Apppassword,
	}

	raw, err = json.Marshal(tr)
	if err != nil {
		return "", errors.New("unable to get app token")
	}

	client := &http.Client{}
	req, err = http.NewRequest("POST", c.Endpoint+"/GetToken",
		bytes.NewReader(raw))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/json")

	res, err = client.Do(req)
	if err != nil {
		return "", err
	}

	resRaw, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	res.Body.Close()

	matched, err = regexp.Match(ehrtokenregex, resRaw)
	if err != nil || !matched {
		return "", errors.New("unable to fetch GRT token from Allscripts")
	}

	token = string(resRaw)

	return
}

func (c *Client) constructReq(action string, data map[string]string) (req magicJsonRequest,
	err error) {
	if c.Token == "" {
		var token string
		token, err = c.getToken()
		if err != nil {
			return
		}
		c.Token = token
	}

	req = magicJsonRequest{
		c.Userid,
		action,
		c.Appname,
		data["Patient"],
		c.Token,
		data["Param1"],
		data["Param2"],
		data["Param3"],
		data["Param4"],
		data["Param5"],
		data["Param6"],
		data["Data"],
	}

	return
}

func (c *Client) makeRequest(reqbody magicJsonRequest) (resp []byte,
	err error) {
	var (
		raw []byte
		req *http.Request
		res *http.Response
	)

	raw, err = json.Marshal(reqbody)
	if err != nil {
		return
	}

	client := &http.Client{}
	req, err = http.NewRequest("POST", c.Endpoint+"/MagicJson",
		bytes.NewReader(raw))
	if err != nil {
		return []byte(nil), err
	}
	req.Header.Add("Content-Type", "application/json")

	res, err = client.Do(req)
	if err != nil {
		return []byte(nil), err
	}

	resp, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return []byte(nil), err
	}
	res.Body.Close()

	return
}
<|endoftext|>


<commit_before>package magina

import (
	"fmt"
	"github.com/ruizeng/magina/packets"
	"github.com/streadway/amqp"
	"log"
	"net"
)

const (
	defaultPubsubExchange = "pubsub"
	defaultCrpcExchange   = "crpc"
	defaultDrpcExchange   = "drpc"
)

type Client struct {
	Conn       net.Conn
	Broker     *Broker
	Identifier string
	Channel    *amqp.Channel
}

func (c *Client) initRabbit() error {
	var err error
	if c.Channel == nil {
		c.Channel, err = c.Broker.RabbitConnection.Channel()
		if err != nil {
			return err
		}

		err = c.Channel.ExchangeDeclare(
			defaultPubsubExchange, // name
			"topic",               // type
			true,                  // durable
			false,                 // auto-deleted
			false,                 // internal
			false,                 // no-wait
			nil,                   // arguments
		)

		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Client) trySendPacket(packet packets.ControlPacket) {
	log.Printf("try send packet******** \n%v\n**********\n", packet)
	err := packet.Write(c.Conn)
	if err != nil {
		log.Println(err)
	}
}

func (c *Client) handlePublish(pub *packets.PublishPacket) error {
	if c.Channel == nil {
		return fmt.Errorf("client channel not ready")
	}
	err := c.Channel.Publish(defaultPubsubExchange,
		pub.TopicName, false, false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        pub.Payload,
		})
	return err
}

func (c *Client) handleSubscribe(sub *packets.SubscribePacket) error {
	if c.Channel == nil {
		return fmt.Errorf("client channel not ready")
	}
	q, err := c.Channel.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	if err != nil {
		return err
	}

	err = c.Channel.QueueBind(
		q.Name,                // queue name
		sub.Topics[0],         // routing key
		defaultPubsubExchange, // exchange
		false,
		nil,
	)
	if err != nil {
		return err
	}

	msgs, err := c.Channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	if err != nil {
		return err
	}

	go func() {
		for d := range msgs {
			pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
			pub.Payload = d.Body
			pub.TopicName = d.RoutingKey
			c.trySendPacket(pub)
		}
	}()

	suback := packets.NewControlPacket(packets.Suback).(*packets.SubackPacket)
	suback.MessageID = sub.MessageID
	c.trySendPacket(suback)
	return nil
}

func (c *Client) Serve() {
	defer func() {
		if c.Channel != nil {
			c.Channel.Close()
		}
		if c.Conn != nil {
			c.Conn.Close()
		}
	}()
	needDisconnect := false
	for {
		if needDisconnect {
			break
		}
		packet, err := packets.ReadPacket(c.Conn)
		if err != nil {
			log.Printf("reading packets from connection error: %v", err)
			break
		}
		log.Printf("packet received =========\n%v\n===============\n", packet)
		switch packet.(type) {
		case *packets.ConnectPacket:
			conn := packet.(*packets.ConnectPacket)
			ca := packets.NewControlPacket(packets.Connack).(*packets.ConnackPacket)
			ca.ReturnCode = conn.Validate()
			err = c.initRabbit()
			if err != nil {
				log.Printf("init rabbitmq for client failed: %v\n", err)
				ca.ReturnCode = packets.ErrRefusedServerUnavailable
			}
			c.trySendPacket(ca)
		case *packets.DisconnectPacket:
			log.Println("disconnecting client...")
			needDisconnect = true
		case *packets.PingreqPacket:
			pres := packets.NewControlPacket(packets.Pingresp)
			log.Println("ping back to cliend...")
			c.trySendPacket(pres)
		case *packets.PublishPacket:
			pub := packet.(*packets.PublishPacket)
			c.handlePublish(pub)
		case *packets.SubscribePacket:
			sub := packet.(*packets.SubscribePacket)
			c.handleSubscribe(sub)
		default:
			log.Println("unknown packet: ", packet)
		}
	}
}
<commit_msg>change: support topic unsubscribe bugfix: none<commit_after>package magina

import (
	"fmt"
	"github.com/ruizeng/magina/packets"
	"github.com/streadway/amqp"
	"log"
	"net"
)

const (
	defaultPubsubExchange = "pubsub"
	defaultCrpcExchange   = "crpc"
	defaultDrpcExchange   = "drpc"
)

type Client struct {
	Conn       net.Conn
	Broker     *Broker
	Identifier string
	Channel    *amqp.Channel
	TopicQueue map[string]string
}

func (c *Client) initRabbit() error {
	var err error
	if c.Channel == nil {
		c.Channel, err = c.Broker.RabbitConnection.Channel()
		if err != nil {
			return err
		}

		err = c.Channel.ExchangeDeclare(
			defaultPubsubExchange, // name
			"topic",               // type
			true,                  // durable
			false,                 // auto-deleted
			false,                 // internal
			false,                 // no-wait
			nil,                   // arguments
		)

		if err != nil {
			return err
		}
	}

	if c.TopicQueue == nil {
		c.TopicQueue = make(map[string]string)
	}

	return nil
}

func (c *Client) trySendPacket(packet packets.ControlPacket) error {
	log.Printf("try send packet******** \n%v\n**********\n", packet)
	return packet.Write(c.Conn)
}

func (c *Client) handlePublish(pub *packets.PublishPacket) error {
	if c.Channel == nil {
		return fmt.Errorf("client channel not ready")
	}
	err := c.Channel.Publish(defaultPubsubExchange,
		pub.TopicName, false, false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        pub.Payload,
		})
	return err
}

func (c *Client) handleSubscribe(sub *packets.SubscribePacket) error {
	if c.Channel == nil {
		return fmt.Errorf("client channel not ready")
	}
	q, err := c.Channel.QueueDeclare(
		"",    // name
		false, // durable
		true,  // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	if err != nil {
		return err
	}

	topic := sub.Topics[0] // only suport one topic a time now

	err = c.Channel.QueueBind(
		q.Name, // queue name
		topic,  // routing key
		defaultPubsubExchange, // exchange
		false,
		nil,
	)
	if err != nil {
		return err
	}

	c.TopicQueue[topic] = q.Name

	msgs, err := c.Channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	if err != nil {
		return err
	}

	go func() {
		for d := range msgs {
			pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
			pub.Payload = d.Body
			pub.TopicName = d.RoutingKey
			c.trySendPacket(pub)
		}
	}()

	suback := packets.NewControlPacket(packets.Suback).(*packets.SubackPacket)
	suback.MessageID = sub.MessageID
	suback.Qos = sub.Qos
	c.trySendPacket(suback)
	return nil
}

func (c *Client) handleUnsubscribe(unsub *packets.UnsubscribePacket) error {
	if c.Channel == nil {
		return fmt.Errorf("client channel not ready")
	}

	topic := unsub.Topics[0] // only suport one topic a time now

	if queueName, exist := c.TopicQueue[topic]; exist {
		err := c.Channel.QueueUnbind(queueName, topic, defaultPubsubExchange, nil)
		delete(c.TopicQueue, topic)
		if err != nil {
			return err
		}
	}
	unsuback := packets.NewControlPacket(packets.Unsuback).(*packets.UnsubackPacket)
	unsuback.MessageID = unsub.MessageID
	unsuback.Qos = unsub.Qos
	return c.trySendPacket(unsuback)
}

func (c *Client) Serve() {
	defer func() {
		if c.Channel != nil {
			c.Channel.Close()
			c.Channel = nil
		}
		if c.Conn != nil {
			c.Conn.Close()
			c.Conn = nil
		}
	}()
	needDisconnect := false
	for {
		if needDisconnect {
			break
		}
		packet, err := packets.ReadPacket(c.Conn)
		if err != nil {
			log.Printf("reading packets from connection error: %v", err)
			break
		}
		log.Printf("packet received =========\n%v\n===============\n", packet)
		switch packet.(type) {
		case *packets.ConnectPacket:
			conn := packet.(*packets.ConnectPacket)
			ca := packets.NewControlPacket(packets.Connack).(*packets.ConnackPacket)
			ca.ReturnCode = conn.Validate()
			err = c.initRabbit()
			if err != nil {
				log.Printf("init rabbitmq for client failed: %v\n", err)
				ca.ReturnCode = packets.ErrRefusedServerUnavailable
			}
			err = c.trySendPacket(ca)
		case *packets.DisconnectPacket:
			log.Println("disconnecting client...")
			needDisconnect = true
		case *packets.PingreqPacket:
			pres := packets.NewControlPacket(packets.Pingresp)
			log.Println("ping back to cliend...")
			err = c.trySendPacket(pres)
		case *packets.PublishPacket:
			pub := packet.(*packets.PublishPacket)
			err = c.handlePublish(pub)
		case *packets.SubscribePacket:
			sub := packet.(*packets.SubscribePacket)
			err = c.handleSubscribe(sub)
		case *packets.UnsubscribePacket:
			unsub := packet.(*packets.UnsubscribePacket)
			err = c.handleUnsubscribe(unsub)
		default:
			log.Println("unknown packet: ", packet)
		}
		if err != nil {
			log.Println("handle packat error: ", err)
		}
	}
}
<|endoftext|>


<commit_before>package bitbucket

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

	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/bitbucket"
	"golang.org/x/oauth2/clientcredentials"
)

const DEFAULT_PAGE_LENGTH = 10

type Client struct {
	Auth         *auth
	Users        users
	User         user
	Teams        teams
	Repositories *Repositories
	Pagelen      uint64
}

type auth struct {
	appID, secret  string
	user, password string
	token          oauth2.Token
}

// Uses the Client Credentials Grant oauth2 flow to authenticate to Bitbucket
func NewOAuthClientCredentials(i, s string) *Client {
	a := &auth{app_id: i, secret: s}
	ctx := context.Background()
	conf := &clientcredentials.Config{
		ClientID:     i,
		ClientSecret: s,
		TokenURL:     bitbucket.Endpoint.TokenURL,
	}

	tok, err := conf.Token(ctx)
	if err != nil {
		log.Fatal(err)
	}
	a.token = *tok
	return injectClient(a)

}

func NewOAuth(i, s string) *Client {
	a := &auth{appID: i, secret: s}
	ctx := context.Background()
	conf := &oauth2.Config{
		ClientID:     i,
		ClientSecret: s,
		Endpoint:     bitbucket.Endpoint,
	}

	// Redirect user to consent page to ask for permission
	// for the scopes specified above.
	url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
	fmt.Printf("Visit the URL for the auth dialog:\n%v", url)

	// Use the authorization code that is pushed to the redirect
	// URL. Exchange will do the handshake to retrieve the
	// initial access token. The HTTP Client returned by
	// conf.Client will refresh the token as necessary.
	var code string
	fmt.Printf("Enter the code in the return URL: ")
	if _, err := fmt.Scan(&code); err != nil {
		log.Fatal(err)
	}
	tok, err := conf.Exchange(ctx, code)
	if err != nil {
		log.Fatal(err)
	}
	a.token = *tok
	return injectClient(a)
}

func NewBasicAuth(u, p string) *Client {
	a := &auth{user: u, password: p}
	return injectClient(a)
}

func injectClient(a *auth) *Client {
	c := &Client{Auth: a, Pagelen: DEFAULT_PAGE_LENGTH}
	c.Repositories = &Repositories{
		c:                  c,
		PullRequests:       &PullRequests{c: c},
		Repository:         &Repository{c: c},
		Commits:            &Commits{c: c},
		Diff:               &Diff{c: c},
		BranchRestrictions: &BranchRestrictions{c: c},
		Webhooks:           &Webhooks{c: c},
	}
	c.Users = &Users{c: c}
	c.User = &User{c: c}
	c.Teams = &Teams{c: c}
	return c
}

func (c *Client) execute(method string, urlStr string, text string) (interface{}, error) {
	// Use pagination if changed from default value
	const DEC_RADIX = 10
	if strings.Contains(urlStr, "/repositories/") {
		if c.Pagelen != DEFAULT_PAGE_LENGTH {
			urlObj, err := url.Parse(urlStr)
			if err != nil {
				return nil, err
			}
			q := urlObj.Query()
			q.Set("pagelen", strconv.FormatUint(c.Pagelen, DEC_RADIX))
			urlObj.RawQuery = q.Encode()
			urlStr = urlObj.String()
		}
	}

	body := strings.NewReader(text)
	req, err := http.NewRequest(method, urlStr, body)
	if text != "" {
		req.Header.Set("Content-Type", "application/json")
	}

	if err != nil {
		return nil, err
	}

	if c.Auth.user != "" && c.Auth.password != "" {
		req.SetBasicAuth(c.Auth.user, c.Auth.password)
	} else if c.Auth.token.Valid() {
		c.Auth.token.SetAuthHeader(req)
	}

	client := new(http.Client)
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.Body != nil {
		defer resp.Body.Close()
	}

	if (resp.StatusCode != http.StatusOK) && (resp.StatusCode != http.StatusCreated) {
		return nil, fmt.Errorf(resp.Status)
	}

	if resp.Body == nil {
		return nil, fmt.Errorf("response body is nil")
	}

	resBodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var result interface{}
	err = json.Unmarshal(resBodyBytes, &result)
	if err != nil {
		return nil, err
	}

	resultMap, isMap := result.(map[string]interface{})
	if isMap {
		nextIn := resultMap["next"]
		valuesIn := resultMap["values"]
		if nextIn != nil && valuesIn != nil {
			nextUrl := nextIn.(string)
			if nextUrl != "" {
				valuesSlice := valuesIn.([]interface{})
				if valuesSlice != nil {
					nextResult, err := c.execute(method, nextUrl, text)
					if err != nil {
						return nil, err
					}
					nextResultMap, isNextMap := nextResult.(map[string]interface{})
					if !isNextMap {
						return nil, fmt.Errorf("next page result is not map, it's %T", nextResult)
					}
					nextValuesIn := nextResultMap["values"]
					if nextValuesIn == nil {
						return nil, fmt.Errorf("next page result has no values")
					}
					nextValuesSlice, isSlice := nextValuesIn.([]interface{})
					if !isSlice {
						return nil, fmt.Errorf("next page result 'values' is not slice")
					}
					valuesSlice = append(valuesSlice, nextValuesSlice...)
					resultMap["values"] = valuesSlice
					delete(resultMap, "page")
					delete(resultMap, "pagelen")
					delete(resultMap, "size")
					result = resultMap
				}
			}
		}
	}

	return result, nil
}

func (c *Client) requestUrl(template string, args ...interface{}) string {

	if len(args) == 1 && args[0] == "" {
		return GetApiBaseURL() + template
	}
	return GetApiBaseURL() + fmt.Sprintf(template, args...)
}
<commit_msg>Fix wrong field name<commit_after>package bitbucket

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

	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/bitbucket"
	"golang.org/x/oauth2/clientcredentials"
)

const DEFAULT_PAGE_LENGTH = 10

type Client struct {
	Auth         *auth
	Users        users
	User         user
	Teams        teams
	Repositories *Repositories
	Pagelen      uint64
}

type auth struct {
	appID, secret  string
	user, password string
	token          oauth2.Token
}

// Uses the Client Credentials Grant oauth2 flow to authenticate to Bitbucket
func NewOAuthClientCredentials(i, s string) *Client {
	a := &auth{appID: i, secret: s}
	ctx := context.Background()
	conf := &clientcredentials.Config{
		ClientID:     i,
		ClientSecret: s,
		TokenURL:     bitbucket.Endpoint.TokenURL,
	}

	tok, err := conf.Token(ctx)
	if err != nil {
		log.Fatal(err)
	}
	a.token = *tok
	return injectClient(a)

}

func NewOAuth(i, s string) *Client {
	a := &auth{appID: i, secret: s}
	ctx := context.Background()
	conf := &oauth2.Config{
		ClientID:     i,
		ClientSecret: s,
		Endpoint:     bitbucket.Endpoint,
	}

	// Redirect user to consent page to ask for permission
	// for the scopes specified above.
	url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
	fmt.Printf("Visit the URL for the auth dialog:\n%v", url)

	// Use the authorization code that is pushed to the redirect
	// URL. Exchange will do the handshake to retrieve the
	// initial access token. The HTTP Client returned by
	// conf.Client will refresh the token as necessary.
	var code string
	fmt.Printf("Enter the code in the return URL: ")
	if _, err := fmt.Scan(&code); err != nil {
		log.Fatal(err)
	}
	tok, err := conf.Exchange(ctx, code)
	if err != nil {
		log.Fatal(err)
	}
	a.token = *tok
	return injectClient(a)
}

func NewBasicAuth(u, p string) *Client {
	a := &auth{user: u, password: p}
	return injectClient(a)
}

func injectClient(a *auth) *Client {
	c := &Client{Auth: a, Pagelen: DEFAULT_PAGE_LENGTH}
	c.Repositories = &Repositories{
		c:                  c,
		PullRequests:       &PullRequests{c: c},
		Repository:         &Repository{c: c},
		Commits:            &Commits{c: c},
		Diff:               &Diff{c: c},
		BranchRestrictions: &BranchRestrictions{c: c},
		Webhooks:           &Webhooks{c: c},
	}
	c.Users = &Users{c: c}
	c.User = &User{c: c}
	c.Teams = &Teams{c: c}
	return c
}

func (c *Client) execute(method string, urlStr string, text string) (interface{}, error) {
	// Use pagination if changed from default value
	const DEC_RADIX = 10
	if strings.Contains(urlStr, "/repositories/") {
		if c.Pagelen != DEFAULT_PAGE_LENGTH {
			urlObj, err := url.Parse(urlStr)
			if err != nil {
				return nil, err
			}
			q := urlObj.Query()
			q.Set("pagelen", strconv.FormatUint(c.Pagelen, DEC_RADIX))
			urlObj.RawQuery = q.Encode()
			urlStr = urlObj.String()
		}
	}

	body := strings.NewReader(text)
	req, err := http.NewRequest(method, urlStr, body)
	if text != "" {
		req.Header.Set("Content-Type", "application/json")
	}

	if err != nil {
		return nil, err
	}

	if c.Auth.user != "" && c.Auth.password != "" {
		req.SetBasicAuth(c.Auth.user, c.Auth.password)
	} else if c.Auth.token.Valid() {
		c.Auth.token.SetAuthHeader(req)
	}

	client := new(http.Client)
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.Body != nil {
		defer resp.Body.Close()
	}

	if (resp.StatusCode != http.StatusOK) && (resp.StatusCode != http.StatusCreated) {
		return nil, fmt.Errorf(resp.Status)
	}

	if resp.Body == nil {
		return nil, fmt.Errorf("response body is nil")
	}

	resBodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var result interface{}
	err = json.Unmarshal(resBodyBytes, &result)
	if err != nil {
		return nil, err
	}

	resultMap, isMap := result.(map[string]interface{})
	if isMap {
		nextIn := resultMap["next"]
		valuesIn := resultMap["values"]
		if nextIn != nil && valuesIn != nil {
			nextUrl := nextIn.(string)
			if nextUrl != "" {
				valuesSlice := valuesIn.([]interface{})
				if valuesSlice != nil {
					nextResult, err := c.execute(method, nextUrl, text)
					if err != nil {
						return nil, err
					}
					nextResultMap, isNextMap := nextResult.(map[string]interface{})
					if !isNextMap {
						return nil, fmt.Errorf("next page result is not map, it's %T", nextResult)
					}
					nextValuesIn := nextResultMap["values"]
					if nextValuesIn == nil {
						return nil, fmt.Errorf("next page result has no values")
					}
					nextValuesSlice, isSlice := nextValuesIn.([]interface{})
					if !isSlice {
						return nil, fmt.Errorf("next page result 'values' is not slice")
					}
					valuesSlice = append(valuesSlice, nextValuesSlice...)
					resultMap["values"] = valuesSlice
					delete(resultMap, "page")
					delete(resultMap, "pagelen")
					delete(resultMap, "size")
					result = resultMap
				}
			}
		}
	}

	return result, nil
}

func (c *Client) requestUrl(template string, args ...interface{}) string {

	if len(args) == 1 && args[0] == "" {
		return GetApiBaseURL() + template
	}
	return GetApiBaseURL() + fmt.Sprintf(template, args...)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"reflect"

	"github.com/jmoiron/sqlx"
)

//Client is our SQL client
type Client struct {
	db      *sqlx.DB
	history []string
}

//Row will hold rows of our SQL table
type Row []interface{}

//Result will hold our SQL query resultset
type Result struct {
	Columns []string `json:"columns"`
	Rows    []Row    `json:"rows"`
}

//NewClient will create a new client
func NewClient() (*Client, error) {
	db, err := sqlx.Open("mysql", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

//NewClientFromURL will create a new mysql client using the URL provided in parameters
func NewClientFromURL(url string) (*Client, error) {
	fmt.Println(url)
	db, err := sqlx.Open("mysql", url)

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

//Close disconnects a existing connection
func (client *Client) Close() error {
	return client.db.Close()
}

//Test if we have a working connection with the database
func (client *Client) Test() error {
	return client.db.Ping()
}

func (client *Client) recordQuery(query string) {
	client.history = append(client.history, query)
}

//Info of our connected database
func (client *Client) Info() (*Result, error) {
	return client.Query(MySQLInfo)
}

//Databases will list all the databases in the system
func (client *Client) Databases() ([]string, error) {
	res, err := client.Query(MySQLDatabases)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseTables will give you list of tables belonging to the database
func (client *Client) DatabaseTables(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseTables, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseViews will give you list of views belonging to the database
func (client *Client) DatabaseViews(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseViews, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseProcedures returns a list of all the stored procedures in the database
func (client *Client) DatabaseProcedures(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseProcedures, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseFunctions returns a list of all the functions in the database
func (client *Client) DatabaseFunctions(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseFunctions, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//TableInfo will return info like data used, row count etc.
func (client *Client) TableInfo(table string) (*Result, error) {
	return client.Query(fmt.Sprintf(MySQLTableInfo, table))
}

//TableIndexes returns all the indexes of the table
func (client *Client) TableIndexes(table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableIndexs, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

func (client *Client) TableColumns(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableColumns, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//ProcedureParameters returns all the paramaters of a stored procedure
func (client *Client) ProcedureParameters(procedure string, database string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLProcedureParameters, procedure, database))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DatabaseCollationCharSet returns all the collation and character sets in db
func (client *Client) DatabaseCollationCharSet() (*Result, error) {
	res, err := client.Query(MySQLAllCollationCharSet)

	if err != nil {
		return nil, err
	}

	return res, err
}

//AlterDatabase let's you set character set & collation of the database
func (client *Client) AlterDatabase(database string, charset string, collation string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseAlter, database, charset, collation))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DropDatabase will drop the database from the system
func (client *Client) DropDatabase(database string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseDrop, database))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DropTable will drop the table from selected database
func (client *Client) DropTable(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableDrop, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//TruncateTable will truncate the table
func (client *Client) TruncateTable(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableTruncate, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//ProcedureDefinition will give you the create statement of procedure/function
func (client *Client) ProcedureDefinition(procType string, database string, name string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLProcedureDefinition, procType, database, name))

	if err != nil {
		return nil, err
	}

	return res, err
}

func (client *Client) DropProcedure(procType string, database string, name string) (bool, error) {
	_, err := client.Execute(fmt.Sprintf(MySQLProcedureDrop, procType, database, name))

	if err != nil {
		return false, err
	}

	return true, err
}

func (client *Client) ProcedureCreate(procType string, database string, name string, definition string) (bool, error) {
	trans, err := client.db.Begin()

	if err != nil {
		return false, err
	}

	//set this as default database
	_, err = trans.Exec(fmt.Sprintf("use %s;", database))

	//Drop existing procedure
	_, err = trans.Exec(fmt.Sprintf(MySQLProcedureDrop, procType, database, name))

	if err != nil {
		return false, err
	}

	//Create new definition
	//yoIndex := 10
	//if procType == "FUNCTION" {
	//	yoIndex = 9
	//}
	//mehIndex := strings.Index(definition, procType+" `")
	//newDef := splice(definition, mehIndex+yoIndex, 0, "`"+database+"`.")

	_, err = trans.Exec(definition)

	if err != nil {
		return false, err
	}

	return true, nil
}

func (client *Client) ViewDefinition(database string, name string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLViewDefinition, database, name))

	if err != nil {
		return nil, err
	}

	return res, err
}

//Query will execute the sql query passed as parameter, and return the resultset
func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	client.recordQuery(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func (client *Client) Execute(query string) (int64, error) {
	res, err := client.db.Exec(query)

	if err != nil {
		return -1, err
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return -1, err
	}

	return rowsAffected, nil
}

//Format the resultset
func (res *Result) Format() []map[string]interface{} {
	var items []map[string]interface{}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		items = append(items, item)
	}

	return items
}

//CSV will format the sql resultset as CSV
func (res *Result) CSV() []byte {
	buff := &bytes.Buffer{}
	writer := csv.NewWriter(buff)

	writer.Write(res.Columns)

	for _, row := range res.Rows {
		record := make([]string, len(res.Columns))

		for i, item := range row {
			if item != nil {
				record[i] = fmt.Sprintf("%v", item)
			} else {
				record[i] = ""
			}
		}

		err := writer.Write(record)

		if err != nil {
			fmt.Println(err)
			break
		}
	}

	writer.Flush()
	return buff.Bytes()
}
<commit_msg>Clear the history on connection close<commit_after>package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"reflect"

	"github.com/jmoiron/sqlx"
)

//Client is our SQL client
type Client struct {
	db      *sqlx.DB
	history []string
}

//Row will hold rows of our SQL table
type Row []interface{}

//Result will hold our SQL query resultset
type Result struct {
	Columns []string `json:"columns"`
	Rows    []Row    `json:"rows"`
}

//NewClient will create a new client
func NewClient() (*Client, error) {
	db, err := sqlx.Open("mysql", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

//NewClientFromURL will create a new mysql client using the URL provided in parameters
func NewClientFromURL(url string) (*Client, error) {
	fmt.Println(url)
	db, err := sqlx.Open("mysql", url)

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

//Close disconnects a existing connection
func (client *Client) Close() error {
	//Clear history
	client.history = nil
	return client.db.Close()
}

//Test if we have a working connection with the database
func (client *Client) Test() error {
	return client.db.Ping()
}

func (client *Client) recordQuery(query string) {
	client.history = append(client.history, query)
}

//Info of our connected database
func (client *Client) Info() (*Result, error) {
	return client.Query(MySQLInfo)
}

//Databases will list all the databases in the system
func (client *Client) Databases() ([]string, error) {
	res, err := client.Query(MySQLDatabases)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseTables will give you list of tables belonging to the database
func (client *Client) DatabaseTables(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseTables, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseViews will give you list of views belonging to the database
func (client *Client) DatabaseViews(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseViews, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseProcedures returns a list of all the stored procedures in the database
func (client *Client) DatabaseProcedures(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseProcedures, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//DatabaseFunctions returns a list of all the functions in the database
func (client *Client) DatabaseFunctions(database string) ([]string, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseFunctions, database))

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

//TableInfo will return info like data used, row count etc.
func (client *Client) TableInfo(table string) (*Result, error) {
	return client.Query(fmt.Sprintf(MySQLTableInfo, table))
}

//TableIndexes returns all the indexes of the table
func (client *Client) TableIndexes(table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableIndexs, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

func (client *Client) TableColumns(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableColumns, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//ProcedureParameters returns all the paramaters of a stored procedure
func (client *Client) ProcedureParameters(procedure string, database string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLProcedureParameters, procedure, database))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DatabaseCollationCharSet returns all the collation and character sets in db
func (client *Client) DatabaseCollationCharSet() (*Result, error) {
	res, err := client.Query(MySQLAllCollationCharSet)

	if err != nil {
		return nil, err
	}

	return res, err
}

//AlterDatabase let's you set character set & collation of the database
func (client *Client) AlterDatabase(database string, charset string, collation string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseAlter, database, charset, collation))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DropDatabase will drop the database from the system
func (client *Client) DropDatabase(database string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLDatabaseDrop, database))

	if err != nil {
		return nil, err
	}

	return res, err
}

//DropTable will drop the table from selected database
func (client *Client) DropTable(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableDrop, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//TruncateTable will truncate the table
func (client *Client) TruncateTable(database string, table string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLTableTruncate, database, table))

	if err != nil {
		return nil, err
	}

	return res, err
}

//ProcedureDefinition will give you the create statement of procedure/function
func (client *Client) ProcedureDefinition(procType string, database string, name string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLProcedureDefinition, procType, database, name))

	if err != nil {
		return nil, err
	}

	return res, err
}

func (client *Client) DropProcedure(procType string, database string, name string) (bool, error) {
	_, err := client.Execute(fmt.Sprintf(MySQLProcedureDrop, procType, database, name))

	if err != nil {
		return false, err
	}

	return true, err
}

func (client *Client) ProcedureCreate(procType string, database string, name string, definition string) (bool, error) {
	trans, err := client.db.Begin()

	if err != nil {
		return false, err
	}

	//set this as default database
	_, err = trans.Exec(fmt.Sprintf("use %s;", database))

	//Drop existing procedure
	_, err = trans.Exec(fmt.Sprintf(MySQLProcedureDrop, procType, database, name))

	if err != nil {
		return false, err
	}

	//Create new definition
	//yoIndex := 10
	//if procType == "FUNCTION" {
	//	yoIndex = 9
	//}
	//mehIndex := strings.Index(definition, procType+" `")
	//newDef := splice(definition, mehIndex+yoIndex, 0, "`"+database+"`.")

	_, err = trans.Exec(definition)

	if err != nil {
		return false, err
	}

	return true, nil
}

func (client *Client) ViewDefinition(database string, name string) (*Result, error) {
	res, err := client.Query(fmt.Sprintf(MySQLViewDefinition, database, name))

	if err != nil {
		return nil, err
	}

	return res, err
}

//Query will execute the sql query passed as parameter, and return the resultset
func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	client.recordQuery(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func (client *Client) Execute(query string) (int64, error) {
	res, err := client.db.Exec(query)

	if err != nil {
		return -1, err
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return -1, err
	}

	return rowsAffected, nil
}

//Format the resultset
func (res *Result) Format() []map[string]interface{} {
	var items []map[string]interface{}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		items = append(items, item)
	}

	return items
}

//CSV will format the sql resultset as CSV
func (res *Result) CSV() []byte {
	buff := &bytes.Buffer{}
	writer := csv.NewWriter(buff)

	writer.Write(res.Columns)

	for _, row := range res.Rows {
		record := make([]string, len(res.Columns))

		for i, item := range row {
			if item != nil {
				record[i] = fmt.Sprintf("%v", item)
			} else {
				record[i] = ""
			}
		}

		err := writer.Write(record)

		if err != nil {
			fmt.Println(err)
			break
		}
	}

	writer.Flush()
	return buff.Bytes()
}
<|endoftext|>


<commit_before>package socketio_client

import (
	"net/url"
	"path"
	"reflect"
	"strings"
	"sync"
)

type Options struct {
	Transport string            //protocol name string,websocket polling...
	Query     map[string]string //url的附加的参数
	Header 	  map[string][]string
}

type Client struct {
	opts *Options

	conn *clientConn

	eventsLock sync.RWMutex
	events     map[string]*caller
	acks       map[int]*caller
	id         int
	namespace  string
}

func NewClient(uri string, opts *Options) (client *Client, err error) {

	url, err := url.Parse(uri)
	if err != nil {
		return
	}
	url.Path = path.Join("/socket.io", url.Path)
	url.Path = url.EscapedPath()
	if strings.HasSuffix(url.Path, "socket.io") {
		url.Path += "/"
	}
	q := url.Query()
	for k, v := range opts.Query {
		q.Set(k, v)
	}
	url.RawQuery = q.Encode()

	socket, err := newClientConn(opts, url)
	if err != nil {
		return
	}

	client = &Client{
		opts: opts,
		conn: socket,

		events: make(map[string]*caller),
		acks:   make(map[int]*caller),
	}

	go client.readLoop()

	return
}

func (client *Client) On(message string, f interface{}) (err error) {
	c, err := newCaller(f)
	if err != nil {
		return
	}
	client.eventsLock.Lock()
	client.events[message] = c
	client.eventsLock.Unlock()
	return
}

func (client *Client) Emit(message string, args ...interface{}) (err error) {
	var c *caller
	if l := len(args); l > 0 {
		fv := reflect.ValueOf(args[l-1])
		if fv.Kind() == reflect.Func {
			var err error
			c, err = newCaller(args[l-1])
			if err != nil {
				return err
			}
			args = args[:l-1]
		}
	}
	args = append([]interface{}{message}, args...)
	if c != nil {
		id, err := client.sendId(args)
		if err != nil {
			return err
		}
		client.eventsLock.Lock()
		client.acks[id] = c
		client.eventsLock.Unlock()
		return nil
	}
	return client.send(args)
}

func (client *Client) sendConnect() error {
	packet := packet{
		Type: _CONNECT,
		Id:   -1,
		NSP:  client.namespace,
	}
	encoder := newEncoder(client.conn)
	return encoder.Encode(packet)
}

func (client *Client) sendId(args []interface{}) (int, error) {
	packet := packet{
		Type: _EVENT,
		Id:   client.id,
		NSP:  client.namespace,
		Data: args,
	}
	client.id++
	if client.id < 0 {
		client.id = 0
	}
	encoder := newEncoder(client.conn)
	err := encoder.Encode(packet)
	if err != nil {
		return -1, nil
	}
	return packet.Id, nil
}

func (client *Client) send(args []interface{}) error {
	packet := packet{
		Type: _EVENT,
		Id:   -1,
		NSP:  client.namespace,
		Data: args,
	}
	encoder := newEncoder(client.conn)
	return encoder.Encode(packet)
}

func (client *Client) onPacket(decoder *decoder, packet *packet) ([]interface{}, error) {
	var message string
	switch packet.Type {
	case _CONNECT:
		message = "connection"
	case _DISCONNECT:
		message = "disconnection"
	case _ERROR:
		message = "error"
	case _ACK:
		fallthrough
	case _BINARY_ACK:
		return nil, client.onAck(packet.Id, decoder, packet)
	default:
		message = decoder.Message()
	}
	client.eventsLock.RLock()
	c, ok := client.events[message]
	client.eventsLock.RUnlock()
	if !ok {
		// If the message is not recognized by the server, the decoder.currentCloser
		// needs to be closed otherwise the server will be stuck until the e
		decoder.Close()
		return nil, nil
	}
	args := c.GetArgs()
	olen := len(args)
	if olen > 0 {
		packet.Data = &args
		if err := decoder.DecodeData(packet); err != nil {
			return nil, err
		}
	}
	for i := len(args); i < olen; i++ {
		args = append(args, nil)
	}

	retV := c.Call(args)
	if len(retV) == 0 {
		return nil, nil
	}

	var err error
	if last, ok := retV[len(retV)-1].Interface().(error); ok {
		err = last
		retV = retV[0 : len(retV)-1]
	}
	ret := make([]interface{}, len(retV))
	for i, v := range retV {
		ret[i] = v.Interface()
	}
	return ret, err
}

func (client *Client) onAck(id int, decoder *decoder, packet *packet) error {
	client.eventsLock.RLock()
	c, ok := client.acks[id]
	client.eventsLock.RUnlock()
	if !ok {
		return nil
	}
	delete(client.acks, id)

	args := c.GetArgs()
	packet.Data = &args
	if err := decoder.DecodeData(packet); err != nil {
		return err
	}
	c.Call(args)
	return nil
}

func (client *Client) readLoop() error {
	defer func() {
		p := packet{
			Type: _DISCONNECT,
			Id:   -1,
		}
		client.onPacket(nil, &p)
	}()

	for {
		decoder := newDecoder(client.conn)
		var p packet
		if err := decoder.Decode(&p); err != nil {
			return err
		}
		ret, err := client.onPacket(decoder, &p)
		if err != nil {
			return err
		}
		switch p.Type {
		case _CONNECT:
			client.namespace = p.NSP
			// !!!下面这个不能有，否则会有死循环
			//client.sendConnect()
		case _BINARY_EVENT:
			fallthrough
		case _EVENT:
			if p.Id >= 0 {
				p := packet{
					Type: _ACK,
					Id:   p.Id,
					NSP:  client.namespace,
					Data: ret,
				}
				encoder := newEncoder(client.conn)
				if err := encoder.Encode(p); err != nil {
					return err
				}
			}
		case _DISCONNECT:
			return nil
		}
	}
}
<commit_msg>Fixed struct field read/write race condition<commit_after>package socketio_client

import (
	"net/url"
	"path"
	"reflect"
	"strings"
	"sync"
)

type Options struct {
	Transport string            //protocol name string,websocket polling...
	Query     map[string]string //url的附加的参数
	Header 	  map[string][]string
}

type Client struct {
	opts *Options

	conn *clientConn

	eventsLock sync.RWMutex
	events     map[string]*caller
	acks       map[int]*caller
	id         int
	namespace  string
}

func NewClient(uri string, opts *Options) (client *Client, err error) {

	url, err := url.Parse(uri)
	if err != nil {
		return
	}
	url.Path = path.Join("/socket.io", url.Path)
	url.Path = url.EscapedPath()
	if strings.HasSuffix(url.Path, "socket.io") {
		url.Path += "/"
	}
	q := url.Query()
	for k, v := range opts.Query {
		q.Set(k, v)
	}
	url.RawQuery = q.Encode()

	socket, err := newClientConn(opts, url)
	if err != nil {
		return
	}

	client = &Client{
		opts: opts,
		conn: socket,

		events: make(map[string]*caller),
		acks:   make(map[int]*caller),
	}

	go client.readLoop()

	return
}

func (client *Client) On(message string, f interface{}) (err error) {
	c, err := newCaller(f)
	if err != nil {
		return
	}
	client.eventsLock.Lock()
	client.events[message] = c
	client.eventsLock.Unlock()
	return
}

func (client *Client) Emit(message string, args ...interface{}) (err error) {
	var c *caller
	if l := len(args); l > 0 {
		fv := reflect.ValueOf(args[l-1])
		if fv.Kind() == reflect.Func {
			var err error
			c, err = newCaller(args[l-1])
			if err != nil {
				return err
			}
			args = args[:l-1]
		}
	}
	args = append([]interface{}{message}, args...)
	if c != nil {
		id, err := client.sendId(args)
		if err != nil {
			return err
		}
		client.eventsLock.Lock()
		client.acks[id] = c
		client.eventsLock.Unlock()
		return nil
	}
	return client.send(args)
}

func (client *Client) sendConnect() error {
	packet := packet{
		Type: _CONNECT,
		Id:   -1,
		NSP:  client.namespace,
	}
	encoder := newEncoder(client.conn)
	return encoder.Encode(packet)
}

func (client *Client) sendId(args []interface{}) (int, error) {
	client.eventsLock.Lock()
	packet := packet{
		Type: _EVENT,
		Id:   client.id,
		NSP:  client.namespace,
		Data: args,
	}
	client.id++
	if client.id < 0 {
		client.id = 0
	}
	client.eventsLock.Unlock()

	encoder := newEncoder(client.conn)
	err := encoder.Encode(packet)
	if err != nil {
		return -1, nil
	}
	return packet.Id, nil
}

func (client *Client) send(args []interface{}) error {
	packet := packet{
		Type: _EVENT,
		Id:   -1,
		NSP:  client.namespace,
		Data: args,
	}
	encoder := newEncoder(client.conn)
	return encoder.Encode(packet)
}

func (client *Client) onPacket(decoder *decoder, packet *packet) ([]interface{}, error) {
	var message string
	switch packet.Type {
	case _CONNECT:
		message = "connection"
	case _DISCONNECT:
		message = "disconnection"
	case _ERROR:
		message = "error"
	case _ACK:
		fallthrough
	case _BINARY_ACK:
		return nil, client.onAck(packet.Id, decoder, packet)
	default:
		message = decoder.Message()
	}
	client.eventsLock.RLock()
	c, ok := client.events[message]
	client.eventsLock.RUnlock()
	if !ok {
		// If the message is not recognized by the server, the decoder.currentCloser
		// needs to be closed otherwise the server will be stuck until the e
		decoder.Close()
		return nil, nil
	}
	args := c.GetArgs()
	olen := len(args)
	if olen > 0 {
		packet.Data = &args
		if err := decoder.DecodeData(packet); err != nil {
			return nil, err
		}
	}
	for i := len(args); i < olen; i++ {
		args = append(args, nil)
	}

	retV := c.Call(args)
	if len(retV) == 0 {
		return nil, nil
	}

	var err error
	if last, ok := retV[len(retV)-1].Interface().(error); ok {
		err = last
		retV = retV[0 : len(retV)-1]
	}
	ret := make([]interface{}, len(retV))
	for i, v := range retV {
		ret[i] = v.Interface()
	}
	return ret, err
}

func (client *Client) onAck(id int, decoder *decoder, packet *packet) error {
	client.eventsLock.RLock()
	c, ok := client.acks[id]
	client.eventsLock.RUnlock()
	if !ok {
		return nil
	}
	delete(client.acks, id)

	args := c.GetArgs()
	packet.Data = &args
	if err := decoder.DecodeData(packet); err != nil {
		return err
	}
	c.Call(args)
	return nil
}

func (client *Client) readLoop() error {
	defer func() {
		p := packet{
			Type: _DISCONNECT,
			Id:   -1,
		}
		client.onPacket(nil, &p)
	}()

	for {
		decoder := newDecoder(client.conn)
		var p packet
		if err := decoder.Decode(&p); err != nil {
			return err
		}
		ret, err := client.onPacket(decoder, &p)
		if err != nil {
			return err
		}
		switch p.Type {
		case _CONNECT:
			client.namespace = p.NSP
			// !!!下面这个不能有，否则会有死循环
			//client.sendConnect()
		case _BINARY_EVENT:
			fallthrough
		case _EVENT:
			if p.Id >= 0 {
				p := packet{
					Type: _ACK,
					Id:   p.Id,
					NSP:  client.namespace,
					Data: ret,
				}
				encoder := newEncoder(client.conn)
				if err := encoder.Encode(p); err != nil {
					return err
				}
			}
		case _DISCONNECT:
			return nil
		}
	}
}
<|endoftext|>