<commit_before>package weedCL

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"

	"io"
)

type Client struct {
	client *http.Client
	Cfg    *HTTPConfig
}

func NewClient(cfg *HTTPConfig) *Client {
	return &Client{
		client: http.DefaultClient,
		Cfg:    cfg,
	}
}

//Upload uploads a file  on weedfs and returns the fid of weedfs and an error if any
//filename is the name of the file
//contentType is the mime type of the file
//body is a reader on the file to upload
func (c *Client) Upload(filename, contentType string, body io.Reader) (string, error) {
	assignRsp, err := c.assign()
	if err != nil {
		return "", err
	}

	mp, contentType, err := createMultiPart(filename, body)
	if err != nil {
		return "", err
	}

	req, err := http.NewRequest("POST", assignRsp.PublicURL, mp)
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-type", contentType)

	resp, err := c.client.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		bResp, err := ioutil.ReadAll(resp.Body)
		defer resp.Body.Close()
		if err != nil {
			return "", err
		}
		return "", fmt.Errorf("error during upload (%s) :%s", resp.StatusCode, string(bResp))
	}
	return assignRsp.Fid, nil
}

//Download make a request on weeds and return a io.ReadCloser
// that contain the file identified by fid or an error if any
func (c *Client) Download(fid string) (io.ReadCloser, error) {
	lookupResp, err := c.lookupFid(fid)
	if err != nil {
		return nil, err
	}
	volURL := ""
	for _, loc := range lookupResp.Locations {
		if loc.PublicURL != "" {
			volURL = loc.PublicURL
			break
		}
	}
	if volURL == "" {
		return nil, fmt.Errorf("no volume url found for that fid")
	}
	resp, err := c.client.Get(fmt.Sprintf("%s/%s", volURL, fid))
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

// AssignResponse is the response for an assign (new file upload) such as
// {"count":1,"fid":"3,01637037d6","url":"127.0.0.1:8080","publicUrl":"localhost:8080"}
type assignRsp struct {
	Count     int    `json:"count"`
	Fid       string `json:"fid"`
	URL       string `json:"url"`
	PublicURL string `json:"publicUrl"`
}

// assign get a new fileID from master
func (c *Client) assign() (*assignRsp, error) {
	u := fmt.Sprintf("%s/dir/assign", c.Cfg.BaseURL.String())
	resp, err := c.client.Get(u)
	if err != nil {
		return nil, err
	}
	assignRsp := &assignRsp{}
	err = json.NewDecoder(resp.Body).Decode(assignRsp)
	return assignRsp, err
}

func createMultiPart(filename string, body io.Reader) (io.Reader, string, error) {
	buff := &bytes.Buffer{}
	mpW := multipart.NewWriter(buff)
	defer mpW.Close()
	filePart, err := mpW.CreateFormFile("file", filename)

	_, err = io.Copy(filePart, body)
	if err != nil {
		return nil, "", err
	}
	return buff, mpW.FormDataContentType(), nil
}

func getVolID(fid string) string {
	var volID string
	if i := strings.Index(fid, ","); i > 0 {
		volID = fid[:i]
	} else {
		volID = fid
	}
	return volID
}

type lookupResp struct {
	Locations []struct {
		PublicURL string `json:"publicUrl"`
		URL       string `json:"url"`
	} `json:"locations"`
}

//lookupFid does a lookup request on weedfs for fid and return a lookupResp or an error if any
func (c *Client) lookupFid(fid string) (*lookupResp, error) {
	volID := getVolID(fid)
	u := fmt.Sprintf("%s/dir/lookup?volumeId=%s", c.Cfg.BaseURL.String(), volID)
	resp, err := c.client.Get(u)
	if err != nil {
		return nil, err
	}
	lookupResp := &lookupResp{}
	if err := json.NewDecoder(resp.Body).Decode(lookupResp); err != nil {
		return nil, err
	}
	return lookupResp, nil
}
<commit_msg>better handling of the url return by weedfs<commit_after>package weedCL

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"

	"io"
)

type Client struct {
	client *http.Client
	Cfg    *HTTPConfig
}

func NewClient(cfg *HTTPConfig) *Client {
	return &Client{
		client: http.DefaultClient,
		Cfg:    cfg,
	}
}

//Upload uploads a file  on weedfs and returns the fid of weedfs and an error if any
//filename is the name of the file
//contentType is the mime type of the file
//body is a reader on the file to upload
func (c *Client) Upload(filename, contentType string, body io.Reader) (string, error) {
	assignRsp, err := c.assign()
	if err != nil {
		return "", err
	}

	mp, contentType, err := createMultiPart(filename, body)
	if err != nil {
		return "", err
	}

	req, err := http.NewRequest("POST", assignRsp.PutURL(), mp)
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-type", contentType)

	resp, err := c.client.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		bResp, err := ioutil.ReadAll(resp.Body)
		defer resp.Body.Close()
		if err != nil {
			return "", err
		}
		return "", fmt.Errorf("error during upload (%s) :%s", resp.StatusCode, string(bResp))
	}
	return assignRsp.Fid, nil
}

//Download make a request on weeds and return a io.ReadCloser
// that contain the file identified by fid or an error if any
func (c *Client) Download(fid string) (io.ReadCloser, error) {
	lookupResp, err := c.lookupFid(fid)
	if err != nil {
		return nil, err
	}
	volURL := ""
	for _, loc := range lookupResp.Locations {
		if loc.PublicURL != "" {
			volURL = loc.GetURL(fid)
			break
		}
	}
	if volURL == "" {
		return nil, fmt.Errorf("no volume url found for that fid")
	}
	resp, err := c.client.Get(volURL)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

// AssignResponse is the response for an assign (new file upload) such as
// {"count":1,"fid":"3,01637037d6","url":"127.0.0.1:8080","publicUrl":"localhost:8080"}
type assignRsp struct {
	Count     int    `json:"count"`
	Fid       string `json:"fid"`
	URL       string `json:"url"`
	PublicURL string `json:"publicUrl"`
}

func (a *assignRsp) PutURL() string {
	// TODO need to handle scheme
	out := fmt.Sprintf("%s/%s", a.URL, a.Fid)
	if !strings.HasPrefix(a.URL, "http://") {
		out = fmt.Sprintf("http://%s", out)
	}
	return out
}

// assign get a new fileID from master
func (c *Client) assign() (*assignRsp, error) {
	u := fmt.Sprintf("%s/dir/assign", c.Cfg.BaseURL.String())
	resp, err := c.client.Get(u)
	if err != nil {
		return nil, err
	}
	assignRsp := &assignRsp{}
	err = json.NewDecoder(resp.Body).Decode(assignRsp)
	return assignRsp, err
}

func createMultiPart(filename string, body io.Reader) (io.Reader, string, error) {
	buff := &bytes.Buffer{}
	mpW := multipart.NewWriter(buff)
	defer mpW.Close()
	filePart, err := mpW.CreateFormFile("file", filename)

	_, err = io.Copy(filePart, body)
	if err != nil {
		return nil, "", err
	}
	return buff, mpW.FormDataContentType(), nil
}

func getVolID(fid string) string {
	var volID string
	if i := strings.Index(fid, ","); i > 0 {
		volID = fid[:i]
	} else {
		volID = fid
	}
	return volID
}

type location struct {
	PublicURL string `json:"publicUrl"`
	URL       string `json:"url"`
}

func (l location) GetURL(fid string) string {
	// TODO need to handle scheme
	out := fmt.Sprintf("%s/%s", l.URL, fid)
	if !strings.HasPrefix(l.URL, "http://") {
		out = fmt.Sprintf("http://%s", out)
	}
	return out
}

type lookupResp struct {
	Locations []location `json:"locations"`
}

//lookupFid does a lookup request on weedfs for fid and return a lookupResp or an error if any
func (c *Client) lookupFid(fid string) (*lookupResp, error) {
	volID := getVolID(fid)
	u := fmt.Sprintf("%s/dir/lookup?volumeId=%s", c.Cfg.BaseURL.String(), volID)
	resp, err := c.client.Get(u)
	if err != nil {
		return nil, err
	}
	lookupResp := &lookupResp{}
	if err := json.NewDecoder(resp.Body).Decode(lookupResp); err != nil {
		return nil, err
	}
	return lookupResp, nil
}
<|endoftext|>


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

// HTTP file system request handler

package http

import (
	"fmt";
	"io";
	"os";
	"path";
	"strings";
	"utf8";
)

// TODO this should be in a mime package somewhere
var contentByExt = map[string]string{
	".css": "text/css",
	".gif": "image/gif",
	".html": "text/html; charset=utf-8",
	".jpg": "image/jpeg",
	".js": "application/x-javascript",
	".pdf": "application/pdf",
	".png": "image/png",
}

// Heuristic: b is text if it is valid UTF-8 and doesn't
// contain any unprintable ASCII or Unicode characters.
func isText(b []byte) bool {
	for len(b) > 0 && utf8.FullRune(b) {
		rune, size := utf8.DecodeRune(b);
		if size == 1 && rune == utf8.RuneError {
			// decoding error
			return false
		}
		if 0x80 <= rune && rune <= 0x9F {
			return false
		}
		if rune < ' ' {
			switch rune {
			case '\n', '\r', '\t':
				// okay
			default:
				// binary garbage
				return false
			}
		}
		b = b[size:];
	}
	return true;
}

func dirList(c *Conn, f *os.File) {
	fmt.Fprintf(c, "
\n");
	for {
		dirs, err := f.Readdir(100);
		if err != nil || len(dirs) == 0 {
			break
		}
		for _, d := range dirs {
			name := d.Name;
			if d.IsDirectory() {
				name += "/"
			}
			// TODO htmlescape
			fmt.Fprintf(c, "%s\n", name, name);
		}
	}
	fmt.Fprintf(c, "
\n");
}

func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
	const indexPage = "/index.html";

	// redirect to strip off any index.html
	n := len(name) - len(indexPage);
	if n >= 0 && name[n:] == indexPage {
		Redirect(c, name[0:n+1], StatusMovedPermanently);
		return;
	}

	f, err := os.Open(name, os.O_RDONLY, 0);
	if err != nil {
		// TODO expose actual error?
		NotFound(c, r);
		return;
	}
	defer f.Close();

	d, err1 := f.Stat();
	if err1 != nil {
		// TODO expose actual error?
		NotFound(c, r);
		return;
	}

	if redirect {
		// redirect to canonical path: / at end of directory url
		// r.URL.Path always begins with /
		url := r.URL.Path;
		if d.IsDirectory() {
			if url[len(url)-1] != '/' {
				Redirect(c, url+"/", StatusMovedPermanently);
				return;
			}
		} else {
			if url[len(url)-1] == '/' {
				Redirect(c, url[0:len(url)-1], StatusMovedPermanently);
				return;
			}
		}
	}

	// use contents of index.html for directory, if present
	if d.IsDirectory() {
		index := name + indexPage;
		ff, err := os.Open(index, os.O_RDONLY, 0);
		if err == nil {
			defer ff.Close();
			dd, err := ff.Stat();
			if err == nil {
				name = index;
				d = dd;
				f = ff;
			}
		}
	}

	if d.IsDirectory() {
		dirList(c, f);
		return;
	}

	// serve file
	// use extension to find content type.
	ext := path.Ext(name);
	if ctype, ok := contentByExt[ext]; ok {
		c.SetHeader("Content-Type", ctype)
	} else {
		// read first chunk to decide between utf-8 text and binary
		var buf [1024]byte;
		n, _ := io.ReadFull(f, &buf);
		b := buf[0:n];
		if isText(b) {
			c.SetHeader("Content-Type", "text-plain; charset=utf-8")
		} else {
			c.SetHeader("Content-Type", "application/octet-stream")	// generic binary
		}
		c.Write(b);
	}
	io.Copy(c, f);
}

// ServeFile replies to the request with the contents of the named file or directory.
func ServeFile(c *Conn, r *Request, name string) {
	serveFileInternal(c, r, name, false)
}

type fileHandler struct {
	root	string;
	prefix	string;
}

// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
// It strips prefix from the incoming requests before
// looking up the file name in the file system.
func FileServer(root, prefix string) Handler	{ return &fileHandler{root, prefix} }

func (f *fileHandler) ServeHTTP(c *Conn, r *Request) {
	path := r.URL.Path;
	if !strings.HasPrefix(path, f.prefix) {
		NotFound(c, r);
		return;
	}
	path = path[len(f.prefix):];
	serveFileInternal(c, r, f.root+"/"+path, true);
}
<commit_msg>http: redirect to correct URL<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// HTTP file system request handler

package http

import (
	"fmt";
	"io";
	"os";
	"path";
	"strings";
	"utf8";
)

// TODO this should be in a mime package somewhere
var contentByExt = map[string]string{
	".css": "text/css",
	".gif": "image/gif",
	".html": "text/html; charset=utf-8",
	".jpg": "image/jpeg",
	".js": "application/x-javascript",
	".pdf": "application/pdf",
	".png": "image/png",
}

// Heuristic: b is text if it is valid UTF-8 and doesn't
// contain any unprintable ASCII or Unicode characters.
func isText(b []byte) bool {
	for len(b) > 0 && utf8.FullRune(b) {
		rune, size := utf8.DecodeRune(b);
		if size == 1 && rune == utf8.RuneError {
			// decoding error
			return false
		}
		if 0x80 <= rune && rune <= 0x9F {
			return false
		}
		if rune < ' ' {
			switch rune {
			case '\n', '\r', '\t':
				// okay
			default:
				// binary garbage
				return false
			}
		}
		b = b[size:];
	}
	return true;
}

func dirList(c *Conn, f *os.File) {
	fmt.Fprintf(c, "
\n");
	for {
		dirs, err := f.Readdir(100);
		if err != nil || len(dirs) == 0 {
			break
		}
		for _, d := range dirs {
			name := d.Name;
			if d.IsDirectory() {
				name += "/"
			}
			// TODO htmlescape
			fmt.Fprintf(c, "%s\n", name, name);
		}
	}
	fmt.Fprintf(c, "
\n");
}

func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
	const indexPage = "/index.html";

	// redirect .../index.html to .../
	if strings.HasSuffix(r.URL.Path, indexPage) {
		Redirect(c, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently);
		return;
	}

	f, err := os.Open(name, os.O_RDONLY, 0);
	if err != nil {
		// TODO expose actual error?
		NotFound(c, r);
		return;
	}
	defer f.Close();

	d, err1 := f.Stat();
	if err1 != nil {
		// TODO expose actual error?
		NotFound(c, r);
		return;
	}

	if redirect {
		// redirect to canonical path: / at end of directory url
		// r.URL.Path always begins with /
		url := r.URL.Path;
		if d.IsDirectory() {
			if url[len(url)-1] != '/' {
				Redirect(c, url+"/", StatusMovedPermanently);
				return;
			}
		} else {
			if url[len(url)-1] == '/' {
				Redirect(c, url[0:len(url)-1], StatusMovedPermanently);
				return;
			}
		}
	}

	// use contents of index.html for directory, if present
	if d.IsDirectory() {
		index := name + indexPage;
		ff, err := os.Open(index, os.O_RDONLY, 0);
		if err == nil {
			defer ff.Close();
			dd, err := ff.Stat();
			if err == nil {
				name = index;
				d = dd;
				f = ff;
			}
		}
	}

	if d.IsDirectory() {
		dirList(c, f);
		return;
	}

	// serve file
	// use extension to find content type.
	ext := path.Ext(name);
	if ctype, ok := contentByExt[ext]; ok {
		c.SetHeader("Content-Type", ctype)
	} else {
		// read first chunk to decide between utf-8 text and binary
		var buf [1024]byte;
		n, _ := io.ReadFull(f, &buf);
		b := buf[0:n];
		if isText(b) {
			c.SetHeader("Content-Type", "text-plain; charset=utf-8")
		} else {
			c.SetHeader("Content-Type", "application/octet-stream")	// generic binary
		}
		c.Write(b);
	}
	io.Copy(c, f);
}

// ServeFile replies to the request with the contents of the named file or directory.
func ServeFile(c *Conn, r *Request, name string) {
	serveFileInternal(c, r, name, false)
}

type fileHandler struct {
	root	string;
	prefix	string;
}

// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
// It strips prefix from the incoming requests before
// looking up the file name in the file system.
func FileServer(root, prefix string) Handler	{ return &fileHandler{root, prefix} }

func (f *fileHandler) ServeHTTP(c *Conn, r *Request) {
	path := r.URL.Path;
	if !strings.HasPrefix(path, f.prefix) {
		NotFound(c, r);
		return;
	}
	path = path[len(f.prefix):];
	serveFileInternal(c, r, f.root+"/"+path, true);
}
<|endoftext|>


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

// Pipe adapter to connect code expecting an io.Read
// with code expecting an io.Write.

package io

import (
	"os"
	"sync"
)

type pipeReturn struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	rclosed bool            // Read end closed?
	rerr    os.Error        // Error supplied to CloseReader
	wclosed bool            // Write end closed?
	werr    os.Error        // Error supplied to CloseWriter
	wpend   []byte          // Written data waiting to be read.
	wtot    int             // Bytes consumed so far in current write.
	cr      chan []byte     // Write sends data here...
	cw      chan pipeReturn // ... and reads the n, err back from here.
}

func (p *pipe) Read(data []byte) (n int, err os.Error) {
	if p == nil || p.rclosed {
		return 0, os.EINVAL
	}

	// Wait for next write block if necessary.
	if p.wpend == nil {
		if !p.wclosed {
			p.wpend = <-p.cr
		}
		if p.wclosed {
			return 0, p.werr
		}
		p.wtot = 0
	}

	// Read from current write block.
	n = len(data)
	if n > len(p.wpend) {
		n = len(p.wpend)
	}
	for i := 0; i < n; i++ {
		data[i] = p.wpend[i]
	}
	p.wtot += n
	p.wpend = p.wpend[n:]

	// If write block is done, finish the write.
	if len(p.wpend) == 0 {
		p.wpend = nil
		p.cw <- pipeReturn{p.wtot, nil}
		p.wtot = 0
	}

	return n, nil
}

func (p *pipe) Write(data []byte) (n int, err os.Error) {
	if p == nil || p.wclosed {
		return 0, os.EINVAL
	}
	if p.rclosed {
		return 0, p.rerr
	}

	// Send data to reader.
	p.cr <- data

	// Wait for reader to finish copying it.
	res := <-p.cw
	return res.n, res.err
}

func (p *pipe) CloseReader(rerr os.Error) os.Error {
	if p == nil || p.rclosed {
		return os.EINVAL
	}

	// Stop any future writes.
	p.rclosed = true
	if rerr == nil {
		rerr = os.EPIPE
	}
	p.rerr = rerr

	// Stop the current write.
	if !p.wclosed {
		p.cw <- pipeReturn{p.wtot, rerr}
	}

	return nil
}

func (p *pipe) CloseWriter(werr os.Error) os.Error {
	if werr == nil {
		werr = os.EOF
	}
	if p == nil || p.wclosed {
		return os.EINVAL
	}

	// Stop any future reads.
	p.wclosed = true
	p.werr = werr

	// Stop the current read.
	if !p.rclosed {
		p.cr <- nil
	}

	return nil
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finisher can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	lock sync.Mutex
	p    *pipe
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.Read(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.CloseReader(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error rerr.
func (r *PipeReader) CloseWithError(rerr os.Error) os.Error {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.CloseReader(rerr)
}

func (r *PipeReader) finish() { r.Close() }

// Write half of pipe.
type PipeWriter struct {
	lock sync.Mutex
	p    *pipe
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.Write(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and a nil error.
func (w *PipeWriter) Close() os.Error {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.CloseWriter(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error werr.
func (w *PipeWriter) CloseWithError(werr os.Error) os.Error {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.CloseWriter(werr)
}

func (w *PipeWriter) finish() { w.Close() }

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := new(pipe)
	p.cr = make(chan []byte, 1)
	p.cw = make(chan pipeReturn, 1)
	r := new(PipeReader)
	r.p = p
	w := new(PipeWriter)
	w.p = p
	return r, w
}
<commit_msg>io: revised Pipe implementation<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"sync"
)

// Shared pipe structure.
type pipe struct {
	rclosed bool        // Read end closed?
	rerr    os.Error    // Error supplied to CloseReader
	wclosed bool        // Write end closed?
	werr    os.Error    // Error supplied to CloseWriter
	wpend   []byte      // Written data waiting to be read.
	wtot    int         // Bytes consumed so far in current write.
	cw      chan []byte // Write sends data here...
	cr      chan bool   // ... and reads a done notification from here.
}

func (p *pipe) Read(data []byte) (n int, err os.Error) {
	if p.rclosed {
		return 0, os.EINVAL
	}

	// Wait for next write block if necessary.
	if p.wpend == nil {
		if !closed(p.cw) {
			p.wpend = <-p.cw
		}
		if closed(p.cw) {
			return 0, p.werr
		}
		p.wtot = 0
	}

	// Read from current write block.
	n = copy(data, p.wpend)
	p.wtot += n
	p.wpend = p.wpend[n:]

	// If write block is done, finish the write.
	if len(p.wpend) == 0 {
		p.wpend = nil
		p.cr <- true
		p.wtot = 0
	}

	return n, nil
}

func (p *pipe) Write(data []byte) (n int, err os.Error) {
	if p.wclosed {
		return 0, os.EINVAL
	}
	if closed(p.cr) {
		return 0, p.rerr
	}

	// Send write to reader.
	p.cw <- data

	// Wait for reader to finish copying it.
	<-p.cr
	if closed(p.cr) {
		_, _ = <-p.cw // undo send if reader is gone
		return 0, p.rerr
	}
	return len(data), nil
}

func (p *pipe) CloseReader(rerr os.Error) os.Error {
	if p.rclosed {
		return os.EINVAL
	}
	p.rclosed = true

	// Wake up writes.
	if rerr == nil {
		rerr = os.EPIPE
	}
	p.rerr = rerr
	close(p.cr)
	return nil
}

func (p *pipe) CloseWriter(werr os.Error) os.Error {
	if p.wclosed {
		return os.EINVAL
	}
	p.wclosed = true

	// Wake up reads.
	if werr == nil {
		werr = os.EOF
	}
	p.werr = werr
	close(p.cw)
	return nil
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finisher can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	lock sync.Mutex
	p    *pipe
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.Read(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.CloseReader(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error rerr.
func (r *PipeReader) CloseWithError(rerr os.Error) os.Error {
	r.lock.Lock()
	defer r.lock.Unlock()

	return r.p.CloseReader(rerr)
}

func (r *PipeReader) finish() { r.Close() }

// Write half of pipe.
type PipeWriter struct {
	lock sync.Mutex
	p    *pipe
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.Write(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and a nil error.
func (w *PipeWriter) Close() os.Error {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.CloseWriter(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error werr.
func (w *PipeWriter) CloseWithError(werr os.Error) os.Error {
	w.lock.Lock()
	defer w.lock.Unlock()

	return w.p.CloseWriter(werr)
}

func (w *PipeWriter) finish() { w.Close() }

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		cw: make(chan []byte, 1),
		cr: make(chan bool, 1),
	}
	return &PipeReader{p: p}, &PipeWriter{p: p}
}
<|endoftext|>


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

// Rudimentary logging package. Defines a type, Logger, with simple
// methods for formatting output to one or two destinations. Also has
// predefined Loggers accessible through helper functions Stdout[f],
// Stderr[f], Exit[f], and Crash[f], which are easier to use than creating
// a Logger manually.
// Exit exits when written to.
// Crash causes a crash when written to.
package log

import (
	"fmt";
	"io";
	"runtime";
	"os";
	"time";
)

// These flags define the properties of the Logger and the output they produce.
const (
	// Flags
	Lok = iota;
	Lexit;	// terminate execution when written
	Lcrash;	// crash (panic) when written
	// Bits or'ed together to control what's printed. There is no control over the
	// order they appear (the order listed here) or the format they present (as
	// described in the comments).  A colon appears after these items:
	//	2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate = 1 << iota;	// the date: 2009/0123
	Ltime;	// the time: 01:23:23
	Lmicroseconds;	// microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile;	// full file name and line number: /a/b/c/d.go:23
	Lshortfile;	// final file name element and line number: d.go:23. overrides Llongfile
	lAllBits = Ldate | Ltime | Lmicroseconds | Llongfile | Lshortfile;
)

// Logger represents an active logging object.
type Logger struct {
	out0	io.Writer;	// first destination for output
	out1	io.Writer;	// second destination for output; may be nil
	prefix string;	// prefix to write at beginning of each line
	flag int;	// properties
}

// New creates a new Logger.   The out0 and out1 variables set the
// destinations to which log data will be written; out1 may be nil.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out0, out1 io.Writer, prefix string, flag int) *Logger {
	return &Logger{out0, out1, prefix, flag}
}

var (
	stdout = New(os.Stdout, nil, "", Lok|Ldate|Ltime);
	stderr = New(os.Stderr, nil, "", Lok|Ldate|Ltime);
	exit = New(os.Stderr, nil, "", Lexit|Ldate|Ltime);
	crash = New(os.Stderr, nil, "", Lcrash|Ldate|Ltime);
)

var shortnames = make(map[string] string)	// cache of short names to avoid allocation.

// Cheap integer to fixed-width decimal ASCII.  Use a negative width to avoid zero-padding
func itoa(i int, wid int) string {
	var u uint = uint(i);
	if u == 0 && wid <= 1 {
		return "0"
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0 || wid > 0; u /= 10 {
		bp--;
		wid--;
		b[bp] = byte(u%10) + '0';
	}

	return string(b[bp:len(b)])
}

func (l *Logger) formatHeader(ns int64, calldepth int) string {
	h := l.prefix;
	if l.flag & (Ldate | Ltime | Lmicroseconds) != 0 {
		t := time.SecondsToLocalTime(ns/1e9);
		if l.flag & (Ldate) != 0 {
			h += itoa(int(t.Year), 4) + "/" + itoa(t.Month, 2) + itoa(t.Day, 2) + " "
		}
		if l.flag & (Ltime | Lmicroseconds) != 0 {
			h += itoa(t.Hour, 2) + ":" + itoa(t.Minute, 2) + ":" + itoa(t.Second, 2);
			if l.flag & Lmicroseconds != 0 {
				h += "." + itoa(int(ns % 1e9)/1e3, 6);
			}
			h += " ";
		}
	}
	if l.flag & (Lshortfile | Llongfile) != 0 {
		pc, file, line, ok := runtime.Caller(calldepth);
		if ok {
			if l.flag & Lshortfile != 0 {
				short, ok := shortnames[file];
				if !ok {
					short = file;
					for i := len(file) - 1; i > 0; i-- {
						if file[i] == '/' {
							short = file[i+1:len(file)];
							break;
						}
					}
					shortnames[file] = short;
				}
				file = short;
			}
		} else {
			file = "???";
			line = 0;
		}
		h += file + ":" + itoa(line, -1) + ": ";
	}
	return h;
}

// Output writes the output for a logging event.  The string s contains the text to print after
// the time stamp;  calldepth is used to recover the PC.  It is provided for generality, although
// at the moment on all pre-defined paths it will be 2.
func (l *Logger) Output(calldepth int, s string) {
	now := time.Nanoseconds();	// get this early.
	newline := "\n";
	if len(s) > 0 && s[len(s)-1] == '\n' {
		newline = ""
	}
	s = l.formatHeader(now, calldepth+1) + s + newline;
	io.WriteString(l.out0, s);
	if l.out1 != nil {
		io.WriteString(l.out1, s);
	}
	switch l.flag & ^lAllBits {
	case Lcrash:
		panic("log: fatal error");
	case Lexit:
		os.Exit(1);
	}
}

// Logf is analogous to Printf() for a Logger.
func (l *Logger) Logf(format string, v ...) {
	l.Output(2, fmt.Sprintf(format, v))
}

// Log is analogouts to Print() for a Logger.
func (l *Logger) Log(v ...) {
	l.Output(2, fmt.Sprintln(v))
}

// Stdout is a helper function for easy logging to stdout. It is analogous to Print().
func Stdout(v ...) {
	stdout.Output(2, fmt.Sprint(v))
}

// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr).
func Stderr(v ...) {
	stderr.Output(2, fmt.Sprintln(v))
}

// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf().
func Stdoutf(format string, v ...) {
	stdout.Output(2, fmt.Sprintf(format, v))
}

// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr).
func Stderrf(format string, v ...) {
	stderr.Output(2, fmt.Sprintf(format, v))
}

// Exit is equivalent to Stderr() followed by a call to os.Exit(1).
func Exit(v ...) {
	exit.Output(2, fmt.Sprintln(v))
}

// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1).
func Exitf(format string, v ...) {
	exit.Output(2, fmt.Sprintf(format, v))
}

// Crash is equivalent to Stderrf() followed by a call to panic().
func Crash(v ...) {
	crash.Output(2, fmt.Sprintln(v))
}

// Crashf is equivalent to Stderrf() followed by a call to panic().
func Crashf(format string, v ...) {
	crash.Output(2, fmt.Sprintf(format, v))
}
<commit_msg>fix typo<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Rudimentary logging package. Defines a type, Logger, with simple
// methods for formatting output to one or two destinations. Also has
// predefined Loggers accessible through helper functions Stdout[f],
// Stderr[f], Exit[f], and Crash[f], which are easier to use than creating
// a Logger manually.
// Exit exits when written to.
// Crash causes a crash when written to.
package log

import (
	"fmt";
	"io";
	"runtime";
	"os";
	"time";
)

// These flags define the properties of the Logger and the output they produce.
const (
	// Flags
	Lok = iota;
	Lexit;	// terminate execution when written
	Lcrash;	// crash (panic) when written
	// Bits or'ed together to control what's printed. There is no control over the
	// order they appear (the order listed here) or the format they present (as
	// described in the comments).  A colon appears after these items:
	//	2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate = 1 << iota;	// the date: 2009/0123
	Ltime;	// the time: 01:23:23
	Lmicroseconds;	// microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile;	// full file name and line number: /a/b/c/d.go:23
	Lshortfile;	// final file name element and line number: d.go:23. overrides Llongfile
	lAllBits = Ldate | Ltime | Lmicroseconds | Llongfile | Lshortfile;
)

// Logger represents an active logging object.
type Logger struct {
	out0	io.Writer;	// first destination for output
	out1	io.Writer;	// second destination for output; may be nil
	prefix string;	// prefix to write at beginning of each line
	flag int;	// properties
}

// New creates a new Logger.   The out0 and out1 variables set the
// destinations to which log data will be written; out1 may be nil.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out0, out1 io.Writer, prefix string, flag int) *Logger {
	return &Logger{out0, out1, prefix, flag}
}

var (
	stdout = New(os.Stdout, nil, "", Lok|Ldate|Ltime);
	stderr = New(os.Stderr, nil, "", Lok|Ldate|Ltime);
	exit = New(os.Stderr, nil, "", Lexit|Ldate|Ltime);
	crash = New(os.Stderr, nil, "", Lcrash|Ldate|Ltime);
)

var shortnames = make(map[string] string)	// cache of short names to avoid allocation.

// Cheap integer to fixed-width decimal ASCII.  Use a negative width to avoid zero-padding
func itoa(i int, wid int) string {
	var u uint = uint(i);
	if u == 0 && wid <= 1 {
		return "0"
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0 || wid > 0; u /= 10 {
		bp--;
		wid--;
		b[bp] = byte(u%10) + '0';
	}

	return string(b[bp:len(b)])
}

func (l *Logger) formatHeader(ns int64, calldepth int) string {
	h := l.prefix;
	if l.flag & (Ldate | Ltime | Lmicroseconds) != 0 {
		t := time.SecondsToLocalTime(ns/1e9);
		if l.flag & (Ldate) != 0 {
			h += itoa(int(t.Year), 4) + "/" + itoa(t.Month, 2) + itoa(t.Day, 2) + " "
		}
		if l.flag & (Ltime | Lmicroseconds) != 0 {
			h += itoa(t.Hour, 2) + ":" + itoa(t.Minute, 2) + ":" + itoa(t.Second, 2);
			if l.flag & Lmicroseconds != 0 {
				h += "." + itoa(int(ns % 1e9)/1e3, 6);
			}
			h += " ";
		}
	}
	if l.flag & (Lshortfile | Llongfile) != 0 {
		pc, file, line, ok := runtime.Caller(calldepth);
		if ok {
			if l.flag & Lshortfile != 0 {
				short, ok := shortnames[file];
				if !ok {
					short = file;
					for i := len(file) - 1; i > 0; i-- {
						if file[i] == '/' {
							short = file[i+1:len(file)];
							break;
						}
					}
					shortnames[file] = short;
				}
				file = short;
			}
		} else {
			file = "???";
			line = 0;
		}
		h += file + ":" + itoa(line, -1) + ": ";
	}
	return h;
}

// Output writes the output for a logging event.  The string s contains the text to print after
// the time stamp;  calldepth is used to recover the PC.  It is provided for generality, although
// at the moment on all pre-defined paths it will be 2.
func (l *Logger) Output(calldepth int, s string) {
	now := time.Nanoseconds();	// get this early.
	newline := "\n";
	if len(s) > 0 && s[len(s)-1] == '\n' {
		newline = ""
	}
	s = l.formatHeader(now, calldepth+1) + s + newline;
	io.WriteString(l.out0, s);
	if l.out1 != nil {
		io.WriteString(l.out1, s);
	}
	switch l.flag & ^lAllBits {
	case Lcrash:
		panic("log: fatal error");
	case Lexit:
		os.Exit(1);
	}
}

// Logf is analogous to Printf() for a Logger.
func (l *Logger) Logf(format string, v ...) {
	l.Output(2, fmt.Sprintf(format, v))
}

// Log is analogouts to Print() for a Logger.
func (l *Logger) Log(v ...) {
	l.Output(2, fmt.Sprintln(v))
}

// Stdout is a helper function for easy logging to stdout. It is analogous to Print().
func Stdout(v ...) {
	stdout.Output(2, fmt.Sprint(v))
}

// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr).
func Stderr(v ...) {
	stderr.Output(2, fmt.Sprintln(v))
}

// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf().
func Stdoutf(format string, v ...) {
	stdout.Output(2, fmt.Sprintf(format, v))
}

// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr).
func Stderrf(format string, v ...) {
	stderr.Output(2, fmt.Sprintf(format, v))
}

// Exit is equivalent to Stderr() followed by a call to os.Exit(1).
func Exit(v ...) {
	exit.Output(2, fmt.Sprintln(v))
}

// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1).
func Exitf(format string, v ...) {
	exit.Output(2, fmt.Sprintf(format, v))
}

// Crash is equivalent to Stderr() followed by a call to panic().
func Crash(v ...) {
	crash.Output(2, fmt.Sprintln(v))
}

// Crashf is equivalent to Stderrf() followed by a call to panic().
func Crashf(format string, v ...) {
	crash.Output(2, fmt.Sprintf(format, v))
}
<|endoftext|>


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

// The net package provides a portable interface to Unix
// networks sockets, including TCP/IP, UDP, domain name
// resolution, and Unix domain sockets.
package net

// TODO(rsc):
//	support for raw ethernet sockets

import "os"

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetTimeout and SetReadTimeout.
	Read(b []byte) (n int, err os.Error)

	// Write writes data to the connection.
	// Write can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetTimeout and SetWriteTimeout.
	Write(b []byte) (n int, err os.Error)

	// Close closes the connection.
	// The error returned is an os.Error to satisfy io.Closer;
	Close() os.Error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetTimeout sets the read and write deadlines associated
	// with the connection.
	SetTimeout(nsec int64) os.Error

	// SetReadTimeout sets the time (in nanoseconds) that
	// Read will wait for data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	SetReadTimeout(nsec int64) os.Error

	// SetWriteTimeout sets the time (in nanoseconds) that
	// Write will wait to send its data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteTimeout(nsec int64) os.Error
}

// An Error represents a network error.
type Error interface {
	os.Error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetTimeout and SetReadTimeout.
	ReadFrom(b []byte) (n int, addr Addr, err os.Error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetTimeout and SetWriteTimeout.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err os.Error)

	// Close closes the connection.
	// The error returned is an os.Error to satisfy io.Closer;
	Close() os.Error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetTimeout sets the read and write deadlines associated
	// with the connection.
	SetTimeout(nsec int64) os.Error

	// SetReadTimeout sets the time (in nanoseconds) that
	// Read will wait for data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	SetReadTimeout(nsec int64) os.Error

	// SetWriteTimeout sets the time (in nanoseconds) that
	// Write will wait to send its data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteTimeout(nsec int64) os.Error
}

// A Listener is a generic network listener for stream-oriented protocols.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err os.Error)

	// Close closes the listener.
	// The error returned is an os.Error to satisfy io.Closer;
	Close() os.Error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = os.ErrorString("missing address")

type OpError struct {
	Op    string
	Net   string
	Addr  Addr
	Error os.Error
}

func (e *OpError) String() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Error.String()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Error.(temporary)
	return ok && t.Temporary()
}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Error.(timeout)
	return ok && t.Timeout()
}

type AddrError struct {
	Error string
	Addr  string
}

func (e *AddrError) String() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Error
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) String() string  { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }
<commit_msg>net: remove comment fragments<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The net package provides a portable interface to Unix
// networks sockets, including TCP/IP, UDP, domain name
// resolution, and Unix domain sockets.
package net

// TODO(rsc):
//	support for raw ethernet sockets

import "os"

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetTimeout and SetReadTimeout.
	Read(b []byte) (n int, err os.Error)

	// Write writes data to the connection.
	// Write can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetTimeout and SetWriteTimeout.
	Write(b []byte) (n int, err os.Error)

	// Close closes the connection.
	Close() os.Error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetTimeout sets the read and write deadlines associated
	// with the connection.
	SetTimeout(nsec int64) os.Error

	// SetReadTimeout sets the time (in nanoseconds) that
	// Read will wait for data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	SetReadTimeout(nsec int64) os.Error

	// SetWriteTimeout sets the time (in nanoseconds) that
	// Write will wait to send its data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteTimeout(nsec int64) os.Error
}

// An Error represents a network error.
type Error interface {
	os.Error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetTimeout and SetReadTimeout.
	ReadFrom(b []byte) (n int, addr Addr, err os.Error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetTimeout and SetWriteTimeout.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err os.Error)

	// Close closes the connection.
	Close() os.Error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetTimeout sets the read and write deadlines associated
	// with the connection.
	SetTimeout(nsec int64) os.Error

	// SetReadTimeout sets the time (in nanoseconds) that
	// Read will wait for data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	SetReadTimeout(nsec int64) os.Error

	// SetWriteTimeout sets the time (in nanoseconds) that
	// Write will wait to send its data before returning an error with Timeout() == true.
	// Setting nsec == 0 (the default) disables the deadline.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteTimeout(nsec int64) os.Error
}

// A Listener is a generic network listener for stream-oriented protocols.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err os.Error)

	// Close closes the listener.
	Close() os.Error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = os.ErrorString("missing address")

type OpError struct {
	Op    string
	Net   string
	Addr  Addr
	Error os.Error
}

func (e *OpError) String() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Error.String()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Error.(temporary)
	return ok && t.Temporary()
}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Error.(timeout)
	return ok && t.Timeout()
}

type AddrError struct {
	Error string
	Addr  string
}

func (e *AddrError) String() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Error
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) String() string  { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }
<|endoftext|>


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

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value
		%%	a literal percent sign; consumes no value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%q	a single-quoted character literal safely escaped with Go syntax.
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%04X"
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power of two,
			in the manner of strconv.FormatFloat with the 'b' format,
			e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	Width is specified by an optional decimal number immediately following the verb.
	If absent, the width is whatever is necessary to represent the value.
	Precision is specified after the (optional) width by a period followed by a
	decimal number. If no period is present, a default precision is used.
	A period with no following number specifies a precision of zero.
	Examples:
		%f:    default width, default precision
		%9f    width 9, default precision
		%.2f   default width, precision 2
		%9.2f  width 9, precision 2
		%9.f   width 9, precision 0

	Width and precision are measured in units of Unicode code points.
	(This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For most values, width is the minimum number of characters to output,
	padding the formatted form with spaces if necessary.
	For strings, precision is the maximum number of characters to output,
	truncating if necessary.

	For floating-point values, width sets the minimum width of the field and
	precision sets the number of places after the decimal, if appropriate,
	except that for %g/%G it sets the total number of digits. For example,
	given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
	The default precision for %e and %f is 6; for %g it is the smallest
	number of digits necessary to identify the value uniquely.

	For complex numbers, the width and precision apply to the two
	components independently and the result is parenthsized, so %f applied
	to 1.2+3.4i produces (1.200000+3.400000i).

	Other flags:
		+	always print a sign for numeric values;
			guarantee ASCII-only output for %q (%+q)
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			for %q, print a raw (backquoted) string if strconv.CanBackquote
			returns true;
			write e.g. U+0078 'x' if the character is printable for %U (%#U).
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces;
			for numbers, this moves the padding after the sign

	Flags are ignored by verbs that do not expect them.
	For example there is no alternate decimal format, so %#d and %d
	behave identically.

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If the format (which is implicitly %v for Println etc.) is valid
	for a string (%s %q %v %x %X), the following two rules also apply:

	1. If an operand implements the error interface, the Error method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any).

	2. If an operand implements method String() string, that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any).

	To avoid recursion in cases such as
		type X string
		func (x X) String() string { return Sprintf("<%s>", x) }
	convert the value before recurring:
		func (x X) String() string { return Sprintf("<%s>", string(x)) }

	Explicit argument indexes:

	In Printf, Sprintf, and Fprintf, the default behavior is for each
	formatting verb to format successive arguments passed in the call.
	However, the notation [n] immediately before the verb indicates that the
	nth one-indexed argument is to be formatted instead. The same notation
	before a '*' for a width or precision selects the argument index holding
	the value. After processing a bracketed expression [n], arguments n+1,
	n+2, etc. will be processed unless otherwise directed.

	For example,
		fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
	will yield "22, 11", while
		fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),
	equivalent to
		fmt.Sprintf("%6.2f", 12.0),
	will yield " 12.00". Because an explicit index affects subsequent verbs,
	this notation can be used to print the same values multiple times
	by resetting the index for the first argument to be repeated:
		fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
	will yield "16 17 0x10 0x11".

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
		Invalid or invalid use of argument index: %!(BADINDEX)
			Printf("%*[2]d", 7):       %!d(BADINDEX)
			Printf("%.[2]d", 7):       %!d(BADINDEX)

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	If an Error or String method triggers a panic when called by a
	print routine, the fmt package reformats the error message
	from the panic, decorating it with an indication that it came
	through the fmt package.  For example, if a String method
	calls panic("bad"), the resulting formatted message will look
	like
		%!s(PANIC=bad)

	The %!s just shows the print verb in use when the failure
	occurred.

	Scanning

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified io.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Scanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Scanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

		%p is not implemented
		%T is not implemented
		%e %E %f %F %g %G are all equivalent and scan any floating point or complex value
		%s and %v on strings scan a space-delimited token
		Flags # and + are not implemented.

	The familiar base-setting prefixes 0 (octal) and 0x
	(hexadecimal) are accepted when scanning integers without a
	format or with the %v verb.

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, a carriage return followed
	immediately by a newline is treated as a plain newline
	(\r\n means the same as \n).

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the input
	they return, which means that a loop calling a scan routine
	may skip some of the input.  This is usually a problem only
	when there is no space between input values.  If the reader
	provided to Fscan implements ReadRune, that method will be used
	to read characters.  If the reader also implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach ReadRune and UnreadRune
	methods to a reader without that capability, use
	bufio.NewReader.
*/
package fmt
<commit_msg>fmt: document GoStringer and explain application of formats to compound objects %q quotes each element of a string slice; this was never explained in the docs. Fixes issue 7015.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value
		%%	a literal percent sign; consumes no value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%q	a single-quoted character literal safely escaped with Go syntax.
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%04X"
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power of two,
			in the manner of strconv.FormatFloat with the 'b' format,
			e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	Width is specified by an optional decimal number immediately following the verb.
	If absent, the width is whatever is necessary to represent the value.
	Precision is specified after the (optional) width by a period followed by a
	decimal number. If no period is present, a default precision is used.
	A period with no following number specifies a precision of zero.
	Examples:
		%f:    default width, default precision
		%9f    width 9, default precision
		%.2f   default width, precision 2
		%9.2f  width 9, precision 2
		%9.f   width 9, precision 0

	Width and precision are measured in units of Unicode code points.
	(This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For most values, width is the minimum number of characters to output,
	padding the formatted form with spaces if necessary.
	For strings, precision is the maximum number of characters to output,
	truncating if necessary.

	For floating-point values, width sets the minimum width of the field and
	precision sets the number of places after the decimal, if appropriate,
	except that for %g/%G it sets the total number of digits. For example,
	given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
	The default precision for %e and %f is 6; for %g it is the smallest
	number of digits necessary to identify the value uniquely.

	For complex numbers, the width and precision apply to the two
	components independently and the result is parenthsized, so %f applied
	to 1.2+3.4i produces (1.200000+3.400000i).

	Other flags:
		+	always print a sign for numeric values;
			guarantee ASCII-only output for %q (%+q)
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			for %q, print a raw (backquoted) string if strconv.CanBackquote
			returns true;
			write e.g. U+0078 'x' if the character is printable for %U (%#U).
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces;
			for numbers, this moves the padding after the sign

	Flags are ignored by verbs that do not expect them.
	For example there is no alternate decimal format, so %#d and %d
	behave identically.

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting. Similarly, if an
	operand implements the GoStringer interface, that will be
	invoked if the '%#v' verb is used to format the operand.

	If the format (which is implicitly %v for Println etc.) is valid
	for a string (%s %q %v %x %X), the following two rules also apply:

	1. If an operand implements the error interface, the Error method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any).

	2. If an operand implements method String() string, that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any).

	For compound operands such as slices and structs, the format
	applies to the elements of each operand, recursively, not to the
	operand as a whole. Thus %q will quote each element of a slice
	of strings, and %6.2f will control formatting for each element
	of a floating-point array.

	To avoid recursion in cases such as
		type X string
		func (x X) String() string { return Sprintf("<%s>", x) }
	convert the value before recurring:
		func (x X) String() string { return Sprintf("<%s>", string(x)) }

	Explicit argument indexes:

	In Printf, Sprintf, and Fprintf, the default behavior is for each
	formatting verb to format successive arguments passed in the call.
	However, the notation [n] immediately before the verb indicates that the
	nth one-indexed argument is to be formatted instead. The same notation
	before a '*' for a width or precision selects the argument index holding
	the value. After processing a bracketed expression [n], arguments n+1,
	n+2, etc. will be processed unless otherwise directed.

	For example,
		fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
	will yield "22, 11", while
		fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),
	equivalent to
		fmt.Sprintf("%6.2f", 12.0),
	will yield " 12.00". Because an explicit index affects subsequent verbs,
	this notation can be used to print the same values multiple times
	by resetting the index for the first argument to be repeated:
		fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
	will yield "16 17 0x10 0x11".

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
		Invalid or invalid use of argument index: %!(BADINDEX)
			Printf("%*[2]d", 7):       %!d(BADINDEX)
			Printf("%.[2]d", 7):       %!d(BADINDEX)

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	If an Error or String method triggers a panic when called by a
	print routine, the fmt package reformats the error message
	from the panic, decorating it with an indication that it came
	through the fmt package.  For example, if a String method
	calls panic("bad"), the resulting formatted message will look
	like
		%!s(PANIC=bad)

	The %!s just shows the print verb in use when the failure
	occurred.

	Scanning

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified io.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Scanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Scanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

		%p is not implemented
		%T is not implemented
		%e %E %f %F %g %G are all equivalent and scan any floating point or complex value
		%s and %v on strings scan a space-delimited token
		Flags # and + are not implemented.

	The familiar base-setting prefixes 0 (octal) and 0x
	(hexadecimal) are accepted when scanning integers without a
	format or with the %v verb.

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, a carriage return followed
	immediately by a newline is treated as a plain newline
	(\r\n means the same as \n).

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the input
	they return, which means that a loop calling a scan routine
	may skip some of the input.  This is usually a problem only
	when there is no space between input values.  If the reader
	provided to Fscan implements ReadRune, that method will be used
	to read characters.  If the reader also implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach ReadRune and UnreadRune
	methods to a reader without that capability, use
	bufio.NewReader.
*/
package fmt
<|endoftext|>


<commit_before>package analytics

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"github.com/jehiah/go-strftime"
	"github.com/xtgo/uuid"
)

// Version of the client.
const Version = "2.0.0"

// Endpoint for the Segment API.
const Endpoint = "https://api.segment.io"

// DefaultContext of message batches.
var DefaultContext = map[string]interface{}{
	"library": map[string]interface{}{
		"name":    "analytics-go",
		"version": Version,
	},
}

// Message interface.
type message interface {
	setMessageId(string)
	setTimestamp(string)
}

// Response from API.
type response struct {
	Message string `json:"message"`
	Code    string `json:"code"`
}

// Message fields common to all.
type Message struct {
	Type      string `json:"type,omitempty"`
	MessageId string `json:"messageId,omitempty"`
	Timestamp string `json:"timestamp,omitempty"`
	SentAt    string `json:"sentAt,omitempty"`
}

// Batch message.
type Batch struct {
	Context  map[string]interface{} `json:"context,omitempty"`
	Messages []interface{}          `json:"batch"`
	Message
}

// Identify message.
type Identify struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"traits,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Message
}

// Group message.
type Group struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"traits,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	GroupId     string                 `json:"groupId"`
	Message
}

// Track message.
type Track struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Properties  map[string]interface{} `json:"properties,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Event       string                 `json:"event"`
	Message
}

// Page message.
type Page struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"properties,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Category    string                 `json:"category,omitempty"`
	Name        string                 `json:"name,omitempty"`
	Message
}

// Alias message.
type Alias struct {
	PreviousId string `json:"previousId"`
	UserId     string `json:"userId"`
	Message
}

// Client which batches messages and flushes at the given Interval or
// when the Size limit is exceeded. Set Verbose to true to enable
// logging output.
type Client struct {
	Endpoint string
	Interval time.Duration
	Verbose  bool
	Size     int
	key      string
	msgs     chan interface{}
	quit     chan bool

	uid func() string
	now func() time.Time
}

// New client with write key.
func New(key string) *Client {
	c := &Client{
		msgs:     make(chan interface{}, 100),
		quit:     make(chan bool),
		Interval: 5 * time.Second,
		Endpoint: Endpoint,
		Size:     250,
		key:      key,
		now:      time.Now,
		uid:      uid,
	}

	go c.loop()

	return c
}

// Alias buffers an "alias" message.
func (c *Client) Alias(msg *Alias) error {
	if msg.UserId == "" {
		return errors.New("You must pass a 'userId'.")
	}

	if msg.PreviousId == "" {
		return errors.New("You must pass a 'previousId'.")
	}

	msg.Type = "alias"
	c.queue(msg)

	return nil
}

// Page buffers an "page" message.
func (c *Client) Page(msg *Page) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "page"
	c.queue(msg)

	return nil
}

// Group buffers an "group" message.
func (c *Client) Group(msg *Group) error {
	if msg.GroupId == "" {
		return errors.New("You must pass a 'groupId'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "group"
	c.queue(msg)

	return nil
}

// Identify buffers an "identify" message.
func (c *Client) Identify(msg *Identify) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "identify"
	c.queue(msg)

	return nil
}

// Track buffers an "track" message.
func (c *Client) Track(msg *Track) error {
	if msg.Event == "" {
		return errors.New("You must pass 'event'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "track"
	c.queue(msg)

	return nil
}

// Queue message.
func (c *Client) queue(msg message) {
	msg.setMessageId(c.uid())
	msg.setTimestamp(timestamp(c.now()))
	c.msgs <- msg
}

// Close and flush metrics.
func (c *Client) Close() error {
	c.quit <- true
	close(c.msgs)
	<-c.quit
	return nil
}

// Send batch request.
func (c *Client) send(msgs []interface{}) {
	if len(msgs) == 0 {
		return
	}

	batch := new(Batch)
	batch.Messages = msgs
	batch.MessageId = c.uid()
	batch.SentAt = timestamp(c.now())
	batch.Context = DefaultContext

	b, err := json.Marshal(batch)
	if err != nil {
		c.log("error marshalling msgs: %s", err)
		return
	}

	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.log("error creating request: %s", err)
		return
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		c.log("error sending request: %s", err)
		return
	}
	defer res.Body.Close()

	c.report(res)
}

// Report on response body.
func (c *Client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.verbose("response %s", res.Status)
		return
	}

	msg := new(response)
	err := json.NewDecoder(res.Body).Decode(msg)
	if err != nil {
		c.log("error reading response: %s", err)
		return
	}

	c.log("response %s: %s – %s", res.Status, msg.Code, msg.Message)
}

// Batch loop.
func (c *Client) loop() {
	var msgs []interface{}
	tick := time.NewTicker(c.Interval)

	for {
		select {
		case msg := <-c.msgs:
			c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
			msgs = append(msgs, msg)
			if len(msgs) == c.Size {
				c.verbose("exceeded %d messages – flushing", c.Size)
				c.send(msgs)
				msgs = nil
			}
		case <-tick.C:
			if len(msgs) > 0 {
				c.verbose("interval reached - flushing %d", len(msgs))
				c.send(msgs)
				msgs = nil
			} else {
				c.verbose("interval reached – nothing to send")
			}
		case <-c.quit:
			c.verbose("exit requested – flushing %d", len(msgs))
			c.send(msgs)
			c.verbose("exit")
			c.quit <- true
			return
		}
	}
}

// Verbose log.
func (c *Client) verbose(msg string, args ...interface{}) {
	if c.Verbose {
		log.Printf("segment: "+msg, args...)
	}
}

// Unconditional log.
func (c *Client) log(msg string, args ...interface{}) {
	log.Printf("segment: "+msg, args...)
}

// Set message timestamp if one is not already set.
func (m *Message) setTimestamp(s string) {
	if m.Timestamp == "" {
		m.Timestamp = s
	}
}

// Set message id.
func (m *Message) setMessageId(s string) {
	m.MessageId = s
}

// Return formatted timestamp.
func timestamp(t time.Time) string {
	return strftime.Format("%Y-%m-%dT%H:%M:%S%z", t)
}

// Return uuid string.
func uid() string {
	return uuid.NewRandom().String()
}
<commit_msg>OCD: organize struct declaring and initializers<commit_after>package analytics

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"github.com/jehiah/go-strftime"
	"github.com/xtgo/uuid"
)

// Version of the client.
const Version = "2.0.0"

// Endpoint for the Segment API.
const Endpoint = "https://api.segment.io"

// DefaultContext of message batches.
var DefaultContext = map[string]interface{}{
	"library": map[string]interface{}{
		"name":    "analytics-go",
		"version": Version,
	},
}

// Message interface.
type message interface {
	setMessageId(string)
	setTimestamp(string)
}

// Response from API.
type response struct {
	Message string `json:"message"`
	Code    string `json:"code"`
}

// Message fields common to all.
type Message struct {
	Type      string `json:"type,omitempty"`
	MessageId string `json:"messageId,omitempty"`
	Timestamp string `json:"timestamp,omitempty"`
	SentAt    string `json:"sentAt,omitempty"`
}

// Batch message.
type Batch struct {
	Context  map[string]interface{} `json:"context,omitempty"`
	Messages []interface{}          `json:"batch"`
	Message
}

// Identify message.
type Identify struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"traits,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Message
}

// Group message.
type Group struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"traits,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	GroupId     string                 `json:"groupId"`
	Message
}

// Track message.
type Track struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Properties  map[string]interface{} `json:"properties,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Event       string                 `json:"event"`
	Message
}

// Page message.
type Page struct {
	Context     map[string]interface{} `json:"context,omitempty"`
	Traits      map[string]interface{} `json:"properties,omitempty"`
	AnonymousId string                 `json:"anonymousId,omitempty"`
	UserId      string                 `json:"userId,omitempty"`
	Category    string                 `json:"category,omitempty"`
	Name        string                 `json:"name,omitempty"`
	Message
}

// Alias message.
type Alias struct {
	PreviousId string `json:"previousId"`
	UserId     string `json:"userId"`
	Message
}

// Client which batches messages and flushes at the given Interval or
// when the Size limit is exceeded. Set Verbose to true to enable
// logging output.
type Client struct {
	Endpoint string
	Interval time.Duration
	Size     int
	Verbose  bool
	key      string
	msgs     chan interface{}
	quit     chan bool
	uid      func() string
	now      func() time.Time
}

// New client with write key.
func New(key string) *Client {
	c := &Client{
		Endpoint: Endpoint,
		Interval: 5 * time.Second,
		Size:     250,
		Verbose:  false,
		key:      key,
		msgs:     make(chan interface{}, 100),
		quit:     make(chan bool),
		now:      time.Now,
		uid:      uid,
	}

	go c.loop()

	return c
}

// Alias buffers an "alias" message.
func (c *Client) Alias(msg *Alias) error {
	if msg.UserId == "" {
		return errors.New("You must pass a 'userId'.")
	}

	if msg.PreviousId == "" {
		return errors.New("You must pass a 'previousId'.")
	}

	msg.Type = "alias"
	c.queue(msg)

	return nil
}

// Page buffers an "page" message.
func (c *Client) Page(msg *Page) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "page"
	c.queue(msg)

	return nil
}

// Group buffers an "group" message.
func (c *Client) Group(msg *Group) error {
	if msg.GroupId == "" {
		return errors.New("You must pass a 'groupId'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "group"
	c.queue(msg)

	return nil
}

// Identify buffers an "identify" message.
func (c *Client) Identify(msg *Identify) error {
	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "identify"
	c.queue(msg)

	return nil
}

// Track buffers an "track" message.
func (c *Client) Track(msg *Track) error {
	if msg.Event == "" {
		return errors.New("You must pass 'event'.")
	}

	if msg.UserId == "" && msg.AnonymousId == "" {
		return errors.New("You must pass either an 'anonymousId' or 'userId'.")
	}

	msg.Type = "track"
	c.queue(msg)

	return nil
}

// Queue message.
func (c *Client) queue(msg message) {
	msg.setMessageId(c.uid())
	msg.setTimestamp(timestamp(c.now()))
	c.msgs <- msg
}

// Close and flush metrics.
func (c *Client) Close() error {
	c.quit <- true
	close(c.msgs)
	<-c.quit
	return nil
}

// Send batch request.
func (c *Client) send(msgs []interface{}) {
	if len(msgs) == 0 {
		return
	}

	batch := new(Batch)
	batch.Messages = msgs
	batch.MessageId = c.uid()
	batch.SentAt = timestamp(c.now())
	batch.Context = DefaultContext

	b, err := json.Marshal(batch)
	if err != nil {
		c.log("error marshalling msgs: %s", err)
		return
	}

	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.log("error creating request: %s", err)
		return
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		c.log("error sending request: %s", err)
		return
	}
	defer res.Body.Close()

	c.report(res)
}

// Report on response body.
func (c *Client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.verbose("response %s", res.Status)
		return
	}

	msg := new(response)
	err := json.NewDecoder(res.Body).Decode(msg)
	if err != nil {
		c.log("error reading response: %s", err)
		return
	}

	c.log("response %s: %s – %s", res.Status, msg.Code, msg.Message)
}

// Batch loop.
func (c *Client) loop() {
	var msgs []interface{}
	tick := time.NewTicker(c.Interval)

	for {
		select {
		case msg := <-c.msgs:
			c.verbose("buffer (%d/%d) %v", len(msgs), c.Size, msg)
			msgs = append(msgs, msg)
			if len(msgs) == c.Size {
				c.verbose("exceeded %d messages – flushing", c.Size)
				c.send(msgs)
				msgs = nil
			}
		case <-tick.C:
			if len(msgs) > 0 {
				c.verbose("interval reached - flushing %d", len(msgs))
				c.send(msgs)
				msgs = nil
			} else {
				c.verbose("interval reached – nothing to send")
			}
		case <-c.quit:
			c.verbose("exit requested – flushing %d", len(msgs))
			c.send(msgs)
			c.verbose("exit")
			c.quit <- true
			return
		}
	}
}

// Verbose log.
func (c *Client) verbose(msg string, args ...interface{}) {
	if c.Verbose {
		log.Printf("segment: "+msg, args...)
	}
}

// Unconditional log.
func (c *Client) log(msg string, args ...interface{}) {
	log.Printf("segment: "+msg, args...)
}

// Set message timestamp if one is not already set.
func (m *Message) setTimestamp(s string) {
	if m.Timestamp == "" {
		m.Timestamp = s
	}
}

// Set message id.
func (m *Message) setMessageId(s string) {
	m.MessageId = s
}

// Return formatted timestamp.
func timestamp(t time.Time) string {
	return strftime.Format("%Y-%m-%dT%H:%M:%S%z", t)
}

// Return uuid string.
func uid() string {
	return uuid.NewRandom().String()
}
<|endoftext|>


<commit_before>package httpclient

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"time"

	"code.cloudfoundry.org/tlsconfig"

	proxy "github.com/cloudfoundry/socks5-proxy"
)

var (
	DefaultClient            = CreateDefaultClientInsecureSkipVerify()
	defaultDialerContextFunc = SOCKS5DialContextFuncFromEnvironment((&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}), proxy.NewSocks5Proxy(proxy.NewHostKey(), log.New(ioutil.Discard, "", log.LstdFlags), 1*time.Minute))
)

type Client interface {
	Do(*http.Request) (*http.Response, error)
}

func CreateDefaultClient(certPool *x509.CertPool) *http.Client {
	insecureSkipVerify := false
	external := false
	return factory{}.New(insecureSkipVerify, external, certPool)
}

func CreateExternalDefaultClient(certPool *x509.CertPool) *http.Client {
	insecureSkipVerify := false
	external := true
	return factory{}.New(insecureSkipVerify, external, certPool)
}

func CreateDefaultClientInsecureSkipVerify() *http.Client {
	insecureSkipVerify := true
	external := false
	return factory{}.New(insecureSkipVerify, external, nil)
}

type factory struct{}

func (f factory) New(insecureSkipVerify, externalClient bool, certPool *x509.CertPool) *http.Client {
	serviceDefaults := tlsconfig.WithInternalServiceDefaults()
	if externalClient {
		serviceDefaults = tlsconfig.WithExternalServiceDefaults()
	}

	tlsConfig, err := tlsconfig.Build(
		serviceDefaults,
		WithInsecureSkipVerify(insecureSkipVerify),
		WithClientSessionCache(0),
	).Client(tlsconfig.WithAuthority(certPool))
	if err != nil {
		log.Fatal(err)
	}

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig:     tlsConfig,
			Proxy:               http.ProxyFromEnvironment,
			DialContext:         defaultDialerContextFunc,
			TLSHandshakeTimeout: 30 * time.Second,
		},
	}

	return client
}

func WithInsecureSkipVerify(insecureSkipVerify bool) tlsconfig.TLSOption {
	return func(config *tls.Config) error {
		config.InsecureSkipVerify = insecureSkipVerify
		return nil
	}
}

func WithClientSessionCache(capacity int) tlsconfig.TLSOption {
	return func(config *tls.Config) error {
		config.ClientSessionCache = tls.NewLRUClientSessionCache(capacity)
		return nil
	}
}
<commit_msg>Move http keepalive into own client [#173690103]<commit_after>package httpclient

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"time"

	"code.cloudfoundry.org/tlsconfig"

	proxy "github.com/cloudfoundry/socks5-proxy"
)

var (
	DefaultClient            = CreateDefaultClientInsecureSkipVerify()
	defaultDialerContextFunc = SOCKS5DialContextFuncFromEnvironment((&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}), proxy.NewSocks5Proxy(proxy.NewHostKey(), log.New(ioutil.Discard, "", log.LstdFlags), 1*time.Minute))
)

type Client interface {
	Do(*http.Request) (*http.Response, error)
}

func CreateDefaultClient(certPool *x509.CertPool) *http.Client {
	insecureSkipVerify := false
	external := false
	disableKeepAlives := true
	return factory{}.New(insecureSkipVerify, external, disableKeepAlives, certPool)
}

func CreateExternalDefaultClient(certPool *x509.CertPool) *http.Client {
	insecureSkipVerify := false
	external := true
	disableKeepAlives := true
	return factory{}.New(insecureSkipVerify, external, disableKeepAlives, certPool)
}

func CreateKeepAliveDefaultClient(certPool *x509.CertPool) *http.Client {
	insecureSkipVerify := false
	external := true
	disableKeepAlives := false
	return factory{}.New(insecureSkipVerify, external, disableKeepAlives, certPool)
}

func CreateDefaultClientInsecureSkipVerify() *http.Client {
	insecureSkipVerify := true
	external := false
	disableKeepAlives := true
	return factory{}.New(insecureSkipVerify, external, disableKeepAlives, nil)
}

type factory struct{}

func (f factory) New(insecureSkipVerify, externalClient bool, disableKeepAlives bool, certPool *x509.CertPool) *http.Client {
	serviceDefaults := tlsconfig.WithInternalServiceDefaults()
	if externalClient {
		serviceDefaults = tlsconfig.WithExternalServiceDefaults()
	}

	tlsConfig, err := tlsconfig.Build(
		serviceDefaults,
		WithInsecureSkipVerify(insecureSkipVerify),
		WithClientSessionCache(0),
	).Client(tlsconfig.WithAuthority(certPool))
	if err != nil {
		log.Fatal(err)
	}

	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig:     tlsConfig,
			Proxy:               http.ProxyFromEnvironment,
			DialContext:         defaultDialerContextFunc,
			TLSHandshakeTimeout: 30 * time.Second,
			DisableKeepAlives:   disableKeepAlives,
		},
	}

	return client
}

func WithInsecureSkipVerify(insecureSkipVerify bool) tlsconfig.TLSOption {
	return func(config *tls.Config) error {
		config.InsecureSkipVerify = insecureSkipVerify
		return nil
	}
}

func WithClientSessionCache(capacity int) tlsconfig.TLSOption {
	return func(config *tls.Config) error {
		config.ClientSessionCache = tls.NewLRUClientSessionCache(capacity)
		return nil
	}
}
<|endoftext|>