<commit_before>package httpclient

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/gobs/pretty"
	"github.com/gobs/simplejson"
)

var (
	DefaultClient = &http.Client{} // we use our own default client, so we can change the TLS configuration

	NoRedirect       = errors.New("No redirect")
	TooManyRedirects = errors.New("stopped after 10 redirects")
)

//
// Allow connections via HTTPS even if something is wrong with the certificate
// (self-signed or expired)
//
func AllowInsecure(insecure bool) {
	if insecure {
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		DefaultClient.Transport = tr
	} else {
		DefaultClient.Transport = nil
	}
}

//
// Set connection timeout
//
func SetTimeout(t time.Duration) {
	DefaultClient.Timeout = t
}

//
// HTTP error
//
type HttpError struct {
	Code    int
	Message string
}

func (e HttpError) Error() string {
	return e.Message
}

func (e HttpError) String() string {
	return fmt.Sprintf("ERROR: %v %v", e.Code, e.Message)
}

//
// CloseResponse makes sure we close the response body
//
func CloseResponse(r *http.Response) {
	if r != nil && r.Body != nil {
		io.Copy(ioutil.Discard, r.Body)
		r.Body.Close()
	}
}

//
// A wrapper for http.Response
//
type HttpResponse struct {
	http.Response
}

func (r *HttpResponse) ContentType() string {
	content_type := r.Header.Get("Content-Type")
	if len(content_type) == 0 {
		return content_type
	}

	return strings.TrimSpace(strings.Split(content_type, ";")[0])
}

//
// Close makes sure that all data from the body is read
// before closing the reader.
//
// If that is not the desider behaviour, just call HttpResponse.Body.Close()
//
func (r *HttpResponse) Close() {
        if r != nil {
	    CloseResponse(&r.Response)
        }
}

//
// ResponseError checks the StatusCode and return an error if needed.
// The error is of type HttpError
//
func (r *HttpResponse) ResponseError() error {
	class := r.StatusCode / 100
	if class != 2 && class != 3 {
		return HttpError{Code: r.StatusCode, Message: "HTTP " + r.Status}
	}

	return nil
}

//
// Check if the input value is a "primitive" that can be safely stringified
//
func canStringify(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Float32, reflect.Float64,
		reflect.String:
		return true
	default:
		return false
	}
}

//
// Given a base URL and a bag of parameteters returns the URL with the encoded parameters
//
func URLWithPathParams(base string, path string, params map[string]interface{}) (u *url.URL) {

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

	if len(path) > 0 {
		u, err = u.Parse(path)
		if err != nil {
			log.Fatal(err)
		}
	}

	q := u.Query()

	for k, v := range params {
		val := reflect.ValueOf(v)

		switch val.Kind() {
		case reflect.Slice:
			if val.IsNil() { // TODO: add an option to ignore empty values
				q.Set(k, "")
				continue
			}
			fallthrough

		case reflect.Array:
			for i := 0; i < val.Len(); i++ {
				av := val.Index(i)

				if canStringify(av) {
					q.Add(k, fmt.Sprintf("%v", av))
				}
			}

		default:
			if canStringify(val) {
				q.Set(k, fmt.Sprintf("%v", v))
			} else {
				log.Fatal("Invalid type ", val)
			}
		}
	}

	u.RawQuery = q.Encode()
	return u
}

func URLWithParams(base string, params map[string]interface{}) (u *url.URL) {
	return URLWithPathParams(base, "", params)
}

//
// http.Get with params
//
func Get(urlStr string, params map[string]interface{}) (*HttpResponse, error) {
	resp, err := DefaultClient.Get(URLWithParams(urlStr, params).String())
	if err == nil {
		return &HttpResponse{*resp}, nil
	} else {
		CloseResponse(resp)
		return nil, err
	}
}

//
// http.Post with params
//
func Post(urlStr string, params map[string]interface{}) (*HttpResponse, error) {
	resp, err := DefaultClient.PostForm(urlStr, URLWithParams(urlStr, params).Query())
	if err == nil {
		return &HttpResponse{*resp}, nil
	} else {
		CloseResponse(resp)
		return nil, err
	}
}

//
//  Read the body
//
func (resp *HttpResponse) Content() []byte {
	body, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	return body
}

//
//  Try to parse the response body as JSON
//
func (resp *HttpResponse) Json() (json *simplejson.Json) {
	json, _ = simplejson.LoadBytes(resp.Content())
	return
}

////////////////////////////////////////////////////////////////////////

//
// http.Client with some defaults and stuff
//
type HttpClient struct {
	// the http.Client
	client *http.Client

	// the base URL for this client
	BaseURL *url.URL

	// the client UserAgent string
	UserAgent string

	// Common headers to be passed on each request
	Headers map[string]string

	// if Verbose, log request and response info
	Verbose bool
}

//
// Create a new HttpClient
//
func NewHttpClient(base string) (httpClient *HttpClient) {
	httpClient = new(HttpClient)
	httpClient.client = &http.Client{CheckRedirect: httpClient.checkRedirect}
	httpClient.Headers = make(map[string]string)

	if u, err := url.Parse(base); err != nil {
		log.Fatal(err)
	} else {
		httpClient.BaseURL = u
	}

	return
}

//
// Allow connections via HTTPS even if something is wrong with the certificate
// (self-signed or expired)
//
func (self *HttpClient) AllowInsecure(insecure bool) {
	if insecure {
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		self.client.Transport = tr
	} else {
		self.client.Transport = nil
	}
}

//
// Set connection timeout
//
func (self *HttpClient) SetTimeout(t time.Duration) {
	self.client.Timeout = t
}

//
// Set LocalAddr in Dialer
//
func (self *HttpClient) SetLocalAddr(addr string) {
	transport, ok := self.client.Transport.(*http.Transport)
	if transport == nil {
		if transport, ok = http.DefaultTransport.(*http.Transport); !ok {
			log.Println("SetLocalAddr for http.DefaultTransport != http.Transport")
			return
		}
	} else if !ok {
		log.Println("SetLocalAddr for client.Transport != http.Transport")
		return
	}
	if tcpaddr, err := net.ResolveTCPAddr("tcp", addr); err == nil {
		transport.Dial = (&net.Dialer{
			Timeout:   30 * time.Second, // defaults from net/http DefaultTransport
			KeepAlive: 30 * time.Second, // defaults from net/http DefaultTransport
			LocalAddr: tcpaddr,
		}).Dial
	} else {
		log.Println("Failed to resolve", addr, " to a TCP address")
	}
}

//
// add default headers plus extra headers
//
func (self *HttpClient) addHeaders(req *http.Request, headers map[string]string) {

	if len(self.UserAgent) > 0 {
		req.Header.Set("User-Agent", self.UserAgent)
	}

	for k, v := range self.Headers {
		req.Header.Set(k, v)
	}

	for k, v := range headers {
		if strings.ToLower(k) == "content-length" {
			if len, err := strconv.Atoi(v); err == nil && req.ContentLength <= 0 {
				req.ContentLength = int64(len)
			}
		} else {
			req.Header.Set(k, v)
		}
	}

}

//
// the callback for CheckRedirect, used to pass along the headers in case of redirection
//
func (self *HttpClient) checkRedirect(req *http.Request, via []*http.Request) error {
	if req.Method == "HEAD" {
		// don't follow redirects on a HEAD request
		return NoRedirect
	}

	if self.Verbose {
		log.Println("REDIRECT:", len(via), req.URL)
	}

	if len(via) >= 10 {
		return TooManyRedirects
	}

	// TODO: check for same host before adding headers
	self.addHeaders(req, nil)
	return nil
}

//
// Create a request object given the method, path, body and extra headers
//
func (self *HttpClient) Request(method string, urlpath string, body io.Reader, headers map[string]string) (req *http.Request) {
	if u, err := self.BaseURL.Parse(urlpath); err != nil {
		log.Fatal(err)
	} else {
		urlpath = u.String()
	}

	req, err := http.NewRequest(method, urlpath, body)
	if err != nil {
		log.Fatal(err)
	}

	self.addHeaders(req, headers)
	return
}

//
// Execute request
//
func (self *HttpClient) Do(req *http.Request) (*HttpResponse, error) {
	if self.Verbose {
		log.Println("REQUEST:", req.Method, req.URL, pretty.PrettyFormat(req.Header))
	}

	resp, err := self.client.Do(req)
	if urlerr, ok := err.(*url.Error); ok && urlerr.Err == NoRedirect {
		err = nil // redirect on HEAD is not an error
	}
	if err == nil {
		if self.Verbose {
			log.Println("RESPONSE:", resp.Status, pretty.PrettyFormat(resp.Header))
		}

		return &HttpResponse{*resp}, nil
	} else {
		if self.Verbose {
			log.Println("ERROR:", err, "REQUEST:", req.Method, req.URL, pretty.PrettyFormat(req.Header))
		}

		CloseResponse(resp)
		return nil, err
	}
}

//
// Execute a DELETE request
//
func (self *HttpClient) Delete(path string, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("DELETE", path, nil, headers)
	return self.Do(req)
}

//
// Execute a HEAD request
//
func (self *HttpClient) Head(path string, params map[string]interface{}, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("HEAD", URLWithParams(path, params).String(), nil, headers)
	return self.Do(req)
}

//
// Execute a GET request
//
func (self *HttpClient) Get(path string, params map[string]interface{}, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("GET", URLWithParams(path, params).String(), nil, headers)
	return self.Do(req)
}

//
// Execute a POST request
//
func (self *HttpClient) Post(path string, content io.Reader, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("POST", path, content, headers)
	return self.Do(req)
}

//
// Execute a PUT request
//
func (self *HttpClient) Put(path string, content io.Reader, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("PUT", path, content, headers)
	return self.Do(req)
}
<commit_msg>use "reuseport" package to open reusable connections (still not sure it really works...)<commit_after>package httpclient

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/gobs/pretty"
	"github.com/gobs/simplejson"

	"github.com/jbenet/go-reuseport"
)

var (
	DefaultClient = &http.Client{} // we use our own default client, so we can change the TLS configuration

	NoRedirect       = errors.New("No redirect")
	TooManyRedirects = errors.New("stopped after 10 redirects")
)

//
// Allow connections via HTTPS even if something is wrong with the certificate
// (self-signed or expired)
//
func AllowInsecure(insecure bool) {
	if insecure {
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		DefaultClient.Transport = tr
	} else {
		DefaultClient.Transport = nil
	}
}

//
// Set connection timeout
//
func SetTimeout(t time.Duration) {
	DefaultClient.Timeout = t
}

//
// HTTP error
//
type HttpError struct {
	Code    int
	Message string
}

func (e HttpError) Error() string {
	return e.Message
}

func (e HttpError) String() string {
	return fmt.Sprintf("ERROR: %v %v", e.Code, e.Message)
}

//
// CloseResponse makes sure we close the response body
//
func CloseResponse(r *http.Response) {
	if r != nil && r.Body != nil {
		io.Copy(ioutil.Discard, r.Body)
		r.Body.Close()
	}
}

//
// A wrapper for http.Response
//
type HttpResponse struct {
	http.Response
}

func (r *HttpResponse) ContentType() string {
	content_type := r.Header.Get("Content-Type")
	if len(content_type) == 0 {
		return content_type
	}

	return strings.TrimSpace(strings.Split(content_type, ";")[0])
}

//
// Close makes sure that all data from the body is read
// before closing the reader.
//
// If that is not the desider behaviour, just call HttpResponse.Body.Close()
//
func (r *HttpResponse) Close() {
	if r != nil {
		CloseResponse(&r.Response)
	}
}

//
// ResponseError checks the StatusCode and return an error if needed.
// The error is of type HttpError
//
func (r *HttpResponse) ResponseError() error {
	class := r.StatusCode / 100
	if class != 2 && class != 3 {
		return HttpError{Code: r.StatusCode, Message: "HTTP " + r.Status}
	}

	return nil
}

//
// Check if the input value is a "primitive" that can be safely stringified
//
func canStringify(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Float32, reflect.Float64,
		reflect.String:
		return true
	default:
		return false
	}
}

//
// Given a base URL and a bag of parameteters returns the URL with the encoded parameters
//
func URLWithPathParams(base string, path string, params map[string]interface{}) (u *url.URL) {

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

	if len(path) > 0 {
		u, err = u.Parse(path)
		if err != nil {
			log.Fatal(err)
		}
	}

	q := u.Query()

	for k, v := range params {
		val := reflect.ValueOf(v)

		switch val.Kind() {
		case reflect.Slice:
			if val.IsNil() { // TODO: add an option to ignore empty values
				q.Set(k, "")
				continue
			}
			fallthrough

		case reflect.Array:
			for i := 0; i < val.Len(); i++ {
				av := val.Index(i)

				if canStringify(av) {
					q.Add(k, fmt.Sprintf("%v", av))
				}
			}

		default:
			if canStringify(val) {
				q.Set(k, fmt.Sprintf("%v", v))
			} else {
				log.Fatal("Invalid type ", val)
			}
		}
	}

	u.RawQuery = q.Encode()
	return u
}

func URLWithParams(base string, params map[string]interface{}) (u *url.URL) {
	return URLWithPathParams(base, "", params)
}

//
// http.Get with params
//
func Get(urlStr string, params map[string]interface{}) (*HttpResponse, error) {
	resp, err := DefaultClient.Get(URLWithParams(urlStr, params).String())
	if err == nil {
		return &HttpResponse{*resp}, nil
	} else {
		CloseResponse(resp)
		return nil, err
	}
}

//
// http.Post with params
//
func Post(urlStr string, params map[string]interface{}) (*HttpResponse, error) {
	resp, err := DefaultClient.PostForm(urlStr, URLWithParams(urlStr, params).Query())
	if err == nil {
		return &HttpResponse{*resp}, nil
	} else {
		CloseResponse(resp)
		return nil, err
	}
}

//
//  Read the body
//
func (resp *HttpResponse) Content() []byte {
	body, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	return body
}

//
//  Try to parse the response body as JSON
//
func (resp *HttpResponse) Json() (json *simplejson.Json) {
	json, _ = simplejson.LoadBytes(resp.Content())
	return
}

////////////////////////////////////////////////////////////////////////

//
// http.Client with some defaults and stuff
//
type HttpClient struct {
	// the http.Client
	client *http.Client

	// the base URL for this client
	BaseURL *url.URL

	// the client UserAgent string
	UserAgent string

	// Common headers to be passed on each request
	Headers map[string]string

	// if Verbose, log request and response info
	Verbose bool
}

//
// Create a new HttpClient
//
func NewHttpClient(base string) (httpClient *HttpClient) {
	httpClient = new(HttpClient)
	httpClient.client = &http.Client{CheckRedirect: httpClient.checkRedirect}
	httpClient.Headers = make(map[string]string)

	if u, err := url.Parse(base); err != nil {
		log.Fatal(err)
	} else {
		httpClient.BaseURL = u
	}

	return
}

//
// Allow connections via HTTPS even if something is wrong with the certificate
// (self-signed or expired)
//
func (self *HttpClient) AllowInsecure(insecure bool) {
	if insecure {
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}

		self.client.Transport = tr
	} else {
		self.client.Transport = nil
	}
}

//
// Set connection timeout
//
func (self *HttpClient) SetTimeout(t time.Duration) {
	self.client.Timeout = t
}

//
// Set LocalAddr in Dialer
// (this assumes you also want the SO_REUSEPORT/SO_REUSEADDR stuff)
//
func (self *HttpClient) SetLocalAddr(addr string) {
	transport, ok := self.client.Transport.(*http.Transport)
	if transport == nil {
		if transport, ok = http.DefaultTransport.(*http.Transport); !ok {
			log.Println("SetLocalAddr for http.DefaultTransport != http.Transport")
			return
		}
	} else if !ok {
		log.Println("SetLocalAddr for client.Transport != http.Transport")
		return
	}
	if tcpaddr, err := net.ResolveTCPAddr("tcp", addr); err == nil {
		dialer := &reuseport.Dialer{
			D: net.Dialer{
				Timeout:   30 * time.Second, // defaults from net/http DefaultTransport
				KeepAlive: 30 * time.Second, // defaults from net/http DefaultTransport
				LocalAddr: tcpaddr,
			}}
		transport.Dial = dialer.Dial
	} else {
		log.Println("Failed to resolve", addr, " to a TCP address")
	}
}

//
// add default headers plus extra headers
//
func (self *HttpClient) addHeaders(req *http.Request, headers map[string]string) {

	if len(self.UserAgent) > 0 {
		req.Header.Set("User-Agent", self.UserAgent)
	}

	for k, v := range self.Headers {
		req.Header.Set(k, v)
	}

	for k, v := range headers {
		if strings.ToLower(k) == "content-length" {
			if len, err := strconv.Atoi(v); err == nil && req.ContentLength <= 0 {
				req.ContentLength = int64(len)
			}
		} else {
			req.Header.Set(k, v)
		}
	}

}

//
// the callback for CheckRedirect, used to pass along the headers in case of redirection
//
func (self *HttpClient) checkRedirect(req *http.Request, via []*http.Request) error {
	if req.Method == "HEAD" {
		// don't follow redirects on a HEAD request
		return NoRedirect
	}

	if self.Verbose {
		log.Println("REDIRECT:", len(via), req.URL)
	}

	if len(via) >= 10 {
		return TooManyRedirects
	}

	// TODO: check for same host before adding headers
	self.addHeaders(req, nil)
	return nil
}

//
// Create a request object given the method, path, body and extra headers
//
func (self *HttpClient) Request(method string, urlpath string, body io.Reader, headers map[string]string) (req *http.Request) {
	if u, err := self.BaseURL.Parse(urlpath); err != nil {
		log.Fatal(err)
	} else {
		urlpath = u.String()
	}

	req, err := http.NewRequest(method, urlpath, body)
	if err != nil {
		log.Fatal(err)
	}

	self.addHeaders(req, headers)
	return
}

//
// Execute request
//
func (self *HttpClient) Do(req *http.Request) (*HttpResponse, error) {
	if self.Verbose {
		log.Println("REQUEST:", req.Method, req.URL, pretty.PrettyFormat(req.Header))
	}

	resp, err := self.client.Do(req)
	if urlerr, ok := err.(*url.Error); ok && urlerr.Err == NoRedirect {
		err = nil // redirect on HEAD is not an error
	}
	if err == nil {
		if self.Verbose {
			log.Println("RESPONSE:", resp.Status, pretty.PrettyFormat(resp.Header))
		}

		return &HttpResponse{*resp}, nil
	} else {
		if self.Verbose {
			log.Println("ERROR:", err, "REQUEST:", req.Method, req.URL, pretty.PrettyFormat(req.Header))
		}

		CloseResponse(resp)
		return nil, err
	}
}

//
// Execute a DELETE request
//
func (self *HttpClient) Delete(path string, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("DELETE", path, nil, headers)
	return self.Do(req)
}

//
// Execute a HEAD request
//
func (self *HttpClient) Head(path string, params map[string]interface{}, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("HEAD", URLWithParams(path, params).String(), nil, headers)
	return self.Do(req)
}

//
// Execute a GET request
//
func (self *HttpClient) Get(path string, params map[string]interface{}, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("GET", URLWithParams(path, params).String(), nil, headers)
	return self.Do(req)
}

//
// Execute a POST request
//
func (self *HttpClient) Post(path string, content io.Reader, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("POST", path, content, headers)
	return self.Do(req)
}

//
// Execute a PUT request
//
func (self *HttpClient) Put(path string, content io.Reader, headers map[string]string) (*HttpResponse, error) {
	req := self.Request("PUT", path, content, headers)
	return self.Do(req)
}
<|endoftext|>


<commit_before>package instructor

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/davecgh/go-spew/spew"
)

// interpreter is a quasi-runtime that holds objects in memory, knows how to find and convert things
// and interprets statements
type interpreter struct {
	finders    finders
	converters converters
	heap       heap
}

// newInterpreter returns a new Instructor
func newInterpreter() *interpreter {
	return &interpreter{
		finders: make(finders),
		heap:    make(heap),
		converters: map[string]Converter{
			"bool":     stringToBool,
			"*bool":    stringToBool,
			"int":      stringToInt,
			"*int":     stringToInt,
			"uint":     stringToUint,
			"*uint":    stringToPUint,
			"float64":  stringToFloat64,
			"*float64": stringToFloat64,
			"string":   stringToString,
			"*string":  stringToString,
		},
	}
}

type statementType int

const (
	INVALID      = iota // 0
	ASSIGNMENT          // 1
	METHODCALL          // 2
	PROPERTYCALL        // 3
	INSPECT             // 4
	LOOKUP              // 5
)

type preparedStatement struct {
	fullStatement statement
	lhs           statement
	rhs           statement
	t             statementType
}

func (i *interpreter) prepareStatement(s statement) (preparedStatement, error) {
	// First thing, lets just make sure no pesky whitespace is hanging around
	s = cleanWhitespace(s)
	ps := preparedStatement{fullStatement: s}
	// Fail fast if it's a simple call to find
	if s[0].token == FIND {
		ps.t = LOOKUP
		ps.lhs = s
		return ps, nil
	}
	// Fail fast if it's just inspecting a variable
	if len(s) == 2 && s[0].token == WORD {
		ps.t = INSPECT
		ps.lhs = s
		return ps, nil
	}
	for i := 0; i < len(s); i++ {
		f := s[i]
		// If there is a singleequal anywhere, this puts us into a lhs = rhs assignment
		if f.token == ASSIGN {
			ps.t = ASSIGNMENT
			ps.lhs = s[0:i]  // Everything on the left of the = is LHS
			ps.rhs = s[i+1:] // Everything +1 the current point is the RHS
			return ps, nil
		} else if f.token == LPAREN {
			// If we haven't hit an assignment but there is a ( somewhere, this is a direct method invocation
			ps.t = METHODCALL
			ps.lhs = s
			return ps, nil
		}
	}
	// If it wasn't a variable inspection, and there were no = or ( found, it must be a property invocation
	ps.t = PROPERTYCALL
	ps.lhs = s
	return ps, nil
}

// Evaluate is a set of rules dictating how the tokens will be interpreted.
func (i *interpreter) Evaluate(s statement) error {
	obj, err := i.evaluateStatement(s)
	if err != nil {
		return err
	}
	spew.Dump(obj)
	return nil
}

// Evaluate is a set of rules dictating how the tokens will be interpreted.
func (i *interpreter) evaluateStatement(s statement) (interface{}, error) {
	ps, err := i.prepareStatement(s)
	if err != nil {
		return nil, err
	}
	switch ps.t {
	case INSPECT:
		obj, err := i.lookupVariable(ps.lhs)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case LOOKUP:
		// Pass from the 4th token on (LPAREN <-> RPAREN : EOF))
		// get back arguments for dynamic finder
		stype, id, err := statementToFindArgs(ps.lhs[1:])
		if err != nil {
			return nil, err
		}
		obj, err := i.find(stype, id)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case METHODCALL:
		chain, args := statementToInvocationChainAndParams(ps.lhs)
		// It's a method invocation
		// The first word in the statement is the variable
		// the next N are the property chains
		// the args are the things to invoke on the method
		obj, err := i.callMethodChain(chain, args)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case PROPERTYCALL:
		chain, _ := statementToInvocationChainAndParams(ps.lhs)
		// It's a property invocation
		// The first word in the statement is the variable
		// the next N are the property chains
		obj, err := i.callPropertyChain(chain)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case ASSIGNMENT:
		// This is the remaining case to port over
		// it's still in the lookup branch below
		// we need to do some recursion here in the new world order
		// send LHS and RHS down the Evaluate tree, and get back their objects
		// then assign RHS to LHS.
		// This requires re-designing Evaluate to return an interface{}, error
		// likely - break this into 2 methods. A wrapper not to be recursed by the
		// caller, and the actual method, which returns an object and an error, for
		// the purposes of being able to be called recursively?
		lhs, err := i.evaluateStatement(ps.lhs)
		initVar := false
		if err != nil && strings.Contains(err.Error(), "Unknown variable") {
			// The left hand side is a variable call, but it hasn't been defined yet
			// we're setting it for the first time
			initVar = true
		} else if err != nil {
			return nil, err
		}
		rhs, err := i.evaluateStatement(ps.rhs)
		if err != nil {
			return nil, err
		}
		if initVar {
			// LHS was a variable that didn't exist
			i.storeInHeap(ps.lhs[0].text, rhs)
		} else {
			// LHS is either an existing variable
			// or
			// a property on something else
			vlhs := reflect.ValueOf(lhs)
			vlhs.Set(reflect.ValueOf(rhs))
		}

		return lhs, nil
	case INVALID:
	default:
		return nil, fmt.Errorf("Error: \"%s\" is not a valid statement", ps.fullStatement)
	}
	return nil, nil
}

func (i *interpreter) callMethodChain(chain statement, args statement) ([]interface{}, error) {
	// No crashing!
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panic: %s\n", err)
		}
	}()
	var err error
	max := len(chain)
	// Get the object to call the method on
	// if max-1 is the last element, and that is the funcion,
	var obj interface{}
	var ok bool
	if max > 2 {
		// if max > 2, then the chain needs to be evaluated to get the object
		// to call the method on. Otherwise, the 2nd fragment is the method, and
		// it's called directly
		obj, err = i.crawlPropertyChain(chain[:max-1])
		if err != nil {
			return nil, err
		}
	} else {
		obj, ok = i.heap[chain[0].text]
		if !ok {
			return nil, fmt.Errorf("Error: Unknown variable %s", chain[0].text)
		}
	}

	// Get the reflect value and look up the method
	v := reflect.ValueOf(obj)
	// Don't do this for methods.. but perhaps we need a ptr/nonptr fallback?
	//if v.Kind() == reflect.Ptr {
	//	v = v.Elem()
	//}
	mname := chain[max-1].text
	m := v.MethodByName(mname)
	mtype := m.Type()

	inputArgs, err := i.statementToArgs(mtype, args)
	if err != nil {
		return nil, err
	}

	// Call the Method with the value args
	r := m.Call(inputArgs)
	results := make([]interface{}, len(r))
	// Print all the results
	for i, rv := range r {
		fmt.Printf("%s[%d] : %v\n", mname, i, rv)
		results[i] = rv.Interface()
	}
	return results, nil
}

func (i *interpreter) crawlPropertyChain(statement statement) (interface{}, error) {
	// No crashing!
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panicxx: %s\n", err)
		}
	}()
	obj, ok := i.heap[statement[0].text]
	if !ok {
		return nil, fmt.Errorf("Error: Unknown variable %s", statement[0].text)
	}
	currentVal := reflect.ValueOf(obj)
	parsingIndex := false
	for _, f := range statement[1:] {
		if f.token != EOF && f.token != PERIOD && f.token != RBRACK {
			if f.token == LBRACK {
				parsingIndex = true
			} else if parsingIndex {
				indexval, err := strconv.Atoi(f.text)
				if err != nil {
					return nil, fmt.Errorf("Error: Unable to use %s as an index value for %v. Original error: %s", f.text, currentVal, err.Error())
				}
				currentVal = currentVal.Index(indexval)
				parsingIndex = false
			} else {
				// We're not dealing with an indexing operation, this is a straight invocation of a property
				// Deref if we're dealing with a pointer
				if currentVal.Kind() == reflect.Ptr {
					currentVal = currentVal.Elem()
				}
				p := currentVal.FieldByName(f.text)
				currentVal = p
			}
		}
	}

	return currentVal.Interface(), nil
}

func (i *interpreter) callPropertyChain(statement statement) (interface{}, error) {
	obj, err := i.crawlPropertyChain(statement)
	if err != nil {
		return nil, err
	}
	fmt.Printf("%+v\n", obj)
	return obj, nil
}

func statementToInvocationChainAndParams(s statement) (statement, statement) {
	chain := make(statement, 0)
	args := make(statement, 0)
	hitParen := false
	for _, f := range s {
		if f.token == LPAREN {
			hitParen = true
			args = append(args, f)
		} else if !hitParen && f.token != PERIOD {
			// We're still in the chain
			chain = append(chain, f)
		} else if hitParen {
			// We're in the method params
			args = append(args, f)
		}
	}
	if hitParen {
		return chain, args
	}
	return chain, nil
}

func statementToFindArgs(s statement) (string, string, error) {
	max := len(s)
	if max == 6 && // Find statement should only have 7 fragements
		s[0].token == LPAREN &&
		s[max-1].token == EOF &&
		s[max-2].token == RPAREN {
		// Valid set of args so far
		return s[1].text, s[3].text, nil
	}
	// TODO re-assemble statement for error message
	return "", "", fmt.Errorf("Error: Invalid set of arguments for Find")
}

func cleanWhitespace(s statement) statement {
	results := make(statement, 0)
	for _, f := range s {
		if f.token != WS {
			results = append(results, f)
		}
	}
	return results
}

// RegisterFinder is for registering one of your custom finders to look up your structs
func (i *interpreter) RegisterFinder(name string, f Finder) {
	i.finders[name] = f
}

// RegisterConverter is for registering one of your custom converters to convert cli arguments to typed values
func (i *interpreter) RegisterConverter(name string, c Converter) {
	i.converters[name] = c
}

func (i *interpreter) storeInHeap(id string, obj interface{}) error {
	// Store record in i.instances
	i.heap[id] = obj

	return nil
}

func (i *interpreter) lookupVariable(s statement) (interface{}, error) {
	f := s[0]
	obj, ok := i.heap[f.text]
	if !ok {
		return nil, fmt.Errorf("Error: %s is not a known variable", f.text)
	}
	return obj, nil
}

// find will find things. It is basically a replacement, all purpose object constructor/retriever
func (i *interpreter) find(stype string, id string) (interface{}, error) {
	var obj interface{}
	var err error
	f := i.finders[stype]
	if f == nil {
		return nil, fmt.Errorf("No lookup method found for type %s", stype)
	}
	if obj, err = f(id); err != nil {
		return nil, err
	}
	return obj, nil
}

func (i *interpreter) statementToArgs(mtype reflect.Type, s statement) ([]reflect.Value, error) {
	// No crashing
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panic: %s\n", err)
		}
	}()
	args := make([]reflect.Value, 0)
	// statement should be of the format LPAREN [WORD WORD COMMA] ... RPAREN EOF
	max := len(s)
	if max == 3 {
		// method with no params, return early
		return args, nil
	}
	wordCount := 0
	// TODO this feels like a super hacky way to do this. Improve it?
	for _, currentfrag := range s {
		if currentfrag.token == WORD {
			// hit a comma, reset
			// Get the type of the argument
			tparts := strings.Split(mtype.In(wordCount).String(), ".")
			atype := tparts[len(tparts)-1] // Get whatever is at the final element of the split
			var c Converter
			var ok bool
			if c, ok = i.converters[atype]; !ok {
				return nil, fmt.Errorf("No converter found for type: %s", atype)
			}
			// Convert, error on not found
			iv, err := c(currentfrag.text)
			if err != nil {
				return nil, fmt.Errorf("Error converting %s %s: %s", currentfrag.text, atype, err.Error())
			}
			// Add to the our list to return
			args = append(args, reflect.ValueOf(iv))
			wordCount++ // Could just take len of args over and over but eh
		}
	}
	return args, nil
}
<commit_msg>fixing bug during x = find call<commit_after>package instructor

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/davecgh/go-spew/spew"
)

// interpreter is a quasi-runtime that holds objects in memory, knows how to find and convert things
// and interprets statements
type interpreter struct {
	finders    finders
	converters converters
	heap       heap
}

// newInterpreter returns a new Instructor
func newInterpreter() *interpreter {
	return &interpreter{
		finders: make(finders),
		heap:    make(heap),
		converters: map[string]Converter{
			"bool":     stringToBool,
			"*bool":    stringToBool,
			"int":      stringToInt,
			"*int":     stringToInt,
			"uint":     stringToUint,
			"*uint":    stringToPUint,
			"float64":  stringToFloat64,
			"*float64": stringToFloat64,
			"string":   stringToString,
			"*string":  stringToString,
		},
	}
}

type statementType int

const (
	INVALID      = iota // 0
	ASSIGNMENT          // 1
	METHODCALL          // 2
	PROPERTYCALL        // 3
	INSPECT             // 4
	LOOKUP              // 5
)

type preparedStatement struct {
	fullStatement statement
	lhs           statement
	rhs           statement
	t             statementType
}

func (i *interpreter) prepareStatement(s statement) (preparedStatement, error) {
	// First thing, lets just make sure no pesky whitespace is hanging around
	s = cleanWhitespace(s)
	ps := preparedStatement{fullStatement: s}
	// Fail fast if it's a simple call to find
	if s[0].token == FIND {
		ps.t = LOOKUP
		ps.lhs = s
		return ps, nil
	}
	// Fail fast if it's just inspecting a variable
	if len(s) == 2 && s[0].token == WORD {
		ps.t = INSPECT
		ps.lhs = s
		return ps, nil
	}
	for i := 0; i < len(s); i++ {
		f := s[i]
		// If there is a singleequal anywhere, this puts us into a lhs = rhs assignment
		if f.token == ASSIGN {
			ps.t = ASSIGNMENT
			ps.lhs = s[0:i]  // Everything on the left of the = is LHS
			ps.rhs = s[i+1:] // Everything +1 the current point is the RHS
			return ps, nil
		} else if f.token == LPAREN {
			// If we haven't hit an assignment but there is a ( somewhere, this is a direct method invocation
			ps.t = METHODCALL
			ps.lhs = s
			return ps, nil
		}
	}
	// If it wasn't a variable inspection, and there were no = or ( found, it must be a property invocation
	ps.t = PROPERTYCALL
	ps.lhs = s
	return ps, nil
}

// Evaluate is a set of rules dictating how the tokens will be interpreted.
func (i *interpreter) Evaluate(s statement) error {
	obj, err := i.evaluateStatement(s)
	if err != nil {
		return err
	}
	spew.Dump(obj)
	return nil
}

// Evaluate is a set of rules dictating how the tokens will be interpreted.
func (i *interpreter) evaluateStatement(s statement) (interface{}, error) {
	ps, err := i.prepareStatement(s)
	if err != nil {
		return nil, err
	}
	switch ps.t {
	case INSPECT:
		obj, err := i.lookupVariable(ps.lhs)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case LOOKUP:
		// Pass from the 4th token on (LPAREN <-> RPAREN : EOF))
		// get back arguments for dynamic finder
		stype, id, err := statementToFindArgs(ps.lhs[1:])
		if err != nil {
			return nil, err
		}
		obj, err := i.find(stype, id)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case METHODCALL:
		chain, args := statementToInvocationChainAndParams(ps.lhs)
		// It's a method invocation
		// The first word in the statement is the variable
		// the next N are the property chains
		// the args are the things to invoke on the method
		obj, err := i.callMethodChain(chain, args)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case PROPERTYCALL:
		chain, _ := statementToInvocationChainAndParams(ps.lhs)
		// It's a property invocation
		// The first word in the statement is the variable
		// the next N are the property chains
		obj, err := i.callPropertyChain(chain)
		if err != nil {
			return nil, err
		}
		return obj, nil
	case ASSIGNMENT:
		// This is the remaining case to port over
		// it's still in the lookup branch below
		// we need to do some recursion here in the new world order
		// send LHS and RHS down the Evaluate tree, and get back their objects
		// then assign RHS to LHS.
		// This requires re-designing Evaluate to return an interface{}, error
		// likely - break this into 2 methods. A wrapper not to be recursed by the
		// caller, and the actual method, which returns an object and an error, for
		// the purposes of being able to be called recursively?
		lhs, err := i.evaluateStatement(ps.lhs)
		initVar := false
		if err != nil && strings.Contains(err.Error(), "Unknown variable") {
			// The left hand side is a variable call, but it hasn't been defined yet
			// we're setting it for the first time
			initVar = true
		} else if err != nil {
			return nil, err
		}
		rhs, err := i.evaluateStatement(ps.rhs)
		if err != nil {
			return nil, err
		}
		if initVar {
			// LHS was a variable that didn't exist
			i.storeInHeap(ps.lhs[0].text, rhs)
			lhs = rhs
		} else {
			// LHS is either an existing variable
			// or
			// a property on something else
			vlhs := reflect.ValueOf(lhs)
			vlhs.Set(reflect.ValueOf(rhs))
		}

		return lhs, nil
	case INVALID:
	default:
		return nil, fmt.Errorf("Error: \"%s\" is not a valid statement", ps.fullStatement)
	}
	return nil, nil
}

func (i *interpreter) callMethodChain(chain statement, args statement) ([]interface{}, error) {
	// No crashing!
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panic: %s\n", err)
		}
	}()
	var err error
	max := len(chain)
	// Get the object to call the method on
	// if max-1 is the last element, and that is the funcion,
	var obj interface{}
	var ok bool
	if max > 2 {
		// if max > 2, then the chain needs to be evaluated to get the object
		// to call the method on. Otherwise, the 2nd fragment is the method, and
		// it's called directly
		obj, err = i.crawlPropertyChain(chain[:max-1])
		if err != nil {
			return nil, err
		}
	} else {
		obj, ok = i.heap[chain[0].text]
		if !ok {
			return nil, fmt.Errorf("Error: Unknown variable %s", chain[0].text)
		}
	}

	// Get the reflect value and look up the method
	v := reflect.ValueOf(obj)
	// Don't do this for methods.. but perhaps we need a ptr/nonptr fallback?
	//if v.Kind() == reflect.Ptr {
	//	v = v.Elem()
	//}
	mname := chain[max-1].text
	m := v.MethodByName(mname)
	mtype := m.Type()

	inputArgs, err := i.statementToArgs(mtype, args)
	if err != nil {
		return nil, err
	}

	// Call the Method with the value args
	r := m.Call(inputArgs)
	results := make([]interface{}, len(r))
	// Print all the results
	for i, rv := range r {
		fmt.Printf("%s[%d] : %v\n", mname, i, rv)
		results[i] = rv.Interface()
	}
	return results, nil
}

func (i *interpreter) crawlPropertyChain(statement statement) (interface{}, error) {
	// No crashing!
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panicxx: %s\n", err)
		}
	}()
	obj, ok := i.heap[statement[0].text]
	if !ok {
		return nil, fmt.Errorf("Error: Unknown variable %s", statement[0].text)
	}
	currentVal := reflect.ValueOf(obj)
	parsingIndex := false
	for _, f := range statement[1:] {
		if f.token != EOF && f.token != PERIOD && f.token != RBRACK {
			if f.token == LBRACK {
				parsingIndex = true
			} else if parsingIndex {
				indexval, err := strconv.Atoi(f.text)
				if err != nil {
					return nil, fmt.Errorf("Error: Unable to use %s as an index value for %v. Original error: %s", f.text, currentVal, err.Error())
				}
				currentVal = currentVal.Index(indexval)
				parsingIndex = false
			} else {
				// We're not dealing with an indexing operation, this is a straight invocation of a property
				// Deref if we're dealing with a pointer
				if currentVal.Kind() == reflect.Ptr {
					currentVal = currentVal.Elem()
				}
				p := currentVal.FieldByName(f.text)
				currentVal = p
			}
		}
	}

	return currentVal.Interface(), nil
}

func (i *interpreter) callPropertyChain(statement statement) (interface{}, error) {
	obj, err := i.crawlPropertyChain(statement)
	if err != nil {
		return nil, err
	}
	fmt.Printf("%+v\n", obj)
	return obj, nil
}

func statementToInvocationChainAndParams(s statement) (statement, statement) {
	chain := make(statement, 0)
	args := make(statement, 0)
	hitParen := false
	for _, f := range s {
		if f.token == LPAREN {
			hitParen = true
			args = append(args, f)
		} else if !hitParen && f.token != PERIOD {
			// We're still in the chain
			chain = append(chain, f)
		} else if hitParen {
			// We're in the method params
			args = append(args, f)
		}
	}
	if hitParen {
		return chain, args
	}
	return chain, nil
}

func statementToFindArgs(s statement) (string, string, error) {
	max := len(s)
	if max == 6 && // Find statement should only have 7 fragements
		s[0].token == LPAREN &&
		s[max-1].token == EOF &&
		s[max-2].token == RPAREN {
		// Valid set of args so far
		return s[1].text, s[3].text, nil
	}
	// TODO re-assemble statement for error message
	return "", "", fmt.Errorf("Error: Invalid set of arguments for Find")
}

func cleanWhitespace(s statement) statement {
	results := make(statement, 0)
	for _, f := range s {
		if f.token != WS {
			results = append(results, f)
		}
	}
	return results
}

// RegisterFinder is for registering one of your custom finders to look up your structs
func (i *interpreter) RegisterFinder(name string, f Finder) {
	i.finders[name] = f
}

// RegisterConverter is for registering one of your custom converters to convert cli arguments to typed values
func (i *interpreter) RegisterConverter(name string, c Converter) {
	i.converters[name] = c
}

func (i *interpreter) storeInHeap(id string, obj interface{}) error {
	// Store record in i.instances
	i.heap[id] = obj

	return nil
}

func (i *interpreter) lookupVariable(s statement) (interface{}, error) {
	f := s[0]
	obj, ok := i.heap[f.text]
	if !ok {
		return nil, fmt.Errorf("Error: %s is not a known variable", f.text)
	}
	return obj, nil
}

// find will find things. It is basically a replacement, all purpose object constructor/retriever
func (i *interpreter) find(stype string, id string) (interface{}, error) {
	var obj interface{}
	var err error
	f := i.finders[stype]
	if f == nil {
		return nil, fmt.Errorf("No lookup method found for type %s", stype)
	}
	if obj, err = f(id); err != nil {
		return nil, err
	}
	return obj, nil
}

func (i *interpreter) statementToArgs(mtype reflect.Type, s statement) ([]reflect.Value, error) {
	// No crashing
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Recovering from panic: %s\n", err)
		}
	}()
	args := make([]reflect.Value, 0)
	// statement should be of the format LPAREN [WORD WORD COMMA] ... RPAREN EOF
	max := len(s)
	if max == 3 {
		// method with no params, return early
		return args, nil
	}
	wordCount := 0
	// TODO this feels like a super hacky way to do this. Improve it?
	for _, currentfrag := range s {
		if currentfrag.token == WORD {
			// hit a comma, reset
			// Get the type of the argument
			tparts := strings.Split(mtype.In(wordCount).String(), ".")
			atype := tparts[len(tparts)-1] // Get whatever is at the final element of the split
			var c Converter
			var ok bool
			if c, ok = i.converters[atype]; !ok {
				return nil, fmt.Errorf("No converter found for type: %s", atype)
			}
			// Convert, error on not found
			iv, err := c(currentfrag.text)
			if err != nil {
				return nil, fmt.Errorf("Error converting %s %s: %s", currentfrag.text, atype, err.Error())
			}
			// Add to the our list to return
			args = append(args, reflect.ValueOf(iv))
			wordCount++ // Could just take len of args over and over but eh
		}
	}
	return args, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	_ "image/png"
	"io"
	"os"

	"image"
	"image/color"
	"sort"
	"strconv"
)

type dpDir image.Point

var (
	east  dpDir
	south dpDir
	west  dpDir
	north dpDir
)

func init() {
	east = dpDir{1, 0}
	south = dpDir{0, 1}
	west = dpDir{-1, 0}
	north = dpDir{0, -1}

}

type ccDir int

const (
	left ccDir = iota
	right
)

// adj returns the four points adjacent to a point.
func adj(p image.Point) [4]image.Point {
	return [4]image.Point{
		{p.X, p.Y + 1},
		{p.X, p.Y - 1},
		{p.X + 1, p.Y},
		{p.X - 1, p.Y},
	}
}

type colorBlock map[image.Point]struct{}

func (cb colorBlock) String() string {
	s := make(sort.StringSlice, len(cb))
	for p, _ := range cb {
		s = append(s, p.String())
	}
	sort.Sort(s)

	return fmt.Sprint(s)
}

func (cb colorBlock) Bounds() (r *image.Rectangle) {
	for p, _ := range cb {
		if r == nil {
			r = &image.Rectangle{p, image.Point{p.X + 1, p.Y + 1}}
		} else {
			newR := image.Rectangle{p, image.Point{p.X + 1, p.Y + 1}}.Union(*r)
			r = &newR
		}
	}
	return
}

type interpreter struct {
	img image.Image
	stack
	dp  dpDir
	cc  ccDir
	pos image.Point
}

func (i interpreter) String() string {
	var dp string
	switch i.dp {
	case east:
		dp = "\u261E"
	case south:
		dp = "\u261F"
	case west:
		dp = "\u261C"
	case north:
		dp = "\u261D"
	}

	var cc string
	switch i.cc {
	case left:
		cc = "<"
	case right:
		cc = ">"
	}

	return fmt.Sprintf("dp:%s, cc:%s, pos:%s", i.pos, dp, cc)
}

func New(img image.Image) interpreter {
	return interpreter{
		img: img,
		dp:  east,
		cc:  left,
		pos: img.Bounds().Min,
	}
}

func (i interpreter) color() color.Color {
	return i.img.At(i.pos.X, i.pos.Y)
}

func (i *interpreter) rotateDp() {
	switch i.dp {
	case east:
		i.dp = south
	case south:
		i.dp = west
	case west:
		i.dp = north
	case north:
		i.dp = east
	}
}

func (i *interpreter) pointer() {
	count := i.pop()
	if count < 0 {
		panic("negative count not implemented")
	}
	for j := 0; j < count; j++ {
		i.rotateDp()
	}
}

func (i *interpreter) switchCc() {
	count := i.pop()
	if count < 0 {
		count = -count
	}
	if count%2 == 1 {
		i.toggleCc()
	}
}

func (i *interpreter) toggleCc() {
	if i.cc == left {
		i.cc = right
	} else {
		i.cc = left
	}
}

// TODO switch from os.Std* to letting the caller pass their own streams
func (i *interpreter) inNum() {
	panic("not implemented")
}

func (i *interpreter) inChar() {
	panic("not implemented")
}

func (i *interpreter) outNum() {
	io.WriteString(os.Stdout, strconv.Itoa(i.pop()))
}

func (i *interpreter) outChar() {
	os.Stdout.Write([]byte{byte(i.pop())})
}

// getColorBlock returns the current color block.
func (i *interpreter) getColorBlock() (block colorBlock) {
	currentColor := i.color()
	block = map[image.Point]struct{}{
		i.pos: struct{}{},
	}
	// very naive implementation currently. At the very least we should be able
	// to cache the current block.
	done := false
	for !done {
		done = true
		for pos, _ := range block {
			for _, newPos := range adj(pos) {
				if newPos.In(i.img.Bounds()) {
					_, inBlock := block[newPos]
					if !inBlock && sameColors(i.img.At(newPos.X, newPos.Y), currentColor) {
						block[newPos] = struct{}{}
						done = false
					}
				}
			}
		}
	}
	return
}

// Whether the interpreter is currently able to move, without changing its DP or CC.
func (i interpreter) canMove() bool {
	newPos := i.pos.Add(image.Point(i.dp))
	return newPos.In(i.img.Bounds()) &&
		!sameColors(color.Black, i.img.At(newPos.X, newPos.Y))
}

// move causes the interpreter to attempt execute a single move.
// Returns whether the move was successful.
func (i *interpreter) move() bool {
	// First, move to the edge of the current block.
	i.moveWithinBlock()
	// Then, try to move into the next block.
	if i.canMove() {
		newPos := i.pos.Add(image.Point(i.dp))
		oldColor := i.color()
		blockSize := len(i.getColorBlock())

		i.pos = newPos
		i.colorChange(oldColor, blockSize)

		return true
	}

	return i.recovery()
}

func (i *interpreter) recovery() bool {
	originalDp := i.dp
	originalCc := i.cc

	// When true, toggle the CC. When false, rotate the DP.
	cc := true

	for !i.canMove() {
		if cc {
			i.toggleCc()
		} else {
			i.rotateDp()
		}
		if i.dp == originalDp && i.cc == originalCc {
			return false
		}

		i.moveWithinBlock()
		cc = !cc
	}

	return true
}

// hue: 0=red, 1=yellow, etc.
// lightness: 0=light, 1=normal, 2=dark
func colorInfo(c color.Color) (hue, lightness int) {
	r, g, b, _ := c.RGBA()
	switch {
	case r == 0xFFFF && g == 0xFFFF && b == 0xFFFF:
		fallthrough
	case r == 0x0000 && g == 0x0000 && b == 0x0000:
		panic("No color info for white or black")

	case r == 0xFFFF && g == 0xC0C0 && b == 0xC0C0:
		return 0, 0
	case r == 0xFFFF && g == 0xFFFF && b == 0xC0C0:
		return 1, 0
	case r == 0xC0C0 && g == 0xFFFF && b == 0xC0C0:
		return 2, 0
	case r == 0xC0C0 && g == 0xFFFF && b == 0xFFFF:
		return 3, 0
	case r == 0xC0C0 && g == 0xC0C0 && b == 0xFFFF:
		return 4, 0
	case r == 0xFFFF && g == 0xC0C0 && b == 0xFFFF:
		return 5, 0

	case r == 0xFFFF && g == 0x0000 && b == 0x0000:
		return 0, 1
	case r == 0xFFFF && g == 0xFFFF && b == 0x0000:
		return 1, 1
	case r == 0x0000 && g == 0xFFFF && b == 0x0000:
		return 2, 1
	case r == 0x0000 && g == 0xFFFF && b == 0xFFFF:
		return 3, 1
	case r == 0x0000 && g == 0x0000 && b == 0xFFFF:
		return 4, 1
	case r == 0xFFFF && g == 0x0000 && b == 0xFFFF:
		return 5, 1

	case r == 0xC0C0 && g == 0x0000 && b == 0x0000:
		return 0, 2
	case r == 0xC0C0 && g == 0xC0C0 && b == 0x0000:
		return 1, 2
	case r == 0x0000 && g == 0xC0C0 && b == 0x0000:
		return 2, 2
	case r == 0x0000 && g == 0xC0C0 && b == 0xC0C0:
		return 3, 2
	case r == 0x0000 && g == 0x0000 && b == 0xC0C0:
		return 4, 2
	case r == 0xC0C0 && g == 0x0000 && b == 0xC0C0:
		return 5, 2
	default:
		panic(c)
	}
}

// Called when the color changes to cause the interpreter to do things.
func (i *interpreter) colorChange(prevColor color.Color, blockSize int) {
	if sameColors(color.White, prevColor) || sameColors(color.White, i.color()) {
		return
	}

	oldHue, oldLightness := colorInfo(prevColor)
	newHue, newLightness := colorInfo(i.color())

	hueChange := (newHue - oldHue + 6) % 6
	lightnessChange := (newLightness - oldLightness + 3) % 3

	switch lightnessChange {
	case 0:
		switch hueChange {
		case 1:
			i.add()
		case 2:
			i.divide()
		case 3:
			i.greater()
		case 4:
			i.duplicate()
		case 5:
			i.inChar()
		}
	case 1:
		switch hueChange {
		case 0:
			i.push(blockSize)
		case 1:
			i.subtract()
		case 2:
			i.mod()
		case 3:
			i.pointer()
		case 4:
			i.roll()
		case 5:
			i.outNum()
		}
	case 2:
		switch hueChange {
		case 0:
			i.pop()
		case 1:
			i.multiply()
		case 2:
			i.not()
		case 3:
			i.switchCc()
		case 4:
			i.inNum()
		case 5:
			i.outChar()
		}
	}
}

func (i *interpreter) run() {
	for i.move() {
	}
}

func (i *interpreter) moveWithinBlock() {
	if sameColors(color.White, i.color()) {
		newPos := i.pos.Add(image.Point(i.dp))
		for sameColors(color.White, i.img.At(newPos.X, newPos.Y)) {
			i.pos = newPos
			newPos = i.pos.Add(image.Point(i.dp))
		}
		return
	}

	var newPos *image.Point
	block := i.getColorBlock()
	bounds := block.Bounds()

	switch i.dp {
	case east:
		for p, _ := range block {
			if p.X == bounds.Max.X-1 {
				if newPos == nil ||
					i.cc == left && p.Y < newPos.Y ||
					i.cc == right && p.Y > newPos.Y {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case south:
		for p, _ := range block {
			if p.Y == bounds.Max.Y-1 {
				if newPos == nil ||
					i.cc == left && p.X > newPos.X ||
					i.cc == right && p.X < newPos.X {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case west:
		for p, _ := range block {
			if p.X == bounds.Min.X {
				if newPos == nil ||
					i.cc == left && p.Y > newPos.Y ||
					i.cc == right && p.Y < newPos.Y {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case north:
		for p, _ := range block {
			if p.Y == bounds.Min.Y {
				if newPos == nil ||
					i.cc == left && p.X < newPos.X ||
					i.cc == right && p.X > newPos.X {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	}
	i.pos = *newPos
}

func sameColors(c1, c2 color.Color) bool {
	r1, g1, b1, _ := c1.RGBA()
	r2, g2, b2, _ := c2.RGBA()
	return r1 == r2 &&
		g1 == g2 &&
		b1 == b2
}
<commit_msg>make Bounds return a Rect instead of a *Rect<commit_after>package main

import (
	"fmt"
	_ "image/png"
	"io"
	"os"

	"image"
	"image/color"
	"sort"
	"strconv"
)

type dpDir image.Point

var (
	east  dpDir
	south dpDir
	west  dpDir
	north dpDir
)

func init() {
	east = dpDir{1, 0}
	south = dpDir{0, 1}
	west = dpDir{-1, 0}
	north = dpDir{0, -1}

}

type ccDir int

const (
	left ccDir = iota
	right
)

// adj returns the four points adjacent to a point.
func adj(p image.Point) [4]image.Point {
	return [4]image.Point{
		{p.X, p.Y + 1},
		{p.X, p.Y - 1},
		{p.X + 1, p.Y},
		{p.X - 1, p.Y},
	}
}

type colorBlock map[image.Point]struct{}

func (cb colorBlock) String() string {
	s := make(sort.StringSlice, len(cb))
	for p, _ := range cb {
		s = append(s, p.String())
	}
	sort.Sort(s)

	return fmt.Sprint(s)
}

func (cb colorBlock) Bounds() (r image.Rectangle) {
	for p, _ := range cb {
		r = image.Rectangle{p, image.Point{p.X + 1, p.Y + 1}}
		break
	}
	for p, _ := range cb {
		r = r.Union(image.Rectangle{p, image.Point{p.X + 1, p.Y + 1}})
	}
	return
}

type interpreter struct {
	img image.Image
	stack
	dp  dpDir
	cc  ccDir
	pos image.Point
}

func (i interpreter) String() string {
	var dp string
	switch i.dp {
	case east:
		dp = "\u261E"
	case south:
		dp = "\u261F"
	case west:
		dp = "\u261C"
	case north:
		dp = "\u261D"
	}

	var cc string
	switch i.cc {
	case left:
		cc = "<"
	case right:
		cc = ">"
	}

	return fmt.Sprintf("dp:%s, cc:%s, pos:%s", i.pos, dp, cc)
}

func New(img image.Image) interpreter {
	return interpreter{
		img: img,
		dp:  east,
		cc:  left,
		pos: img.Bounds().Min,
	}
}

func (i interpreter) color() color.Color {
	return i.img.At(i.pos.X, i.pos.Y)
}

func (i *interpreter) rotateDp() {
	switch i.dp {
	case east:
		i.dp = south
	case south:
		i.dp = west
	case west:
		i.dp = north
	case north:
		i.dp = east
	}
}

func (i *interpreter) pointer() {
	count := i.pop()
	if count < 0 {
		panic("negative count not implemented")
	}
	for j := 0; j < count; j++ {
		i.rotateDp()
	}
}

func (i *interpreter) switchCc() {
	count := i.pop()
	if count < 0 {
		count = -count
	}
	if count%2 == 1 {
		i.toggleCc()
	}
}

func (i *interpreter) toggleCc() {
	if i.cc == left {
		i.cc = right
	} else {
		i.cc = left
	}
}

// TODO switch from os.Std* to letting the caller pass their own streams
func (i *interpreter) inNum() {
	panic("not implemented")
}

func (i *interpreter) inChar() {
	panic("not implemented")
}

func (i *interpreter) outNum() {
	io.WriteString(os.Stdout, strconv.Itoa(i.pop()))
}

func (i *interpreter) outChar() {
	os.Stdout.Write([]byte{byte(i.pop())})
}

// getColorBlock returns the current color block.
func (i *interpreter) getColorBlock() (block colorBlock) {
	currentColor := i.color()
	block = map[image.Point]struct{}{
		i.pos: struct{}{},
	}
	// very naive implementation currently. At the very least we should be able
	// to cache the current block.
	done := false
	for !done {
		done = true
		for pos, _ := range block {
			for _, newPos := range adj(pos) {
				if newPos.In(i.img.Bounds()) {
					_, inBlock := block[newPos]
					if !inBlock && sameColors(i.img.At(newPos.X, newPos.Y), currentColor) {
						block[newPos] = struct{}{}
						done = false
					}
				}
			}
		}
	}
	return
}

// Whether the interpreter is currently able to move, without changing its DP or CC.
func (i interpreter) canMove() bool {
	newPos := i.pos.Add(image.Point(i.dp))
	return newPos.In(i.img.Bounds()) &&
		!sameColors(color.Black, i.img.At(newPos.X, newPos.Y))
}

// move causes the interpreter to attempt execute a single move.
// Returns whether the move was successful.
func (i *interpreter) move() bool {
	// First, move to the edge of the current block.
	i.moveWithinBlock()
	// Then, try to move into the next block.
	if i.canMove() {
		newPos := i.pos.Add(image.Point(i.dp))
		oldColor := i.color()
		blockSize := len(i.getColorBlock())

		i.pos = newPos
		i.colorChange(oldColor, blockSize)

		return true
	}

	return i.recovery()
}

func (i *interpreter) recovery() bool {
	originalDp := i.dp
	originalCc := i.cc

	// When true, toggle the CC. When false, rotate the DP.
	cc := true

	for !i.canMove() {
		if cc {
			i.toggleCc()
		} else {
			i.rotateDp()
		}
		if i.dp == originalDp && i.cc == originalCc {
			return false
		}

		i.moveWithinBlock()
		cc = !cc
	}

	return true
}

// hue: 0=red, 1=yellow, etc.
// lightness: 0=light, 1=normal, 2=dark
func colorInfo(c color.Color) (hue, lightness int) {
	r, g, b, _ := c.RGBA()
	switch {
	case r == 0xFFFF && g == 0xFFFF && b == 0xFFFF:
		fallthrough
	case r == 0x0000 && g == 0x0000 && b == 0x0000:
		panic("No color info for white or black")

	case r == 0xFFFF && g == 0xC0C0 && b == 0xC0C0:
		return 0, 0
	case r == 0xFFFF && g == 0xFFFF && b == 0xC0C0:
		return 1, 0
	case r == 0xC0C0 && g == 0xFFFF && b == 0xC0C0:
		return 2, 0
	case r == 0xC0C0 && g == 0xFFFF && b == 0xFFFF:
		return 3, 0
	case r == 0xC0C0 && g == 0xC0C0 && b == 0xFFFF:
		return 4, 0
	case r == 0xFFFF && g == 0xC0C0 && b == 0xFFFF:
		return 5, 0

	case r == 0xFFFF && g == 0x0000 && b == 0x0000:
		return 0, 1
	case r == 0xFFFF && g == 0xFFFF && b == 0x0000:
		return 1, 1
	case r == 0x0000 && g == 0xFFFF && b == 0x0000:
		return 2, 1
	case r == 0x0000 && g == 0xFFFF && b == 0xFFFF:
		return 3, 1
	case r == 0x0000 && g == 0x0000 && b == 0xFFFF:
		return 4, 1
	case r == 0xFFFF && g == 0x0000 && b == 0xFFFF:
		return 5, 1

	case r == 0xC0C0 && g == 0x0000 && b == 0x0000:
		return 0, 2
	case r == 0xC0C0 && g == 0xC0C0 && b == 0x0000:
		return 1, 2
	case r == 0x0000 && g == 0xC0C0 && b == 0x0000:
		return 2, 2
	case r == 0x0000 && g == 0xC0C0 && b == 0xC0C0:
		return 3, 2
	case r == 0x0000 && g == 0x0000 && b == 0xC0C0:
		return 4, 2
	case r == 0xC0C0 && g == 0x0000 && b == 0xC0C0:
		return 5, 2
	default:
		panic(c)
	}
}

// Called when the color changes to cause the interpreter to do things.
func (i *interpreter) colorChange(prevColor color.Color, blockSize int) {
	if sameColors(color.White, prevColor) || sameColors(color.White, i.color()) {
		return
	}

	oldHue, oldLightness := colorInfo(prevColor)
	newHue, newLightness := colorInfo(i.color())

	hueChange := (newHue - oldHue + 6) % 6
	lightnessChange := (newLightness - oldLightness + 3) % 3

	switch lightnessChange {
	case 0:
		switch hueChange {
		case 1:
			i.add()
		case 2:
			i.divide()
		case 3:
			i.greater()
		case 4:
			i.duplicate()
		case 5:
			i.inChar()
		}
	case 1:
		switch hueChange {
		case 0:
			i.push(blockSize)
		case 1:
			i.subtract()
		case 2:
			i.mod()
		case 3:
			i.pointer()
		case 4:
			i.roll()
		case 5:
			i.outNum()
		}
	case 2:
		switch hueChange {
		case 0:
			i.pop()
		case 1:
			i.multiply()
		case 2:
			i.not()
		case 3:
			i.switchCc()
		case 4:
			i.inNum()
		case 5:
			i.outChar()
		}
	}
}

func (i *interpreter) run() {
	for i.move() {
	}
}

func (i *interpreter) moveWithinBlock() {
	if sameColors(color.White, i.color()) {
		newPos := i.pos.Add(image.Point(i.dp))
		for sameColors(color.White, i.img.At(newPos.X, newPos.Y)) {
			i.pos = newPos
			newPos = i.pos.Add(image.Point(i.dp))
		}
		return
	}

	var newPos *image.Point
	block := i.getColorBlock()
	bounds := block.Bounds()

	switch i.dp {
	case east:
		for p, _ := range block {
			if p.X == bounds.Max.X-1 {
				if newPos == nil ||
					i.cc == left && p.Y < newPos.Y ||
					i.cc == right && p.Y > newPos.Y {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case south:
		for p, _ := range block {
			if p.Y == bounds.Max.Y-1 {
				if newPos == nil ||
					i.cc == left && p.X > newPos.X ||
					i.cc == right && p.X < newPos.X {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case west:
		for p, _ := range block {
			if p.X == bounds.Min.X {
				if newPos == nil ||
					i.cc == left && p.Y > newPos.Y ||
					i.cc == right && p.Y < newPos.Y {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	case north:
		for p, _ := range block {
			if p.Y == bounds.Min.Y {
				if newPos == nil ||
					i.cc == left && p.X < newPos.X ||
					i.cc == right && p.X > newPos.X {
					newPos = &image.Point{p.X, p.Y}
				}
			}
		}
	}
	i.pos = *newPos
}

func sameColors(c1, c2 color.Color) bool {
	r1, g1, b1, _ := c1.RGBA()
	r2, g2, b2, _ := c2.RGBA()
	return r1 == r2 &&
		g1 == g2 &&
		b1 == b2
}
<|endoftext|>


<commit_before>package commandline

import "strings"

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type scanner struct {
	src []byte
}

func (s scanner) scan() {
}

type tokenType int

type token struct {
	tt tokenType
}

const (
	ident tokenType = iota
)
<commit_msg>Add 'str'<commit_after>package commandline

import "strings"

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type scanner struct {
	src []byte
}

func (s scanner) scan() {
}

type tokenType int

type token struct {
	tt tokenType
}

const (
	ident tokenType = iota
	str
)
<|endoftext|>


<commit_before>package commandline

import (
	"errors"
	"fmt"
	"strings"
)

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type scanner struct {
	src  []byte
	size int
	off  int
}

func newScanner(src []byte) *scanner {
	return &scanner{
		src:  src,
		size: len(src),
	}
}

func (s *scanner) next() (byte, bool) {
	if s.off >= s.size {
		return 0, true
	}

	ret := s.src[s.off]

	s.off++
	return ret, false
}

func (s *scanner) scan() (*token, error) {
	ch, eof := s.next()
	if eof {
		return nil, nil
	}
	switch {
	case isIdent(ch):
		var ret []byte
		for isIdent(ch) {
			ch, eof = s.next()
			if eof {
				break
			}
			ret = append(ret, ch)
		}
		return &token{tt: ident, value: ret}, nil
	case ch == '"':
		var ret []byte
		for ch != '"' {
			ch, eof = s.next()
			if eof {
				return nil, errors.New("unexpected eof in string literal")
			}
			ret = append(ret, ch)
		}
		return &token{tt: str, value: ret}, nil
	case isWhitespace(ch):
		return s.scan()
	}
	return nil, fmt.Errorf("unexpected character at offset: %d", s.off)
}

func isWhitespace(b byte) bool {
	return b == ' '
}

func isIdent(b byte) bool {
	return 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z'
}

type tokenType int

type token struct {
	tt    tokenType
	value []byte
}

const (
	ident tokenType = iota
	str
)
<commit_msg>Improve error message<commit_after>package commandline

import (
	"fmt"
	"strings"
)

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type scanner struct {
	src  []byte
	size int
	off  int
}

func newScanner(src []byte) *scanner {
	return &scanner{
		src:  src,
		size: len(src),
	}
}

func (s *scanner) next() (byte, bool) {
	if s.off >= s.size {
		return 0, true
	}

	ret := s.src[s.off]

	s.off++
	return ret, false
}

func (s *scanner) scan() (*token, error) {
	ch, eof := s.next()
	if eof {
		return nil, nil
	}
	switch {
	case isIdent(ch):
		var ret []byte
		for isIdent(ch) {
			ch, eof = s.next()
			if eof {
				break
			}
			ret = append(ret, ch)
		}
		return &token{tt: ident, value: ret}, nil
	case ch == '"':
		var ret []byte
		for ch != '"' {
			ch, eof = s.next()
			if eof {
				return nil, fmt.Errorf("unexpected eof in string literal at offset: %d", s.off)
			}
			ret = append(ret, ch)
		}
		return &token{tt: str, value: ret}, nil
	case isWhitespace(ch):
		return s.scan()
	}
	return nil, fmt.Errorf("unexpected character at offset: %d", s.off)
}

func isWhitespace(b byte) bool {
	return b == ' '
}

func isIdent(b byte) bool {
	return 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z'
}

type tokenType int

type token struct {
	tt    tokenType
	value []byte
}

const (
	ident tokenType = iota
	str
)
<|endoftext|>


<commit_before>package conn

import (
	"fmt"
	"net"
	"time"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
	mpool "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"

	ic "github.com/jbenet/go-ipfs/p2p/crypto"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	u "github.com/jbenet/go-ipfs/util"
	debugerr "github.com/jbenet/go-ipfs/util/debugerror"
)

var log = eventlog.Logger("conn")

// ReleaseBuffer puts the given byte array back into the buffer pool,
// first verifying that it is the correct size
func ReleaseBuffer(b []byte) {
	log.Debugf("Releasing buffer! (cap,size = %d, %d)", cap(b), len(b))
	mpool.ByteSlicePool.Put(uint32(cap(b)), b)
}

// singleConn represents a single connection to another Peer (IPFS Node).
type singleConn struct {
	local  peer.ID
	remote peer.ID
	maconn manet.Conn
	msgrw  msgio.ReadWriteCloser
}

// newConn constructs a new connection
func newSingleConn(ctx context.Context, local, remote peer.ID, maconn manet.Conn) (Conn, error) {

	conn := &singleConn{
		local:  local,
		remote: remote,
		maconn: maconn,
		msgrw:  msgio.NewReadWriter(maconn),
	}

	log.Debugf("newSingleConn %p: %v to %v", conn, local, remote)
	return conn, nil
}

// close is the internal close function, called by ContextCloser.Close
func (c *singleConn) Close() error {
	log.Debug(debugerr.Errorf("%s closing Conn with %s", c.local, c.remote))
	// close underlying connection
	return c.msgrw.Close()
}

// ID is an identifier unique to this connection.
func (c *singleConn) ID() string {
	return ID(c)
}

func (c *singleConn) String() string {
	return String(c, "singleConn")
}

func (c *singleConn) LocalAddr() net.Addr {
	return c.maconn.LocalAddr()
}

func (c *singleConn) RemoteAddr() net.Addr {
	return c.maconn.RemoteAddr()
}

func (c *singleConn) LocalPrivateKey() ic.PrivKey {
	return nil
}

func (c *singleConn) RemotePublicKey() ic.PubKey {
	return nil
}

func (c *singleConn) SetDeadline(t time.Time) error {
	return c.maconn.SetDeadline(t)
}
func (c *singleConn) SetReadDeadline(t time.Time) error {
	return c.maconn.SetReadDeadline(t)
}

func (c *singleConn) SetWriteDeadline(t time.Time) error {
	return c.maconn.SetWriteDeadline(t)
}

// LocalMultiaddr is the Multiaddr on this side
func (c *singleConn) LocalMultiaddr() ma.Multiaddr {
	return c.maconn.LocalMultiaddr()
}

// RemoteMultiaddr is the Multiaddr on the remote side
func (c *singleConn) RemoteMultiaddr() ma.Multiaddr {
	return c.maconn.RemoteMultiaddr()
}

// LocalPeer is the Peer on this side
func (c *singleConn) LocalPeer() peer.ID {
	return c.local
}

// RemotePeer is the Peer on the remote side
func (c *singleConn) RemotePeer() peer.ID {
	return c.remote
}

// Read reads data, net.Conn style
func (c *singleConn) Read(buf []byte) (int, error) {
	return c.msgrw.Read(buf)
}

// Write writes data, net.Conn style
func (c *singleConn) Write(buf []byte) (int, error) {
	return c.msgrw.Write(buf)
}

func (c *singleConn) NextMsgLen() (int, error) {
	return c.msgrw.NextMsgLen()
}

// ReadMsg reads data, net.Conn style
func (c *singleConn) ReadMsg() ([]byte, error) {
	return c.msgrw.ReadMsg()
}

// WriteMsg writes data, net.Conn style
func (c *singleConn) WriteMsg(buf []byte) error {
	return c.msgrw.WriteMsg(buf)
}

// ReleaseMsg releases a buffer
func (c *singleConn) ReleaseMsg(m []byte) {
	c.msgrw.ReleaseMsg(m)
}

// ID returns the ID of a given Conn.
func ID(c Conn) string {
	l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty())
	r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty())
	lh := u.Hash([]byte(l))
	rh := u.Hash([]byte(r))
	ch := u.XOR(lh, rh)
	return u.Key(ch).Pretty()
}

// String returns the user-friendly String representation of a conn
func String(c Conn, typ string) string {
	return fmt.Sprintf("%s (%s) <-- %s %p --> (%s) %s",
		c.LocalPeer(), c.LocalMultiaddr(), typ, c, c.RemoteMultiaddr(), c.RemotePeer())
}
<commit_msg>p2p/net/conn: log conn lifetime event<commit_after>package conn

import (
	"fmt"
	"io"
	"net"
	"time"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
	mpool "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"

	ic "github.com/jbenet/go-ipfs/p2p/crypto"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	u "github.com/jbenet/go-ipfs/util"
	lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
)

var log = eventlog.Logger("conn")

// ReleaseBuffer puts the given byte array back into the buffer pool,
// first verifying that it is the correct size
func ReleaseBuffer(b []byte) {
	log.Debugf("Releasing buffer! (cap,size = %d, %d)", cap(b), len(b))
	mpool.ByteSlicePool.Put(uint32(cap(b)), b)
}

// singleConn represents a single connection to another Peer (IPFS Node).
type singleConn struct {
	local  peer.ID
	remote peer.ID
	maconn manet.Conn
	msgrw  msgio.ReadWriteCloser
	event  io.Closer
}

// newConn constructs a new connection
func newSingleConn(ctx context.Context, local, remote peer.ID, maconn manet.Conn) (Conn, error) {
	ml := lgbl.Dial("conn", local, remote, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())

	conn := &singleConn{
		local:  local,
		remote: remote,
		maconn: maconn,
		msgrw:  msgio.NewReadWriter(maconn),
		event:  log.EventBegin(ctx, "connLifetime", ml),
	}

	log.Debugf("newSingleConn %p: %v to %v", conn, local, remote)
	return conn, nil
}

// close is the internal close function, called by ContextCloser.Close
func (c *singleConn) Close() error {
	defer func() {
		if c.event != nil {
			c.event.Close()
			c.event = nil
		}
	}()

	// close underlying connection
	return c.msgrw.Close()
}

// ID is an identifier unique to this connection.
func (c *singleConn) ID() string {
	return ID(c)
}

func (c *singleConn) String() string {
	return String(c, "singleConn")
}

func (c *singleConn) LocalAddr() net.Addr {
	return c.maconn.LocalAddr()
}

func (c *singleConn) RemoteAddr() net.Addr {
	return c.maconn.RemoteAddr()
}

func (c *singleConn) LocalPrivateKey() ic.PrivKey {
	return nil
}

func (c *singleConn) RemotePublicKey() ic.PubKey {
	return nil
}

func (c *singleConn) SetDeadline(t time.Time) error {
	return c.maconn.SetDeadline(t)
}
func (c *singleConn) SetReadDeadline(t time.Time) error {
	return c.maconn.SetReadDeadline(t)
}

func (c *singleConn) SetWriteDeadline(t time.Time) error {
	return c.maconn.SetWriteDeadline(t)
}

// LocalMultiaddr is the Multiaddr on this side
func (c *singleConn) LocalMultiaddr() ma.Multiaddr {
	return c.maconn.LocalMultiaddr()
}

// RemoteMultiaddr is the Multiaddr on the remote side
func (c *singleConn) RemoteMultiaddr() ma.Multiaddr {
	return c.maconn.RemoteMultiaddr()
}

// LocalPeer is the Peer on this side
func (c *singleConn) LocalPeer() peer.ID {
	return c.local
}

// RemotePeer is the Peer on the remote side
func (c *singleConn) RemotePeer() peer.ID {
	return c.remote
}

// Read reads data, net.Conn style
func (c *singleConn) Read(buf []byte) (int, error) {
	return c.msgrw.Read(buf)
}

// Write writes data, net.Conn style
func (c *singleConn) Write(buf []byte) (int, error) {
	return c.msgrw.Write(buf)
}

func (c *singleConn) NextMsgLen() (int, error) {
	return c.msgrw.NextMsgLen()
}

// ReadMsg reads data, net.Conn style
func (c *singleConn) ReadMsg() ([]byte, error) {
	return c.msgrw.ReadMsg()
}

// WriteMsg writes data, net.Conn style
func (c *singleConn) WriteMsg(buf []byte) error {
	return c.msgrw.WriteMsg(buf)
}

// ReleaseMsg releases a buffer
func (c *singleConn) ReleaseMsg(m []byte) {
	c.msgrw.ReleaseMsg(m)
}

// ID returns the ID of a given Conn.
func ID(c Conn) string {
	l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty())
	r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty())
	lh := u.Hash([]byte(l))
	rh := u.Hash([]byte(r))
	ch := u.XOR(lh, rh)
	return u.Key(ch).Pretty()
}

// String returns the user-friendly String representation of a conn
func String(c Conn, typ string) string {
	return fmt.Sprintf("%s (%s) <-- %s %p --> (%s) %s",
		c.LocalPeer(), c.LocalMultiaddr(), typ, c, c.RemoteMultiaddr(), c.RemotePeer())
}
<|endoftext|>


<commit_before>//utils of network
package net

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"regexp"
)

var (
	gateWayExp  = regexp.MustCompile(`(?m)^(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s*$`)
	ErrNotFound = errors.New("NOT FOUND")
)

func netHexToIPAddr(s string) net.IP {
	var v uint32
	fmt.Scanf(s, "%x", &v)
	ipstr := fmt.Sprintf("%d.%d.%d.%d",
		v&0xFF, (v>>8)&0xFF, (v>>16)&0xFF, (v>>24)&0xFF)
	return net.ParseIP(ipstr)
}

func netHexToIPMask(s string) net.IPMask {
	var v uint32
	fmt.Scanf(s, "%x", &v)
	return net.IPv4Mask(byte(v&0xFF), byte((v>>8)&0xFF),
		byte((v>>16)&0xFF), byte((v>>24)&0xFF))
}

func GetDefaultGateWay() (net.IP, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return "", err
	}
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)
	if len(matched) > 0 {
		//skip title line
		for i := 1; i < len(matched); i++ {
			item := &RouteItem{}
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)

			if item.Dst.String() == "0.0.0.0" {
				return item.Gateway, nil
			}
		}
	}

	return net.ParseIP("0.0.0.0"), ErrNotFound
}

func GetGateWayByNic(nicName string) (net.IP, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return "", err
	}
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)
	if len(matched) > 0 {
		//skip title line
		for i := 1; i < len(matched); i++ {
			item := &RouteItem{}
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)
			if nic == nicName {
				return item.Gateway
			}
		}
	}

	return "", ErrNotFound
}

func ListGateWay() ([]*RouteItem, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return nil, err
	}
	var ret []*RouteItem
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)

	//Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT
	if len(matched) > 0 {
		//skip title line

		for i := 1; i < len(matched); i++ {
			item := new(RouteItem)
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)

			voff++
			flags := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(flags, "%d", &item.Flags)

			voff++
			refCnt := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(refCnt, "%d", &item.RefCnt)

			voff++
			use := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(Use, "%d", &item.Use)

			voff++
			metric := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(metric, "%d", &item.Metric)

			voff++
			mask := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			maskValue := netHexToIPAddrValue(mask)
			item.Mask = net.IPv4Mask(maskValue&0xFF, (maskValue>>8)&0xFF,
				(maskValue>>16)&0xFF, (maskValue>>24)&0xFF)

			voff++
			mtu := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(mtu, "%d", &item.MTU)

			voff++
			window := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(window, "%d", &item.Window)

			voff++
			irtt := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(irtt, "%d", &item.IRTT)

			ret = append(ret, item)
		}
		return ret, nil
	}

	return ret, ErrNotFound
}
<commit_msg>fix build<commit_after>//utils of network
package net

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"regexp"
)

var (
	gateWayExp  = regexp.MustCompile(`(?m)^(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s*$`)
	ErrNotFound = errors.New("NOT FOUND")
)

func netHexToIPAddr(s string) net.IP {
	var v uint32
	fmt.Scanf(s, "%x", &v)
	ipstr := fmt.Sprintf("%d.%d.%d.%d",
		v&0xFF, (v>>8)&0xFF, (v>>16)&0xFF, (v>>24)&0xFF)
	return net.ParseIP(ipstr)
}

func netHexToIPMask(s string) net.IPMask {
	var v uint32
	fmt.Scanf(s, "%x", &v)
	return net.IPv4Mask(byte(v&0xFF), byte((v>>8)&0xFF),
		byte((v>>16)&0xFF), byte((v>>24)&0xFF))
}

func GetDefaultGateWay() (net.IP, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return net.ParseIP("0.0.0.0"), err
	}
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)
	if len(matched) > 0 {
		//skip title line
		for i := 1; i < len(matched); i++ {
			item := &RouteItem{}
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)

			if item.Dst.String() == "0.0.0.0" {
				return item.Gateway, nil
			}
		}
	}

	return net.ParseIP("0.0.0.0"), ErrNotFound
}

func GetGateWayByNic(nicName string) (net.IP, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return net.ParseIP("0.0.0.0"), err
	}
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)
	if len(matched) > 0 {
		//skip title line
		for i := 1; i < len(matched); i++ {
			item := &RouteItem{}
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)
			if item.Iface == nicName {
				return item.Gateway, nil
			}
		}
	}

	return net.ParseIP("0.0.0.0"), ErrNotFound
}

func ListGateWay() ([]*RouteItem, error) {
	txt, err := ioutil.ReadFile("/proc/net/route")
	if err != nil {
		return nil, err
	}
	var ret []*RouteItem
	matched := gateWayExp.FindAllSubmatchIndex(txt, -1)

	//Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT
	if len(matched) > 0 {
		//skip title line

		for i := 1; i < len(matched); i++ {
			item := new(RouteItem)
			var voff int //value offset
			voff++
			item.Iface = string(txt[matched[i][voff*2]:matched[i][voff*2+1]])

			//dst hex string
			voff++
			dst := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Dst = netHexToIPAddr(dst)

			//gateway hex string
			voff++
			gw := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Gateway = netHexToIPAddr(gw)

			voff++
			flags := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(flags, "%d", &item.Flags)

			voff++
			refCnt := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(refCnt, "%d", &item.RefCnt)

			voff++
			use := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(use, "%d", &item.Use)

			voff++
			metric := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(metric, "%d", &item.Metric)

			voff++
			mask := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			item.Mask = netHexToIPMask(mask)

			voff++
			mtu := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(mtu, "%d", &item.MTU)

			voff++
			window := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(window, "%d", &item.Window)

			voff++
			irtt := string(txt[matched[i][voff*2]:matched[i][voff*2+1]])
			fmt.Sscan(irtt, "%d", &item.IRTT)

			ret = append(ret, item)
		}
		return ret, nil
	}

	return ret, ErrNotFound
}
<|endoftext|>


<commit_before>package es

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

const (
	OK  = '2'
	AND = "AND"
	OR  = "OR"
)

type Term map[string]interface{}

type Terms map[string][]interface{}

type Filter struct {
	And   []*Filter         `json:"and,omitempty`
	Term  *Term             `json:"term,omitempty"`
	Terms *Terms            `json:"term,omitempty"`
	Range map[string]*Range `json:"range,omitempty"`
}

type Range struct {
	From interface{}
	To   interface{}
}

type Filtered struct {
	Filter *Filter
}

type QueryString struct {
	Query           string `json:"query,omitempty"`
	DefaultOperator string `json:"default_operator,omitempty"`
}

type Query struct {
	Filtered    *Filtered    `json:"filtered,omitempty"`
	QueryString *QueryString `json:"query_string,omitempty"`
}

var query = Query{
	Filtered: &Filtered{
		Filter: &Filter{
			And: []*Filter{
				{
					Term: &Term{
						"Device": "Anrdoi",
					},
				},
				{
					Terms: &Terms{
						"Action": []interface{}{
							"api/v1/my/photos#create",
							"api/v1/photos#create",
						},
					},
					Range: map[string]*Range{
						"Time": {
							From: "",
						},
					},
				},
			},
		},
	},
}

type BulkIndexJob struct {
	Key    string
	Record interface{}
}

type Index struct {
	Host          string
	Port          int
	Index         string
	Type          string
	bulkIndexJobs []*BulkIndexJob
	BatchSize     int
	Debug         bool
}

func (index *Index) EnqueueBulkIndex(key string, record interface{}) (bool, error) {
	if index.BatchSize == 0 {
		index.BatchSize = 100
	}
	if cap(index.bulkIndexJobs) == 0 {
		index.ResetQueue()
	}
	index.bulkIndexJobs = append(index.bulkIndexJobs, &BulkIndexJob{
		Key: key, Record: record,
	})
	if len(index.bulkIndexJobs) >= index.BatchSize {
		return true, index.RunBatchIndex()
	}
	return false, nil
}

func (index *Index) RunBatchIndex() error {
	started := time.Now()
	buf := &bytes.Buffer{}
	enc := json.NewEncoder(buf)
	for _, r := range index.bulkIndexJobs {
		enc.Encode(map[string]map[string]string{
			"index": map[string]string{
				"_index": index.Index,
				"_type":  index.Type,
				"_id":    r.Key,
			},
		})
		enc.Encode(r.Record)
	}
	rsp, e := http.Post(index.BaseUrl()+"/_bulk", "application/json", buf)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	b, _ := ioutil.ReadAll(rsp.Body)
	if rsp.Status[0] != OK {
		return fmt.Errorf("Error sending bulk request: %s %s", rsp.Status, string(b))
	}
	perSecond := float64(len(index.bulkIndexJobs)) / time.Now().Sub(started).Seconds()
	if index.Debug {
		fmt.Printf("indexed %d, %.1f/second\n", len(index.bulkIndexJobs), perSecond)
	}
	index.ResetQueue()
	return nil
}

func (index *Index) ResetQueue() {
	index.bulkIndexJobs = make([]*BulkIndexJob, 0, index.BatchSize)
}

type IndexStatus struct {
	Index  string `json:"_index"`
	Type   string `json:"_type"`
	Id     string `json:"_id"`
	Exists bool   `json:"exists"`
}

func (index *Index) Status() (status *IndexStatus, e error) {
	rsp, e := http.Get(index.BaseUrl() + "/_status")
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	status = &IndexStatus{}
	e = json.Unmarshal(b, status)
	return status, e
}

func (index *Index) Mapping() (i interface{}, e error) {
	u := index.IndexUrl() + "/_mapping"
	log.Printf("checking for url %s", u)
	rsp, e := index.request("GET", u, i)
	if rsp != nil && rsp.StatusCode == 404 {
		return nil, nil
	} else if e != nil {
		return nil, e
	}
	e = json.Unmarshal(rsp.Body, &i)
	if e != nil {
		return nil, e
	}
	return i, nil
}

func (index *Index) PutMapping(mapping interface{}) (rsp *HttpResponse, e error) {
	return index.request("PUT", index.IndexUrl()+"/", mapping)
}

func (index *Index) BaseUrl() string {
	if index.Port == 0 {
		index.Port = 9200
	}
	return fmt.Sprintf("http://%s:%d", index.Host, index.Port)
}

func (index *Index) IndexUrl() string {
	if index.Index != "" {
		return index.BaseUrl() + "/" + index.Index
	}
	return ""
}

func (index *Index) TypeUrl() string {
	if base := index.IndexUrl(); base != "" && index.Type != "" {
		return base + "/" + index.Type
	}
	return ""
	return ""
}

func (index *Index) Search(req *Request) (rsp *Response, e error) {
	writer := &bytes.Buffer{}
	js := json.NewEncoder(writer)
	e = js.Encode(req)
	if e != nil {
		return nil, e
	}
	u := index.TypeUrl()
	if !strings.HasSuffix(u, "/") {
		u += "/"
	}
	u += "/_search"
	httpRequest, e := http.NewRequest("POST", u, writer)
	if e != nil {
		return nil, e
	}
	httpResponse, e := http.DefaultClient.Do(httpRequest)
	if e != nil {
		return nil, e
	}
	defer httpResponse.Body.Close()
	dec := json.NewDecoder(httpResponse.Body)
	rsp = &Response{}
	e = dec.Decode(rsp)
	if e != nil {
		return nil, e
	}
	return rsp, nil
}

func (index *Index) Post(u string, i interface{}) (*HttpResponse, error) {
	return index.request("POST", u, i)
}

func (index *Index) PutObject(id string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", index.TypeUrl()+"/"+id, i)
}

func (index *Index) Put(u string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", u, i)
}

type HttpResponse struct {
	*http.Response
	Body []byte
}

func (index *Index) request(method string, u string, i interface{}) (httpResponse *HttpResponse, e error) {
	var req *http.Request
	if i != nil {
		buf := &bytes.Buffer{}
		encoder := json.NewEncoder(buf)
		if e := encoder.Encode(i); e != nil {
			return nil, e
		}
		req, e = http.NewRequest(method, u, buf)
	} else {
		req, e = http.NewRequest(method, u, nil)
	}
	if e != nil {
		return nil, e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	httpResponse = &HttpResponse{
		Response: rsp,
		Body:     b,
	}
	if e != nil {
		return httpResponse, e
	}
	if rsp.Status[0] != OK {
		return httpResponse, fmt.Errorf("error indexing: %s %s", rsp.Status, string(b))
	}
	return httpResponse, nil
}
<commit_msg>add methods to Delete and Refresh index<commit_after>package es

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

const (
	OK  = '2'
	AND = "AND"
	OR  = "OR"
)

type Term map[string]interface{}

type Terms map[string][]interface{}

type Filter struct {
	And   []*Filter         `json:"and,omitempty`
	Term  *Term             `json:"term,omitempty"`
	Terms *Terms            `json:"term,omitempty"`
	Range map[string]*Range `json:"range,omitempty"`
}

type Range struct {
	From interface{}
	To   interface{}
}

type Filtered struct {
	Filter *Filter
}

type QueryString struct {
	Query           string `json:"query,omitempty"`
	DefaultOperator string `json:"default_operator,omitempty"`
}

type Query struct {
	Filtered    *Filtered    `json:"filtered,omitempty"`
	QueryString *QueryString `json:"query_string,omitempty"`
}

var query = Query{
	Filtered: &Filtered{
		Filter: &Filter{
			And: []*Filter{
				{
					Term: &Term{
						"Device": "Anrdoi",
					},
				},
				{
					Terms: &Terms{
						"Action": []interface{}{
							"api/v1/my/photos#create",
							"api/v1/photos#create",
						},
					},
					Range: map[string]*Range{
						"Time": {
							From: "",
						},
					},
				},
			},
		},
	},
}

type BulkIndexJob struct {
	Key    string
	Record interface{}
}

type Index struct {
	Host          string
	Port          int
	Index         string
	Type          string
	bulkIndexJobs []*BulkIndexJob
	BatchSize     int
	Debug         bool
}

func (index *Index) EnqueueBulkIndex(key string, record interface{}) (bool, error) {
	if index.BatchSize == 0 {
		index.BatchSize = 100
	}
	if cap(index.bulkIndexJobs) == 0 {
		index.ResetQueue()
	}
	index.bulkIndexJobs = append(index.bulkIndexJobs, &BulkIndexJob{
		Key: key, Record: record,
	})
	if len(index.bulkIndexJobs) >= index.BatchSize {
		return true, index.RunBatchIndex()
	}
	return false, nil
}

func (index *Index) DeleteIndex() error {
	req, e := http.NewRequest("DELETE", index.TypeUrl(), nil)
	if e != nil {
		return e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error delting index at %s: %s", index.TypeUrl(), rsp.Status)
	}
	return nil
}

func (index *Index) Refresh() error {
	rsp, e := index.request("POST", index.IndexUrl()+"/_refresh", nil)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("Error refreshing index: %s", rsp.Status)
	}
	return nil
}

func (index *Index) RunBatchIndex() error {
	started := time.Now()
	buf := &bytes.Buffer{}
	enc := json.NewEncoder(buf)
	for _, r := range index.bulkIndexJobs {
		enc.Encode(map[string]map[string]string{
			"index": map[string]string{
				"_index": index.Index,
				"_type":  index.Type,
				"_id":    r.Key,
			},
		})
		enc.Encode(r.Record)
	}
	rsp, e := http.Post(index.BaseUrl()+"/_bulk", "application/json", buf)
	if e != nil {
		return e
	}
	defer rsp.Body.Close()
	b, _ := ioutil.ReadAll(rsp.Body)
	if rsp.Status[0] != OK {
		return fmt.Errorf("Error sending bulk request: %s %s", rsp.Status, string(b))
	}
	perSecond := float64(len(index.bulkIndexJobs)) / time.Now().Sub(started).Seconds()
	if index.Debug {
		fmt.Printf("indexed %d, %.1f/second\n", len(index.bulkIndexJobs), perSecond)
	}
	index.ResetQueue()
	return nil
}

func (index *Index) ResetQueue() {
	index.bulkIndexJobs = make([]*BulkIndexJob, 0, index.BatchSize)
}

type IndexStatus struct {
	Index  string `json:"_index"`
	Type   string `json:"_type"`
	Id     string `json:"_id"`
	Exists bool   `json:"exists"`
}

func (index *Index) Status() (status *IndexStatus, e error) {
	rsp, e := http.Get(index.BaseUrl() + "/_status")
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	status = &IndexStatus{}
	e = json.Unmarshal(b, status)
	return status, e
}

func (index *Index) Mapping() (i interface{}, e error) {
	u := index.IndexUrl() + "/_mapping"
	log.Printf("checking for url %s", u)
	rsp, e := index.request("GET", u, i)
	if rsp != nil && rsp.StatusCode == 404 {
		return nil, nil
	} else if e != nil {
		return nil, e
	}
	e = json.Unmarshal(rsp.Body, &i)
	if e != nil {
		return nil, e
	}
	return i, nil
}

func (index *Index) PutMapping(mapping interface{}) (rsp *HttpResponse, e error) {
	return index.request("PUT", index.IndexUrl()+"/", mapping)
}

func (index *Index) BaseUrl() string {
	if index.Port == 0 {
		index.Port = 9200
	}
	return fmt.Sprintf("http://%s:%d", index.Host, index.Port)
}

func (index *Index) IndexUrl() string {
	if index.Index != "" {
		return index.BaseUrl() + "/" + index.Index
	}
	return ""
}

func (index *Index) TypeUrl() string {
	if base := index.IndexUrl(); base != "" && index.Type != "" {
		return base + "/" + index.Type
	}
	return ""
	return ""
}

func (index *Index) Search(req *Request) (rsp *Response, e error) {
	writer := &bytes.Buffer{}
	js := json.NewEncoder(writer)
	e = js.Encode(req)
	if e != nil {
		return nil, e
	}
	u := index.TypeUrl()
	if !strings.HasSuffix(u, "/") {
		u += "/"
	}
	u += "/_search"
	httpRequest, e := http.NewRequest("POST", u, writer)
	if e != nil {
		return nil, e
	}
	httpResponse, e := http.DefaultClient.Do(httpRequest)
	if e != nil {
		return nil, e
	}
	defer httpResponse.Body.Close()
	dec := json.NewDecoder(httpResponse.Body)
	rsp = &Response{}
	e = dec.Decode(rsp)
	if e != nil {
		return nil, e
	}
	return rsp, nil
}

func (index *Index) Post(u string, i interface{}) (*HttpResponse, error) {
	return index.request("POST", u, i)
}

func (index *Index) PutObject(id string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", index.TypeUrl()+"/"+id, i)
}

func (index *Index) Put(u string, i interface{}) (*HttpResponse, error) {
	return index.request("PUT", u, i)
}

type HttpResponse struct {
	*http.Response
	Body []byte
}

func (index *Index) request(method string, u string, i interface{}) (httpResponse *HttpResponse, e error) {
	var req *http.Request
	if i != nil {
		buf := &bytes.Buffer{}
		encoder := json.NewEncoder(buf)
		if e := encoder.Encode(i); e != nil {
			return nil, e
		}
		req, e = http.NewRequest(method, u, buf)
	} else {
		req, e = http.NewRequest(method, u, nil)
	}
	if e != nil {
		return nil, e
	}
	rsp, e := http.DefaultClient.Do(req)
	if e != nil {
		return nil, e
	}
	defer rsp.Body.Close()
	b, e := ioutil.ReadAll(rsp.Body)
	if e != nil {
		return nil, e
	}
	httpResponse = &HttpResponse{
		Response: rsp,
		Body:     b,
	}
	if e != nil {
		return httpResponse, e
	}
	if rsp.Status[0] != OK {
		return httpResponse, fmt.Errorf("error indexing: %s %s", rsp.Status, string(b))
	}
	return httpResponse, nil
}
<|endoftext|>