<commit_before>package req

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// M represents the request params.
type M map[string]string

// Request provides much easier useage than http.Request
type Request struct {
	url       string
	urlEncode bool
	params    M
	req       *http.Request
	Resp      Response
	done      bool
	body      []byte
}

// Param set single param to the request.
func (r *Request) Param(k, v string) *Request {
	r.params[k] = v
	return r
}

// Params set multiple params to the request.
func (r *Request) Params(params M) *Request {
	for k, v := range params {
		r.params[k] = v
	}
	return r
}

// Header set the request header.
func (r *Request) Header(k, v string) *Request {
	r.req.Header.Set(k, v)
	return r
}

func (r *Request) Headers(params M) *Request {
	for k, v := range params {
		r.req.Header.Set(k, v)
	}
	return r
}

// Body set the request body,support string and []byte.
func (r *Request) Body(body interface{}) *Request {
	switch v := body.(type) {
	case string:
		bf := bytes.NewBufferString(v)
		r.req.Body = ioutil.NopCloser(bf)
		r.req.ContentLength = int64(len(v))
		r.body = []byte(v)
	case []byte:
		bf := bytes.NewBuffer(v)
		r.req.Body = ioutil.NopCloser(bf)
		r.req.ContentLength = int64(len(v))
		r.body = v
	}
	return r
}

func (r *Request) GetBody() []byte {
	return r.body
}

// Bytes execute the request and get the response body as []byte.
func (r *Request) Bytes() (data []byte, err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	data = resp.Body
	return
}

// String execute the request and get the response body as string.
func (r *Request) String() (s string, err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	s = string(resp.Body)
	return
}

// String execute the request and get the response body unmarshal to json.
func (r *Request) ToJson(v interface{}) (err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	err = resp.ToJson(v)
	return
}

// String execute the request and get the response body unmarshal to xml.
func (r *Request) ToXml(v interface{}) (err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	err = resp.ToXml(v)
	return
}

func (r *Request) UrlEncode(urlEncode bool) *Request {
	r.urlEncode = urlEncode
	return r
}

func (r *Request) getParamBody() string {
	var buf bytes.Buffer
	for k, v := range r.params {
		if r.urlEncode {
			k = url.QueryEscape(k)
			v = url.QueryEscape(v)
		}
		buf.WriteString(k)
		buf.WriteByte('=')
		buf.WriteString(v)
		buf.WriteByte('&')
	}
	p := buf.String()
	p = p[0 : len(p)-1]
	return p
}

func (r *Request) buildGetUrl() string {
	ret := r.url
	p := r.getParamBody()
	if strings.Index(r.url, "?") != -1 {
		ret += "&" + p
	} else {
		ret += "?" + p
	}
	return ret
}

func (r *Request) setParamBody() {
	if r.urlEncode {
		r.Header("Content-Type", "application/x-www-form-urlencoded")
	}
	r.Body(r.getParamBody())
}

func (r *Request) Url() string {
	if r.req.Method != "GET" || r.done {
		return r.url
	}
	return r.buildGetUrl() //GET method and did not send request yet.
}

// Response execute the request and get the response.
func (r *Request) Response() (resp Response, err error) {
	if r.Resp.Raw != nil { // provent multiple call
		resp = r.Resp
		return
	}
	// handle request params
	if len(r.params) > 0 {
		switch r.req.Method {
		case "GET":
			r.url = r.buildGetUrl()
		case "POST":
			if r.req.Body == nil {
				r.setParamBody()
			}
		}
	}
	// set url
	u, err := url.Parse(r.url)
	if err != nil {
		return
	}
	r.req.URL = u
	r.Resp.Raw, err = http.DefaultClient.Do(r.req)
	if err != nil {
		return
	}
	err = r.Resp.Receive()
	if err != nil {
		return
	}
	resp = r.Resp
	r.done = true
	return
}

// Get returns *Request with GET method.
func Get(url string) *Request {
	return newRequest(url, "GET")
}

// Get returns *Request with POST method.
func Post(url string) *Request {
	return newRequest(url, "POST")
}
func Wrap(url string, req *http.Request) *Request {
	return &Request{
		url:       url,
		urlEncode: true,
		params:    M{},
		req:       req,
		Resp:      Response{},
	}
}

func newRequest(url, method string) *Request {
	return &Request{
		url:       url,
		urlEncode: true,
		params:    M{},
		req: &http.Request{
			Method:     method,
			Header:     make(http.Header),
			Proto:      "HTTP/1.1",
			ProtoMajor: 1,
			ProtoMinor: 1,
		},
		Resp: Response{},
	}
}

func (r *Request) Format(s fmt.State, verb rune) {

	if s.Flag('+') { // include header and format pretty.
		fmt.Fprint(s, r.req.Method, " ", r.Url(), " ", r.req.Proto)
		for name, values := range r.req.Header {
			for _, value := range values {
				fmt.Fprint(s, "\n", name, ":", value)
			}
		}
		if r.body != nil {
			fmt.Fprint(s, "\n\n", string(r.body))
		}
		if r.Resp.Raw != nil {
			fmt.Fprint(s, "\n\n")
			r.Resp.Format(s, verb)
		}
		return
	}

	fmt.Fprint(s, r.req.Method, " ", r.Url())

	pretty := false
	if (r.body != nil && bytes.IndexByte(r.body, '\n') != -1) || (r.Resp.Body != nil && bytes.IndexByte(r.Resp.Body, '\n') != -1) {
		pretty = true
	}
	if pretty {
		fmt.Fprint(s, "\n")
		if r.body != nil {
			fmt.Fprint(s, string(r.body))
		}
		if r.Resp.Body != nil {
			fmt.Fprint(s, "\n", string(r.Resp.Body))
		}
		return
	}
	if r.body != nil {
		fmt.Fprint(s, " ", string(r.body))
	}
	if r.Resp.Body != nil { // request has been sent.
		fmt.Fprint(s, " ", string(r.Resp.Body))
	}
}
<commit_msg>support insecure https<commit_after>package req

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// M represents the request params.
type M map[string]string

// Request provides much easier useage than http.Request
type Request struct {
	url       string
	urlEncode bool
	params    M
	req       *http.Request
	Resp      Response
	done      bool
	body      []byte
	Client    http.Client
}

// InsecureTLS insecure the https.
func (r *Request) InsecureTLS() *Request {
	r.Client.Transport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	return r
}

// Param set single param to the request.
func (r *Request) Param(k, v string) *Request {
	r.params[k] = v
	return r
}

// Params set multiple params to the request.
func (r *Request) Params(params M) *Request {
	for k, v := range params {
		r.params[k] = v
	}
	return r
}

// Header set the request header.
func (r *Request) Header(k, v string) *Request {
	r.req.Header.Set(k, v)
	return r
}

func (r *Request) Headers(params M) *Request {
	for k, v := range params {
		r.req.Header.Set(k, v)
	}
	return r
}

// Body set the request body,support string and []byte.
func (r *Request) Body(body interface{}) *Request {
	switch v := body.(type) {
	case string:
		bf := bytes.NewBufferString(v)
		r.req.Body = ioutil.NopCloser(bf)
		r.req.ContentLength = int64(len(v))
		r.body = []byte(v)
	case []byte:
		bf := bytes.NewBuffer(v)
		r.req.Body = ioutil.NopCloser(bf)
		r.req.ContentLength = int64(len(v))
		r.body = v
	}
	return r
}

func (r *Request) GetBody() []byte {
	return r.body
}

// Bytes execute the request and get the response body as []byte.
func (r *Request) Bytes() (data []byte, err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	data = resp.Body
	return
}

// String execute the request and get the response body as string.
func (r *Request) String() (s string, err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	s = string(resp.Body)
	return
}

// String execute the request and get the response body unmarshal to json.
func (r *Request) ToJson(v interface{}) (err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	err = resp.ToJson(v)
	return
}

// String execute the request and get the response body unmarshal to xml.
func (r *Request) ToXml(v interface{}) (err error) {
	resp, err := r.Response()
	if err != nil {
		return
	}
	err = resp.ToXml(v)
	return
}

func (r *Request) UrlEncode(urlEncode bool) *Request {
	r.urlEncode = urlEncode
	return r
}

func (r *Request) getParamBody() string {
	var buf bytes.Buffer
	for k, v := range r.params {
		if r.urlEncode {
			k = url.QueryEscape(k)
			v = url.QueryEscape(v)
		}
		buf.WriteString(k)
		buf.WriteByte('=')
		buf.WriteString(v)
		buf.WriteByte('&')
	}
	p := buf.String()
	p = p[0 : len(p)-1]
	return p
}

func (r *Request) buildGetUrl() string {
	ret := r.url
	p := r.getParamBody()
	if strings.Index(r.url, "?") != -1 {
		ret += "&" + p
	} else {
		ret += "?" + p
	}
	return ret
}

func (r *Request) setParamBody() {
	if r.urlEncode {
		r.Header("Content-Type", "application/x-www-form-urlencoded")
	}
	r.Body(r.getParamBody())
}

func (r *Request) Url() string {
	if r.req.Method != "GET" || r.done {
		return r.url
	}
	return r.buildGetUrl() //GET method and did not send request yet.
}

// Response execute the request and get the response.
func (r *Request) Response() (resp Response, err error) {
	if r.Resp.Raw != nil { // provent multiple call
		resp = r.Resp
		return
	}
	// handle request params
	if len(r.params) > 0 {
		switch r.req.Method {
		case "GET":
			r.url = r.buildGetUrl()
		case "POST":
			if r.req.Body == nil {
				r.setParamBody()
			}
		}
	}
	// set url
	u, err := url.Parse(r.url)
	if err != nil {
		return
	}
	r.req.URL = u
	r.Resp.Raw, err = r.Client.Do(r.req)
	if err != nil {
		return
	}
	err = r.Resp.Receive()
	if err != nil {
		return
	}
	resp = r.Resp
	r.done = true
	return
}

// Get returns *Request with GET method.
func Get(url string) *Request {
	return newRequest(url, "GET")
}

// Get returns *Request with POST method.
func Post(url string) *Request {
	return newRequest(url, "POST")
}
func Wrap(url string, req *http.Request) *Request {
	return &Request{
		url:       url,
		urlEncode: true,
		params:    M{},
		req:       req,
		Resp:      Response{},
	}
}

func newRequest(url, method string) *Request {
	return &Request{
		url:       url,
		urlEncode: true,
		params:    M{},
		req: &http.Request{
			Method:     method,
			Header:     make(http.Header),
			Proto:      "HTTP/1.1",
			ProtoMajor: 1,
			ProtoMinor: 1,
		},
		Resp: Response{},
	}
}

func (r *Request) Format(s fmt.State, verb rune) {

	if s.Flag('+') { // include header and format pretty.
		fmt.Fprint(s, r.req.Method, " ", r.Url(), " ", r.req.Proto)
		for name, values := range r.req.Header {
			for _, value := range values {
				fmt.Fprint(s, "\n", name, ":", value)
			}
		}
		if r.body != nil {
			fmt.Fprint(s, "\n\n", string(r.body))
		}
		if r.Resp.Raw != nil {
			fmt.Fprint(s, "\n\n")
			r.Resp.Format(s, verb)
		}
		return
	}

	fmt.Fprint(s, r.req.Method, " ", r.Url())

	pretty := false
	if (r.body != nil && bytes.IndexByte(r.body, '\n') != -1) || (r.Resp.Body != nil && bytes.IndexByte(r.Resp.Body, '\n') != -1) {
		pretty = true
	}
	if pretty {
		fmt.Fprint(s, "\n")
		if r.body != nil {
			fmt.Fprint(s, string(r.body))
		}
		if r.Resp.Body != nil {
			fmt.Fprint(s, "\n", string(r.Resp.Body))
		}
		return
	}
	if r.body != nil {
		fmt.Fprint(s, " ", string(r.body))
	}
	if r.Resp.Body != nil { // request has been sent.
		fmt.Fprint(s, " ", string(r.Resp.Body))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/artyom/autoflags"
	"github.com/ttacon/chalk"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] ip1 ip2 ...\n", os.Args[0])
		flag.PrintDefaults()
	}
}

type Config struct {
	Concurrency int    `flag:"n,concurrent ssh sessions"`
	Command     string `flag:"cmd,command to run"`
	Login       string `flag:"l,login to use"`
	Port        int    `flag:"p,default port"`
	DumpFiles   bool   `flag:"logs,save stdout/stderr to separate per-host logs"`
	StdoutFmt   string `flag:"logs.stdout,format of stdout per-host log name"`
	StderrFmt   string `flag:"logs.stderr,format of stderr per-host log name"`
}

func main() {
	log.SetFlags(0)
	conf := Config{
		Concurrency: 100,
		Login:       "root",
		Port:        22,
		StdoutFmt:   "/tmp/%s.stdout",
		StderrFmt:   "/tmp/%s.stderr",
	}
	autoflags.Define(&conf)
	flag.Parse()
	if conf.Concurrency < 1 {
		conf.Concurrency = 1
	}
	hosts := flag.Args()
	if len(hosts) == 0 || len(conf.Command) == 0 {
		flag.Usage()
		return
	}
	if conf.DumpFiles {
		if conf.StdoutFmt == conf.StderrFmt {
			log.Fatal("file format for stdout and stderr should differ")
		}
		if !strings.Contains(conf.StdoutFmt, `%s`) {
			log.Fatal("invalid format for stdout log name")
		}
		if !strings.Contains(conf.StderrFmt, `%s`) {
			log.Fatal("invalid format for stderr log name")
		}
	}
	var sshAgent agent.Agent
	agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		log.Fatal(err)
	}
	sshAgent = agent.NewClient(agentConn)
	defer agentConn.Close()

	signers, err := sshAgent.Signers()
	if err != nil {
		log.Fatal(err)
	}

	config := &ssh.ClientConfig{
		User: conf.Login,
		Auth: []ssh.AuthMethod{ssh.PublicKeys(signers...)},
	}

	var wg sync.WaitGroup

	stdout := make(chan string, 10)
	stderr := make(chan string, 10)
	go func() {
		for {
			stdoutPrefix, stderrPrefix := ".", "E"
			if isTerminal(os.Stdout) {
				stdoutPrefix = chalk.Green.Color(stdoutPrefix)
			}
			if isTerminal(os.Stderr) {
				stderrPrefix = chalk.Red.Color(stderrPrefix)
			}
			select {
			case item := <-stdout:
				fmt.Fprintln(os.Stdout, stdoutPrefix, item)
			case item := <-stderr:
				fmt.Fprintln(os.Stderr, stderrPrefix, item)
			}
		}
	}()

	limit := make(chan struct{}, conf.Concurrency)

	uniqueHosts := make(map[string]struct{})
	for _, host := range hosts {
		uniqueHosts[host] = struct{}{}
	}

	for host := range uniqueHosts {
		limit <- struct{}{}
		wg.Add(1)
		go func(host string) {
			defer wg.Done()
			defer func() { <-limit }()
			switch err := RemoteCommand(host, conf, config, stdout, stderr); {
			case err == nil && conf.DumpFiles:
				fmt.Println(host, "processed")
			case err == nil:
			default:
				log.Println(host, err)
			}
		}(host)
	}
	wg.Wait()
}

func RemoteCommand(host string, conf Config, config *ssh.ClientConfig, stdout, stderr chan<- string) error {
	addr := host
	if !strings.ContainsRune(addr, ':') {
		addr = fmt.Sprintf("%s:%d", addr, conf.Port)
	}
	client, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		return err
	}
	defer client.Close()

	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	switch {
	case conf.DumpFiles:
		stdoutLog, err := os.Create(filepath.Clean(fmt.Sprintf(conf.StdoutFmt, host)))
		if err != nil {
			return err
		}
		defer closeAndRemoveIfAt0(stdoutLog)
		session.Stdout = stdoutLog
		stderrLog, err := os.Create(filepath.Clean(fmt.Sprintf(conf.StderrFmt, host)))
		if err != nil {
			return err
		}
		defer closeAndRemoveIfAt0(stderrLog)
		session.Stderr = stderrLog
	default:
		stdoutPipe, err := session.StdoutPipe()
		if err != nil {
			return err
		}
		stderrPipe, err := session.StderrPipe()
		if err != nil {
			return err
		}

		go pipeFeeder(host, stdoutPipe, stdout)
		go pipeFeeder(host, stderrPipe, stderr)
	}

	return session.Run(conf.Command)
}

func pipeFeeder(prefix string, pipe io.Reader, sink chan<- string) {
	scanner := bufio.NewScanner(pipe)
	for scanner.Scan() {
		sink <- prefix + "\t" + scanner.Text()
	}
	if err := scanner.Err(); err != nil {
		log.Print("string scanner error", err)
	}
}

func closeAndRemoveIfAt0(f *os.File) {
	if n, err := f.Seek(0, os.SEEK_CUR); err == nil && n == 0 {
		os.Remove(f.Name())
	}
	f.Close()
}

func isTerminal(f *os.File) bool {
	st, err := f.Stat()
	if err != nil {
		return false
	}
	return st.Mode()&os.ModeDevice != 0
}
<commit_msg>Add support for passing files to remote side via stdin flag<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/artyom/autoflags"
	"github.com/ttacon/chalk"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] ip1 ip2 ...\n", os.Args[0])
		flag.PrintDefaults()
	}
}

type Config struct {
	Concurrency int    `flag:"n,concurrent ssh sessions"`
	Command     string `flag:"cmd,command to run"`
	Login       string `flag:"l,login to use"`
	Port        int    `flag:"p,default port"`
	StdinFile   string `flag:"stdin,REGULAR (no piping!) file to pass to stdin of remote command"`
	DumpFiles   bool   `flag:"logs,save stdout/stderr to separate per-host logs"`
	StdoutFmt   string `flag:"logs.stdout,format of stdout per-host log name"`
	StderrFmt   string `flag:"logs.stderr,format of stderr per-host log name"`
}

func main() {
	log.SetFlags(0)
	conf := Config{
		Concurrency: 100,
		Login:       "root",
		Port:        22,
		StdoutFmt:   "/tmp/%s.stdout",
		StderrFmt:   "/tmp/%s.stderr",
	}
	autoflags.Define(&conf)
	flag.Parse()
	if conf.Concurrency < 1 {
		conf.Concurrency = 1
	}
	hosts := flag.Args()
	if len(hosts) == 0 || len(conf.Command) == 0 {
		flag.Usage()
		return
	}
	if conf.DumpFiles {
		if conf.StdoutFmt == conf.StderrFmt {
			log.Fatal("file format for stdout and stderr should differ")
		}
		if !strings.Contains(conf.StdoutFmt, `%s`) {
			log.Fatal("invalid format for stdout log name")
		}
		if !strings.Contains(conf.StderrFmt, `%s`) {
			log.Fatal("invalid format for stderr log name")
		}
	}
	var sshAgent agent.Agent
	agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		log.Fatal(err)
	}
	sshAgent = agent.NewClient(agentConn)
	defer agentConn.Close()

	signers, err := sshAgent.Signers()
	if err != nil {
		log.Fatal(err)
	}

	config := &ssh.ClientConfig{
		User: conf.Login,
		Auth: []ssh.AuthMethod{ssh.PublicKeys(signers...)},
	}

	var wg sync.WaitGroup

	stdout := make(chan string, 10)
	stderr := make(chan string, 10)
	go func() {
		for {
			stdoutPrefix, stderrPrefix := ".", "E"
			if isTerminal(os.Stdout) {
				stdoutPrefix = chalk.Green.Color(stdoutPrefix)
			}
			if isTerminal(os.Stderr) {
				stderrPrefix = chalk.Red.Color(stderrPrefix)
			}
			select {
			case item := <-stdout:
				fmt.Fprintln(os.Stdout, stdoutPrefix, item)
			case item := <-stderr:
				fmt.Fprintln(os.Stderr, stderrPrefix, item)
			}
		}
	}()

	limit := make(chan struct{}, conf.Concurrency)

	uniqueHosts := make(map[string]struct{})
	for _, host := range hosts {
		uniqueHosts[host] = struct{}{}
	}

	for host := range uniqueHosts {
		limit <- struct{}{}
		wg.Add(1)
		go func(host string) {
			defer wg.Done()
			defer func() { <-limit }()
			switch err := RemoteCommand(host, conf, config, stdout, stderr); {
			case err == nil && conf.DumpFiles:
				fmt.Println(host, "processed")
			case err == nil:
			default:
				log.Println(host, err)
			}
		}(host)
	}
	wg.Wait()
}

func RemoteCommand(host string, conf Config, config *ssh.ClientConfig, stdout, stderr chan<- string) error {
	addr := host
	if !strings.ContainsRune(addr, ':') {
		addr = fmt.Sprintf("%s:%d", addr, conf.Port)
	}
	client, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		return err
	}
	defer client.Close()

	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	if conf.StdinFile != "" {
		f, err := os.Open(conf.StdinFile)
		if err != nil {
			return err
		}
		defer f.Close()
		st, err := f.Stat()
		if err != nil {
			return err
		}
		if !st.Mode().IsRegular() {
			return errors.New("file passed to stdin is not a regular file")
		}
		session.Stdin = f
	}

	switch {
	case conf.DumpFiles:
		stdoutLog, err := os.Create(filepath.Clean(fmt.Sprintf(conf.StdoutFmt, host)))
		if err != nil {
			return err
		}
		defer closeAndRemoveIfAt0(stdoutLog)
		session.Stdout = stdoutLog
		stderrLog, err := os.Create(filepath.Clean(fmt.Sprintf(conf.StderrFmt, host)))
		if err != nil {
			return err
		}
		defer closeAndRemoveIfAt0(stderrLog)
		session.Stderr = stderrLog
	default:
		stdoutPipe, err := session.StdoutPipe()
		if err != nil {
			return err
		}
		stderrPipe, err := session.StderrPipe()
		if err != nil {
			return err
		}

		go pipeFeeder(host, stdoutPipe, stdout)
		go pipeFeeder(host, stderrPipe, stderr)
	}

	return session.Run(conf.Command)
}

func pipeFeeder(prefix string, pipe io.Reader, sink chan<- string) {
	scanner := bufio.NewScanner(pipe)
	for scanner.Scan() {
		sink <- prefix + "\t" + scanner.Text()
	}
	if err := scanner.Err(); err != nil {
		log.Print("string scanner error", err)
	}
}

func closeAndRemoveIfAt0(f *os.File) {
	if n, err := f.Seek(0, os.SEEK_CUR); err == nil && n == 0 {
		os.Remove(f.Name())
	}
	f.Close()
}

func isTerminal(f *os.File) bool {
	st, err := f.Stat()
	if err != nil {
		return false
	}
	return st.Mode()&os.ModeDevice != 0
}
<|endoftext|>


<commit_before>package node

import (
	"erlang/term"
)

type rexRPC struct {
	gsi *GenServerImpl
}

func (nk *rexRPC) Behaviour() (Behaviour, map[string]interface{}) {
	nk.gsi = &GenServerImpl{}
	return nk.gsi, nk.gsi.Options()
}

func (nk *rexRPC) Init(args ...interface{}) {
	nLog("REX: Init: %#v", args)
}

func (nk *rexRPC) HandleCast(message *term.Term) {
	nLog("REX: HandleCast: %#v", *message)
}

func (nk *rexRPC) HandleCall(message *term.Term, from *term.Tuple) (reply *term.Term) {
	nLog("REX: HandleCall: %#v, From: %#v", *message, *from)
	replyTerm := term.Term(term.Atom("yes"))
	reply = &replyTerm
	return
}

func (nk *rexRPC) HandleInfo(message *term.Term) {
	nLog("REX: HandleInfo: %#v", *message)
}

func (nk *rexRPC) Terminate(reason interface{}) {
	nLog("REX: Terminate: %#v", reason.(int))
}
<commit_msg>Change RPC reply<commit_after>package node

import (
	"erlang/term"
)

type rexRPC struct {
	gsi *GenServerImpl
}

func (nk *rexRPC) Behaviour() (Behaviour, map[string]interface{}) {
	nk.gsi = &GenServerImpl{}
	return nk.gsi, nk.gsi.Options()
}

func (nk *rexRPC) Init(args ...interface{}) {
	nLog("REX: Init: %#v", args)
}

func (nk *rexRPC) HandleCast(message *term.Term) {
	nLog("REX: HandleCast: %#v", *message)
}

func (nk *rexRPC) HandleCall(message *term.Term, from *term.Tuple) (reply *term.Term) {
	nLog("REX: HandleCall: %#v, From: %#v", *message, *from)
	replyTerm := term.Term(term.Atom("rpc reply"))
	reply = &replyTerm
	return
}

func (nk *rexRPC) HandleInfo(message *term.Term) {
	nLog("REX: HandleInfo: %#v", *message)
}

func (nk *rexRPC) Terminate(reason interface{}) {
	nLog("REX: Terminate: %#v", reason.(int))
}
<|endoftext|>


<commit_before>package config

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/config/lang/ast"
)

// Funcs is the mapping of built-in functions for configuration.
var Funcs map[string]ast.Function

func init() {
	Funcs = map[string]ast.Function{
		"file":    interpolationFuncFile(),
		"format":  interpolationFuncFormat(),
		"join":    interpolationFuncJoin(),
		"element": interpolationFuncElement(),
		"replace": interpolationFuncReplace(),
		"split":   interpolationFuncSplit(),

		// Concat is a little useless now since we supported embeddded
		// interpolations but we keep it around for backwards compat reasons.
		"concat": interpolationFuncConcat(),
	}
}

// interpolationFuncConcat implements the "concat" function that
// concatenates multiple strings. This isn't actually necessary anymore
// since our language supports string concat natively, but for backwards
// compat we do this.
func interpolationFuncConcat() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeString},
		ReturnType:   ast.TypeString,
		Variadic:     true,
		VariadicType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			var b bytes.Buffer
			for _, v := range args {
				b.WriteString(v.(string))
			}

			return b.String(), nil
		},
	}
}

// interpolationFuncFile implements the "file" function that allows
// loading contents from a file.
func interpolationFuncFile() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			data, err := ioutil.ReadFile(args[0].(string))
			if err != nil {
				return "", err
			}

			return string(data), nil
		},
	}
}

// interpolationFuncFormat implements the "replace" function that does
// string replacement.
func interpolationFuncFormat() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeString},
		Variadic:     true,
		VariadicType: ast.TypeAny,
		ReturnType:   ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			format := args[0].(string)
			return fmt.Sprintf(format, args[1:]...), nil
		},
	}
}

// interpolationFuncJoin implements the "join" function that allows
// multi-variable values to be joined by some character.
func interpolationFuncJoin() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			var list []string
			for _, arg := range args[1:] {
				parts := strings.Split(arg.(string), InterpSplitDelim)
				list = append(list, parts...)
			}

			return strings.Join(list, args[0].(string)), nil
		},
	}
}

// interpolationFuncReplace implements the "replace" function that does
// string replacement.
func interpolationFuncReplace() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			s := args[0].(string)
			search := args[1].(string)
			replace := args[2].(string)

			// We search/replace using a regexp if the string is surrounded
			// in forward slashes.
			if len(search) > 1 && search[0] == '/' && search[len(search)-1] == '/' {
				re, err := regexp.Compile(search[1 : len(search)-1])
				if err != nil {
					return nil, err
				}

				return re.ReplaceAllString(s, replace), nil
			}

			return strings.Replace(s, search, replace, -1), nil
		},
	}
}

// interpolationFuncSplit implements the "split" function that allows
// strings to split into multi-variable values
func interpolationFuncSplit() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			return strings.Replace(args[1].(string), args[0].(string), InterpSplitDelim, -1), nil
		},
	}
}

// interpolationFuncLookup implements the "lookup" function that allows
// dynamic lookups of map types within a Terraform configuration.
func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			k := fmt.Sprintf("var.%s.%s", args[0].(string), args[1].(string))
			v, ok := vs[k]
			if !ok {
				return "", fmt.Errorf(
					"lookup in '%s' failed to find '%s'",
					args[0].(string), args[1].(string))
			}
			if v.Type != ast.TypeString {
				return "", fmt.Errorf(
					"lookup in '%s' for '%s' has bad type %s",
					args[0].(string), args[1].(string), v.Type)
			}

			return v.Value.(string), nil
		},
	}
}

// interpolationFuncElement implements the "element" function that allows
// a specific index to be looked up in a multi-variable value. Note that this will
// wrap if the index is larger than the number of elements in the multi-variable value.
func interpolationFuncElement() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			list := strings.Split(args[0].(string), InterpSplitDelim)

			index, err := strconv.Atoi(args[1].(string))
			if err != nil {
				return "", fmt.Errorf(
					"invalid number for index, got %s", args[1])
			}

			v := list[index%len(list)]
			return v, nil
		},
	}
}
<commit_msg>config: interprets '~' as the current user home dir in file()<commit_after>package config

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/config/lang/ast"
	"github.com/mitchellh/go-homedir"
)

// Funcs is the mapping of built-in functions for configuration.
var Funcs map[string]ast.Function

func init() {
	Funcs = map[string]ast.Function{
		"file":    interpolationFuncFile(),
		"format":  interpolationFuncFormat(),
		"join":    interpolationFuncJoin(),
		"element": interpolationFuncElement(),
		"replace": interpolationFuncReplace(),
		"split":   interpolationFuncSplit(),

		// Concat is a little useless now since we supported embeddded
		// interpolations but we keep it around for backwards compat reasons.
		"concat": interpolationFuncConcat(),
	}
}

// interpolationFuncConcat implements the "concat" function that
// concatenates multiple strings. This isn't actually necessary anymore
// since our language supports string concat natively, but for backwards
// compat we do this.
func interpolationFuncConcat() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeString},
		ReturnType:   ast.TypeString,
		Variadic:     true,
		VariadicType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			var b bytes.Buffer
			for _, v := range args {
				b.WriteString(v.(string))
			}

			return b.String(), nil
		},
	}
}

// interpolationFuncFile implements the "file" function that allows
// loading contents from a file.
func interpolationFuncFile() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			var path string
			path, err := homedir.Expand(args[0].(string))
			if err != nil {
				return "", err
			}
			data, err := ioutil.ReadFile(path)
			if err != nil {
				return "", err
			}

			return string(data), nil
		},
	}
}

// interpolationFuncFormat implements the "replace" function that does
// string replacement.
func interpolationFuncFormat() ast.Function {
	return ast.Function{
		ArgTypes:     []ast.Type{ast.TypeString},
		Variadic:     true,
		VariadicType: ast.TypeAny,
		ReturnType:   ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			format := args[0].(string)
			return fmt.Sprintf(format, args[1:]...), nil
		},
	}
}

// interpolationFuncJoin implements the "join" function that allows
// multi-variable values to be joined by some character.
func interpolationFuncJoin() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			var list []string
			for _, arg := range args[1:] {
				parts := strings.Split(arg.(string), InterpSplitDelim)
				list = append(list, parts...)
			}

			return strings.Join(list, args[0].(string)), nil
		},
	}
}

// interpolationFuncReplace implements the "replace" function that does
// string replacement.
func interpolationFuncReplace() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			s := args[0].(string)
			search := args[1].(string)
			replace := args[2].(string)

			// We search/replace using a regexp if the string is surrounded
			// in forward slashes.
			if len(search) > 1 && search[0] == '/' && search[len(search)-1] == '/' {
				re, err := regexp.Compile(search[1 : len(search)-1])
				if err != nil {
					return nil, err
				}

				return re.ReplaceAllString(s, replace), nil
			}

			return strings.Replace(s, search, replace, -1), nil
		},
	}
}

// interpolationFuncSplit implements the "split" function that allows
// strings to split into multi-variable values
func interpolationFuncSplit() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			return strings.Replace(args[1].(string), args[0].(string), InterpSplitDelim, -1), nil
		},
	}
}

// interpolationFuncLookup implements the "lookup" function that allows
// dynamic lookups of map types within a Terraform configuration.
func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			k := fmt.Sprintf("var.%s.%s", args[0].(string), args[1].(string))
			v, ok := vs[k]
			if !ok {
				return "", fmt.Errorf(
					"lookup in '%s' failed to find '%s'",
					args[0].(string), args[1].(string))
			}
			if v.Type != ast.TypeString {
				return "", fmt.Errorf(
					"lookup in '%s' for '%s' has bad type %s",
					args[0].(string), args[1].(string), v.Type)
			}

			return v.Value.(string), nil
		},
	}
}

// interpolationFuncElement implements the "element" function that allows
// a specific index to be looked up in a multi-variable value. Note that this will
// wrap if the index is larger than the number of elements in the multi-variable value.
func interpolationFuncElement() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			list := strings.Split(args[0].(string), InterpSplitDelim)

			index, err := strconv.Atoi(args[1].(string))
			if err != nil {
				return "", fmt.Errorf(
					"invalid number for index, got %s", args[1])
			}

			v := list[index%len(list)]
			return v, nil
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path"
	"strconv"
)

func (c *Config) Name(_ struct{}, serverName *string) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*serverName = c.ServerName
	return nil
}

func (c *Config) List(_ struct{}, list *[]Server) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*list = make([]Server, 0, len(c.Servers))
	for _, s := range c.Servers {
		*list = append(*list, s)
	}
	return nil
}

func (c *Config) Save(s Server, _ *struct{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	ns, ok := c.Servers[s.ID]
	if !ok {
		return ErrNoServer
	}
	s.Path = ns.Path
	s.status = ns.status
	c.Servers[s.ID] = s
	return nil
}

func (c *Config) MapList(_ struct{}, list *[]Map) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*list = make([]Map, 0, len(c.Maps))
	for _, m := range c.Maps {
		*list = append(*list, m)
	}
	return nil
}

type DefaultMap struct {
	Mode                           int
	Name                           string
	GameMode                       int
	Seed                           int64
	Structures, Cheats, BonusChest bool
}

func (c *Config) CreateDefaultMap(data DefaultMap, _ *struct{}) error {
	return nil
}

func setupMapDir() (string, error) {
	num := 0
	for {
		dir := path.Join(config.MapsDir, strconv.Itoa(num))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			err := os.MkdirAll(dir, 0777)
			if err != nil {
				return "", err
			}
			return dir, nil
		}
		num++
	}
}
<commit_msg>Initial map building<commit_after>package main

import (
	"os"
	"path"
	"strconv"
	"sync"

	"github.com/MJKWoolnough/minecraft"
)

func (c *Config) Name(_ struct{}, serverName *string) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*serverName = c.ServerName
	return nil
}

func (c *Config) List(_ struct{}, list *[]Server) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*list = make([]Server, 0, len(c.Servers))
	for _, s := range c.Servers {
		*list = append(*list, s)
	}
	return nil
}

func (c *Config) Save(s Server, _ *struct{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	ns, ok := c.Servers[s.ID]
	if !ok {
		return ErrNoServer
	}
	s.Path = ns.Path
	s.status = ns.status
	c.Servers[s.ID] = s
	return nil
}

func (c *Config) MapList(_ struct{}, list *[]Map) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	*list = make([]Map, 0, len(c.Maps))
	for _, m := range c.Maps {
		*list = append(*list, m)
	}
	return nil
}

type DefaultMap struct {
	Mode                           int
	Name                           string
	GameMode                       int
	Seed                           int64
	Structures, Cheats, BonusChest bool
}

func (c *Config) CreateDefaultMap(data DefaultMap, _ *struct{}) error {
	d, err := setupMapDir()
	if err != nil {
		return err
	}
	p, err := mincraft.NewFilePath(d)
	if err != nil {
		return err
	}
	l, err := minecraft.NewLevel(p)
	if err != nil {
		return err
	}
	l.GameMode(int32(data.GameMode))
	l.LevelName(data.Name)
	switch data.Mode {
	case 0:
		l.Generator(minecraft.DefaultGenerator)
	case 1:
		l.Generator(minecraft.FlatGenerator)
	case 2:
		l.Generator(minecraft.LargeBiomeGenerator)
	case 3:
		l.Generator(minecraft.AmplifiedGenerator)
	case 4:
		l.Generator(minecraft.CustomGenerator)
	}
	l.Seed(data.Seed)
	l.AllowCommands(data.Cheats)
	l.MapFeatures(data.Structures)
	// Find NBT for Bonus Chest
	l.Save()
	return nil
}

var mapDirLock sync.Mutex

func setupMapDir() (string, error) {
	mapDirLock.Lock()
	defer mapDirLock.Unlock()
	num := 0
	for {
		dir := path.Join(config.MapsDir, strconv.Itoa(num))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			err := os.MkdirAll(dir, 0777)
			if err != nil {
				return "", err
			}
			return dir, nil
		}
		num++
	}
}
<|endoftext|>


<commit_before>package gaeutil

import (
	"bytes"
	//"encoding/base64"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"time"

	"golang.org/x/net/context"

	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
)

const Chunksize = 950000  // A single memcache item can't be bigger than 1000000 bytes
const MaxChunks = 32      // We only shard this much.

func singletonMCKey(name string) string { return "singleton:"+name }

func DeleteSingletonFromMemcache(c context.Context, name string) (error) {
	return memcache.Delete(c, name)
}

func LoadSingletonFromMemcache(c context.Context, name string) ([]byte, error) {
	item,err := memcache.Get(c, singletonMCKey(name))
	if err != nil {
    return nil, err  // might be memcache.ErrCacheMiss
	}
	return item.Value, nil
}

func SaveSingletonToMemcache(c context.Context, name string, data []byte) error {
	if len(data) > 950000 {
		return fmt.Errorf("singleton too large (name=%s, size=%d)", name, len(data))
	}
	item := &memcache.Item{Key:singletonMCKey(name), Value:data}
	return memcache.Set(c, item)
}

func LoadShardedSingletonFromMemcache(c context.Context, name string) ([]byte, error) {
	return bytesFromMemcacheShards(c, name)
}
func SaveShardedSingletonToMemcache(c context.Context, name string, data []byte) error {
	return bytesToMemcacheShards(c, name, data)
}

func bytesToMemcacheShards(c context.Context, key string, b []byte) error {
	if len(b) > MaxChunks * Chunksize {
		return fmt.Errorf("obj '%s' was too large; %d > %d", key, len(b), MaxChunks * Chunksize)
	}

	items := []*memcache.Item{}
	for i:=0; i<len(b); i+=Chunksize {
		k := fmt.Sprintf("=%d=%s",i,key)
		s,e := i, i+Chunksize-1
		if e>=len(b) { e = len(b)-1 }
		items = append(items, &memcache.Item{ Key:k , Value:b[s:e+1] }) // slice sytax is [s,e)
	}

	return memcache.SetMulti(c, items)
}

// err might be memcache.ErrCacheMiss
func bytesFromMemcacheShards(c context.Context, key string) ([]byte, error) {
	keys := []string{}
	for i:=0; i<32; i++ { keys = append(keys, fmt.Sprintf("=%d=%s",i*Chunksize,key)) }

	if items,err := memcache.GetMulti(c, keys); err != nil {
		return nil, fmt.Errorf("MCShards/GetMulti/'%s' err: %v\n", key, err)

	} else {
		b := []byte{}
		for i:=0; i<32; i++ {
			if item,exists := items[keys[i]]; exists==false {
				break
			} else {
				b = append(b, item.Value...)
			}
		}

		if len(b) > 0 {
			return b, nil
		} else {
			return nil, memcache.ErrCacheMiss
		}
	}
}

/*

 object := SomeThing{}

 gaeutil.SaveToMemcacheShards(ctx, "mything", &object)

 if err := gaeutil.LoadFromMemcacheShards(ctx, "mything", &object); err == nil {
    // use object
 }

 */

func SaveToMemcacheShards(ctx context.Context, name string, ptr interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(ptr); err != nil {
		return err
	}
	// log.Infof(ctx, "SAVE<%T>, %d bytes", ptr, buf.Len())

	return bytesToMemcacheShards(ctx, name, buf.Bytes())
}

func LoadFromMemcacheShards(ctx context.Context, name string, ptr interface{}) error {
	myBytes,err := bytesFromMemcacheShards(ctx, name)
	if err != nil { return err }

	buf := bytes.NewBuffer(myBytes)
	if err := gob.NewDecoder(buf).Decode(ptr); err != nil {
		log.Errorf(ctx, "LoadFromMemcacheShards err %v", err)
		return err
	}

	//log.Infof(ctx, "LOAD<%T>, %d/%d bytes", ptr, len(myBytes), buf.Len())

	return nil
}

/* TTL versions; if memcache obj older than 'duration', returns memcache.ErrCacheMiss

 object := SomeThing{}
 duration := time.Minute

 err := gaeutil.SaveToMemcacheShardsTTL(ctx, "mything", &object, duration)
 err := gaeutil.LoadFromMemcacheShardsTTL(ctx, "mything", &object)

 */

// Note that the pointer gets flattened in this roundtrip through encoding/gob.
// When submitted to Save*, the interface is a pointer to an object; but when retrived via
// Load*, the interface contains the actual object originally pointed to.
// There is some reflection nonsense needed to copy results between interfaces.
// https://github.com/mohae/deepcopy/blob/master/deepcopy.go
type explodingObj struct {
	Obj interface{}
	Expires time.Time
}

func SaveToMemcacheShardsTTL(ctx context.Context, name string, ptr interface{}, d time.Duration) error {
	return SaveToMemcacheShards(ctx, name, explodingObj{ptr, time.Now().Add(d)})
}

func LoadFromMemcacheShardsTTL(ctx context.Context, name string, ptr interface{}) error {
	eObj := explodingObj{}
	if err := LoadFromMemcacheShards(ctx, name, &eObj); err != nil {
		return err
	} else if time.Now().After(eObj.Expires) {
		return memcache.ErrCacheMiss
	}

	// Assert that 'ptr' is indeed a pointer to something (and is not nil)
	if reflect.TypeOf(ptr).Kind() != reflect.Ptr {
		return fmt.Errorf("interface arg was '%s', expected pointer", reflect.TypeOf(ptr))

	}
	if reflect.ValueOf(ptr).IsNil() {
		return fmt.Errorf("interface arg was nil pointer")
	}

	// Assert that ptr points to the same type of thing that we have in the explodey obj
	if reflect.ValueOf(ptr).Elem().Type() != reflect.TypeOf(eObj.Obj) {
		return fmt.Errorf("type mismatch; asked to load '%s' into '%s'",
			reflect.TypeOf(eObj.Obj), reflect.ValueOf(ptr).Elem().Type())
	}

	// Now copy whatever is inside of eObj.Obj into whatever the pointer points to
	srcValue := reflect.ValueOf(eObj.Obj)
	dstValue := reflect.ValueOf(ptr).Elem() // Follow the pointer
	dstValue.Set(srcValue)

	return nil
}

type memcacheSingletonEntry struct {
	Name   string
	Body []byte
}

// Expects JSON request {"Name": "singletonName", "Body": "BASE64foobar=="}
func SaveSingletonToMemcacheHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.Body == nil {
		http.Error(w, "Please send a JSON encoded request body", http.StatusBadRequest)
		return
	}

	// TODO: use the new type
	entry := memcacheSingletonEntry{}

	if err := json.NewDecoder(r.Body).Decode(&entry); err != nil {
		http.Error(w, fmt.Sprintf("SSTMH/JsonDecode err:%v", err.Error()), http.StatusBadRequest)
		return
	}

	if entry.Name == "" {
		http.Error(w, "SSTMH needs JSON field 'Name'", http.StatusBadRequest)
		return
	}

/*
	// When receiving this object, field Body will have been base64 encoded into a string
	data, err := base64.StdEncoding.DecodeString(string(entry.Body))
	if err != nil {
		http.Error(w, fmt.Sprintf("SSTMH needs JSON base64 'Body'; %v.\nHad:-\n%s\n--\n", err, entry.Body), http.StatusBadRequest)
		return
	} else if len(data) == 0 {
		http.Error(w, "SSTMH 'Body' field was empty'", http.StatusBadRequest)
		return
	}
*/

	if err := SaveSingletonToMemcache(ctx, entry.Name, entry.Body); err != nil {
		http.Error(w, fmt.Sprintf("SSTMH/memcache save err:%v", err), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "OK\n")
}

func SaveSingletonToMemcacheURL(name string, body []byte, url string) error {
	entry := memcacheSingletonEntry{Name:name, Body:body}
	byt,_ := json.Marshal(entry)

	resp,err := http.Post("http://"+url, "application/json; charset=utf-8", bytes.NewBuffer(byt))
	if err != nil {
		return fmt.Errorf("client.Post to %s err: %v\n", url, err)
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		body,_ := ioutil.ReadAll(resp.Body)
		return fmt.Errorf("%s returned %q\n%s\n", url, resp.Status, body)
	}

	return nil
}
<commit_msg>Final tidyups; the new memcache kludge is working<commit_after>package gaeutil

import (
	"bytes"
	//"encoding/base64"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"time"

	"golang.org/x/net/context"

	"google.golang.org/appengine/log"
	"google.golang.org/appengine/memcache"
)

const Chunksize = 950000  // A single memcache item can't be bigger than 1000000 bytes
const MaxChunks = 32      // We only shard this much.

func singletonMCKey(name string) string { return "singleton:"+name }

func DeleteSingletonFromMemcache(c context.Context, name string) (error) {
	return memcache.Delete(c, name)
}

func LoadSingletonFromMemcache(c context.Context, name string) ([]byte, error) {
	item,err := memcache.Get(c, singletonMCKey(name))
	if err != nil {
    return nil, err  // might be memcache.ErrCacheMiss
	}
	return item.Value, nil
}

func SaveSingletonToMemcache(c context.Context, name string, data []byte) error {
	if len(data) > 950000 {
		return fmt.Errorf("singleton too large (name=%s, size=%d)", name, len(data))
	}
	item := &memcache.Item{Key:singletonMCKey(name), Value:data}
	return memcache.Set(c, item)
}

func LoadShardedSingletonFromMemcache(c context.Context, name string) ([]byte, error) {
	return bytesFromMemcacheShards(c, name)
}

func SaveShardedSingletonToMemcache(c context.Context, name string, data []byte) error {
	return bytesToMemcacheShards(c, name, data)
}

func bytesToMemcacheShards(c context.Context, key string, b []byte) error {
	if len(b) > MaxChunks * Chunksize {
		return fmt.Errorf("obj '%s' was too large; %d > %d", key, len(b), MaxChunks * Chunksize)
	}

	items := []*memcache.Item{}
	for i:=0; i<len(b); i+=Chunksize {
		k := fmt.Sprintf("=%d=%s",i,key)
		s,e := i, i+Chunksize-1
		if e>=len(b) { e = len(b)-1 }
		items = append(items, &memcache.Item{ Key:k , Value:b[s:e+1] }) // slice sytax is [s,e)
	}

	return memcache.SetMulti(c, items)
}

// err might be memcache.ErrCacheMiss
func bytesFromMemcacheShards(c context.Context, key string) ([]byte, error) {
	keys := []string{}
	for i:=0; i<32; i++ { keys = append(keys, fmt.Sprintf("=%d=%s",i*Chunksize,key)) }

	if items,err := memcache.GetMulti(c, keys); err != nil {
		return nil, fmt.Errorf("MCShards/GetMulti/'%s' err: %v\n", key, err)

	} else {
		b := []byte{}
		for i:=0; i<32; i++ {
			if item,exists := items[keys[i]]; exists==false {
				break
			} else {
				b = append(b, item.Value...)
			}
		}

		if len(b) > 0 {
			return b, nil
		} else {
			return nil, memcache.ErrCacheMiss
		}
	}
}

/*

 object := SomeThing{}

 gaeutil.SaveToMemcacheShards(ctx, "mything", &object)

 if err := gaeutil.LoadFromMemcacheShards(ctx, "mything", &object); err == nil {
    // use object
 }

 */

func SaveToMemcacheShards(ctx context.Context, name string, ptr interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(ptr); err != nil {
		return err
	}
	// log.Infof(ctx, "SAVE<%T>, %d bytes", ptr, buf.Len())

	return bytesToMemcacheShards(ctx, name, buf.Bytes())
}

func LoadFromMemcacheShards(ctx context.Context, name string, ptr interface{}) error {
	myBytes,err := bytesFromMemcacheShards(ctx, name)
	if err != nil { return err }

	buf := bytes.NewBuffer(myBytes)
	if err := gob.NewDecoder(buf).Decode(ptr); err != nil {
		log.Errorf(ctx, "LoadFromMemcacheShards err %v", err)
		return err
	}

	//log.Infof(ctx, "LOAD<%T>, %d/%d bytes", ptr, len(myBytes), buf.Len())

	return nil
}

/* TTL versions; if memcache obj older than 'duration', returns memcache.ErrCacheMiss

 object := SomeThing{}
 duration := time.Minute

 err := gaeutil.SaveToMemcacheShardsTTL(ctx, "mything", &object, duration)
 err := gaeutil.LoadFromMemcacheShardsTTL(ctx, "mything", &object)

 */

// Note that the pointer gets flattened in this roundtrip through encoding/gob.
// When submitted to Save*, the interface is a pointer to an object; but when retrived via
// Load*, the interface contains the actual object originally pointed to.
// There is some reflection nonsense needed to copy results between interfaces.
// https://github.com/mohae/deepcopy/blob/master/deepcopy.go
type explodingObj struct {
	Obj interface{}
	Expires time.Time
}

func SaveToMemcacheShardsTTL(ctx context.Context, name string, ptr interface{}, d time.Duration) error {
	return SaveToMemcacheShards(ctx, name, explodingObj{ptr, time.Now().Add(d)})
}

func LoadFromMemcacheShardsTTL(ctx context.Context, name string, ptr interface{}) error {
	eObj := explodingObj{}
	if err := LoadFromMemcacheShards(ctx, name, &eObj); err != nil {
		return err
	} else if time.Now().After(eObj.Expires) {
		return memcache.ErrCacheMiss
	}

	// Assert that 'ptr' is indeed a pointer to something (and is not nil)
	if reflect.TypeOf(ptr).Kind() != reflect.Ptr {
		return fmt.Errorf("interface arg was '%s', expected pointer", reflect.TypeOf(ptr))

	}
	if reflect.ValueOf(ptr).IsNil() {
		return fmt.Errorf("interface arg was nil pointer")
	}

	// Assert that ptr points to the same type of thing that we have in the explodey obj
	if reflect.ValueOf(ptr).Elem().Type() != reflect.TypeOf(eObj.Obj) {
		return fmt.Errorf("type mismatch; asked to load '%s' into '%s'",
			reflect.TypeOf(eObj.Obj), reflect.ValueOf(ptr).Elem().Type())
	}

	// Now copy whatever is inside of eObj.Obj into whatever the pointer points to
	srcValue := reflect.ValueOf(eObj.Obj)
	dstValue := reflect.ValueOf(ptr).Elem() // Follow the pointer
	dstValue.Set(srcValue)

	return nil
}

// The SaveSingletonToMemcache* routines are a kludge to allow appengine flexible
// environment apps (e.g. the pi/cmd/consolidator) to write into memcache, in the absence
// of any cloud APIs for doing so. The actual write is done by a friendly appengine standard
// app (e.g. flightdb/app/frontend), running a handler, which the appengine flexible app sends
// a POST to.

// memcacheSingletonEntry is for data transfer by HTTP
type memcacheSingletonEntry struct {
	Name   string
	Body []byte
}

// SaveSingletonToMemcacheHandler is a HTTP handler that expects an application/json request
// body that encodes a memcacheSingletonEntry struct. (The golang json libs take care of all
// the base64 encoding/decoding transparently). The entry will be written into memcache.
func SaveSingletonToMemcacheHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.Body == nil {
		http.Error(w, "Please send a JSON encoded request body", http.StatusBadRequest)
		return
	}

	entry := memcacheSingletonEntry{}
	if err := json.NewDecoder(r.Body).Decode(&entry); err != nil {
		http.Error(w, fmt.Sprintf("SSTMH/JsonDecode err:%v", err.Error()), http.StatusBadRequest)
		return
	} else if entry.Name == "" {
		http.Error(w, "SSTMH needs non-empty 'Name'", http.StatusBadRequest)
		return
	}

	if err := SaveSingletonToMemcache(ctx, entry.Name, entry.Body); err != nil {
		http.Error(w, fmt.Sprintf("SSTMH/memcache save err:%v", err), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "OK\n")
}

// SaveSingletonToMemcacheURL sends a HTTP request to the given URL, which should route to
// the SaveSingletonToMemcacheHandler routine above.
func SaveSingletonToMemcacheURL(name string, body []byte, url string) error {
	byt,_ := json.Marshal(memcacheSingletonEntry{Name:name, Body:body})

	resp,err := http.Post("http://"+url, "application/json; charset=utf-8", bytes.NewBuffer(byt))
	if err != nil {
		return fmt.Errorf("client.Post to %s err: %v\n", url, err)
	} else if resp.StatusCode != http.StatusOK {
		defer resp.Body.Close()
		body,_ := ioutil.ReadAll(resp.Body)
		return fmt.Errorf("%s returned %q\n%s\n", url, resp.Status, body)
	}

	return nil
}
<|endoftext|>


<commit_before>package raft

import pb "github.com/relab/raft/raftpb"

// QuorumSpec holds information about the quorum size of the current
// configuration and allows us to invoke QRPCs.
// TODO Rename so it's not confused with gorums.QuorumSpec
type QuorumSpec struct {
	N int
	Q int
}

// RequestVoteQF gathers RequestVoteResponses and delivers a reply when a higher
// term is seen or a quorum of votes is received.
// TODO Implements gorums.QuorumSpec interface.
func (qs *QuorumSpec) RequestVoteQF(req *pb.RequestVoteRequest, replies []*pb.RequestVoteResponse) (*pb.RequestVoteResponse, bool) {
	// Make copy of last reply.
	response := *replies[len(replies)-1]

	if response.Term > req.Term {
		// Abort.
		return &response, true
	}

	// Being past this point means last.Term == req.Term.

	var votes int

	for _, reply := range replies {
		// Tally votes.
		if reply.VoteGranted {
			votes++
		}

	}

	if votes >= qs.Q {
		// Quorum.
		response.VoteGranted = true
		return &response, true
	}

	if len(replies) < qs.N {
		// Wait for more replies.
		return nil, false
	}

	return nil, true
}

// AppendEntriesQF gathers AppendEntriesResponses and calculates the log entries
// replicated, depending on the quorum configuration.
// TODO Implements gorums.QuorumSpec interface.
func (qs *QuorumSpec) AppendEntriesQF(req *pb.AppendEntriesRequest, replies []*pb.AppendEntriesResponse) (*pb.AppendEntriesResponse, bool) {
	// Make copy of last reply.
	response := *replies[len(replies)-1]

	if response.Term > req.Term {
		// Abort.
		return &response, true
	}

	// Being past this point means last.Term == req.Term.

	var successful int
	minMatch := ^uint64(0)   // Largest uint64.
	response.Success = false // Default to unsuccessful.

	for _, r := range replies {
		// Track lowest match index.
		if r.MatchIndex < minMatch {
			minMatch = r.MatchIndex
		}

		// Count successful.
		if r.Success {
			response.MatchIndex = r.MatchIndex
			successful++
		}
	}

	if successful >= qs.Q {
		// Quorum.
		response.Success = true
		return &response, true
	}

	response.MatchIndex = minMatch

	// Wait for more replies. Return response, even on failure. This allows
	// raft to back off and try a lower match index.

	if len(replies) < qs.N {
		return &response, false
	}

	return &response, true
}
<commit_msg>qspec.go: Use MaxUint64 from math package<commit_after>package raft

import (
	"math"

	pb "github.com/relab/raft/raftpb"
)

// QuorumSpec holds information about the quorum size of the current
// configuration and allows us to invoke QRPCs.
// TODO Rename so it's not confused with gorums.QuorumSpec
type QuorumSpec struct {
	N int
	Q int
}

// RequestVoteQF gathers RequestVoteResponses and delivers a reply when a higher
// term is seen or a quorum of votes is received.
// TODO Implements gorums.QuorumSpec interface.
func (qs *QuorumSpec) RequestVoteQF(req *pb.RequestVoteRequest, replies []*pb.RequestVoteResponse) (*pb.RequestVoteResponse, bool) {
	// Make copy of last reply.
	response := *replies[len(replies)-1]

	if response.Term > req.Term {
		// Abort.
		return &response, true
	}

	// Being past this point means last.Term == req.Term.

	var votes int

	for _, reply := range replies {
		// Tally votes.
		if reply.VoteGranted {
			votes++
		}

	}

	if votes >= qs.Q {
		// Quorum.
		response.VoteGranted = true
		return &response, true
	}

	if len(replies) < qs.N {
		// Wait for more replies.
		return nil, false
	}

	return nil, true
}

// AppendEntriesQF gathers AppendEntriesResponses and calculates the log entries
// replicated, depending on the quorum configuration.
// TODO Implements gorums.QuorumSpec interface.
func (qs *QuorumSpec) AppendEntriesQF(req *pb.AppendEntriesRequest, replies []*pb.AppendEntriesResponse) (*pb.AppendEntriesResponse, bool) {
	// Make copy of last reply.
	response := *replies[len(replies)-1]

	if response.Term > req.Term {
		// Abort.
		return &response, true
	}

	// Being past this point means last.Term == req.Term.

	var successful int
	var minMatch uint64 = math.MaxUint64
	response.Success = false // Default to unsuccessful.

	for _, r := range replies {
		// Track lowest match index.
		if r.MatchIndex < minMatch {
			minMatch = r.MatchIndex
		}

		// Count successful.
		if r.Success {
			response.MatchIndex = r.MatchIndex
			successful++
		}
	}

	if successful >= qs.Q {
		// Quorum.
		response.Success = true
		return &response, true
	}

	response.MatchIndex = minMatch

	// Wait for more replies. Return response, even on failure. This allows
	// raft to back off and try a lower match index.

	if len(replies) < qs.N {
		return &response, false
	}

	return &response, true
}
<|endoftext|>


<commit_before>package mysqldriver

import (
	"strconv"

	"github.com/pubnative/mysqlproto-go"
)

// Rows represents result set of SELECT query
type Rows struct {
	resultSet mysqlproto.ResultSet
	packet    []byte
	offset    uint64
	eof       bool
	err       error
}

// Next moves cursor to the next unread row.
// It returns false when there are no more rows left
// or an error occurred during reading rows (see LastError() function)
// This function must be called before reading first row
// and continue being called until it returns false.
//  rows, _ := conn.Query("SELECT * FROM people LIMIT 2")
//  rows.Next() // move cursor to the first row
//  // read values from the first row
//  rows.Next() // move cursor to the second row
//  // read values from the second row
//  rows.Next() // drain the stream
// Best practice is to call Next() function in a loop:
//  rows, _ := conn.Query("SELECT * FROM people")
//  for rows.Next() {
//  	// read values from the row
//  }
// It's required to read all rows before performing another query
// because connection contains sequential stream of rows.
//  rows, _ := conn.Query("SELECT name FROM dogs LIMIT 1")
//  rows.Next()   // move cursor to the first row
//  rows.String() // dog's name
//  rows, _ = conn.Query("SELECT name FROM cats LIMIT 2")
//  rows.Next()   // move cursor to the second row of first query
//  rows.String() // still dog's name
//  rows.Next()   // returns false. closes the first stream of rows
//  rows.Next()   // move cursor to the first row of second query
//  rows.String() // cat's name
//  rows.Next()   // returns false. closes the second stream of rows
func (r *Rows) Next() bool {
	if r.eof {
		return false
	}

	if r.err != nil {
		return false
	}

	packet, err := r.resultSet.Row()
	if err != nil {
		r.err = err
		r.eof = true
		return false
	}

	if packet == nil {
		r.eof = true
		return false
	} else {
		r.packet = packet
		r.offset = 0
		return true
	}
}

func (r *Rows) Bytes() []byte {
	value, offset, _ := mysqlproto.ReadRowValue(r.packet, r.offset)
	r.offset = offset
	return value
}

func (r *Rows) NullBytes() ([]byte, bool) {
	value, offset, null := mysqlproto.ReadRowValue(r.packet, r.offset)
	r.offset = offset
	return value, null
}

func (r *Rows) String() string {
	return string(r.Bytes())
}

func (r *Rows) NullString() (string, bool) {
	data, null := r.NullBytes()
	return string(data), null
}

func (r *Rows) Int() int {
	num, _ := r.NullInt()
	return num
}

func (r *Rows) NullInt() (int, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.Atoi(str)
	if err != nil {
		r.err = err
	}

	return num, false
}

func (r *Rows) Int8() int8 {
	num, _ := r.NullInt8()
	return num
}

func (r *Rows) NullInt8() (int8, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 8)
	if err != nil {
		r.err = err
	}

	return int8(num), false
}

func (r *Rows) Int16() int16 {
	num, _ := r.NullInt16()
	return num
}

func (r *Rows) NullInt16() (int16, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 16)
	if err != nil {
		r.err = err
	}

	return int16(num), false
}

func (r *Rows) Int32() int32 {
	num, _ := r.NullInt32()
	return num
}

func (r *Rows) NullInt32() (int32, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 32)
	if err != nil {
		r.err = err
	}

	return int32(num), false
}

func (r *Rows) Int64() int64 {
	num, _ := r.NullInt64()
	return num
}

func (r *Rows) NullInt64() (int64, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		r.err = err
	}

	return int64(num), false
}

func (r *Rows) Float32() float32 {
	num, _ := r.NullFloat32()
	return num
}

func (r *Rows) NullFloat32() (float32, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseFloat(str, 32)
	if err != nil {
		r.err = err
	}

	return float32(num), false
}

func (r *Rows) Float64() float64 {
	num, _ := r.NullFloat64()
	return num
}

func (r *Rows) NullFloat64() (float64, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseFloat(str, 64)
	if err != nil {
		r.err = err
	}

	return num, false
}

func (r *Rows) Bool() bool {
	b, _ := r.NullBool()
	return b
}

func (r *Rows) NullBool() (bool, bool) {
	str, null := r.NullString()
	if null {
		return false, true
	}

	b, err := strconv.ParseBool(str)
	if err != nil {
		r.err = err
	}
	return b, false
}

// LastError returns the error if any occurred during
// reading result set of SELECT query. This method should
// be always called after reading all rows.
//  rows, err := conn.Query("SELECT * FROM dogs")
//  if err != nil {
//  	// handle error
//  }
//  for rows.Next() {
//  	// read values
//  }
//  if err = rows.LastError(); err != nil {
//  	// handle error
//  }
func (r *Rows) LastError() error {
	return r.err
}

func (c Conn) Query(sql string) (*Rows, error) {
	req := mysqlproto.ComQueryRequest([]byte(sql))
	if _, err := c.conn.Write(req); err != nil {
		return nil, err
	}

	resultSet, err := mysqlproto.ComQueryResponse(c.conn)
	if err != nil {
		return nil, err
	}

	return &Rows{resultSet: resultSet}, nil
}

func (c Conn) Exec(sql string) (mysqlproto.OKPacket, error) {
	req := mysqlproto.ComQueryRequest([]byte(sql))
	if _, err := c.conn.Write(req); err != nil {
		return mysqlproto.OKPacket{}, err
	}

	packet, err := c.conn.NextPacket()
	if err != nil {
		return mysqlproto.OKPacket{}, err
	}

	if packet.Payload[0] == mysqlproto.OK_PACKET {
		pkt, err := mysqlproto.ParseOKPacket(packet.Payload, c.conn.CapabilityFlags)
		return pkt, err
	} else {
		pkt, err := mysqlproto.ParseERRPacket(packet.Payload, c.conn.CapabilityFlags)
		if err == nil {
			return mysqlproto.OKPacket{}, pkt
		} else {
			return mysqlproto.OKPacket{}, err
		}
	}
}
<commit_msg>Document func (Conn) Exec<commit_after>package mysqldriver

import (
	"strconv"

	"github.com/pubnative/mysqlproto-go"
)

// Rows represents result set of SELECT query
type Rows struct {
	resultSet mysqlproto.ResultSet
	packet    []byte
	offset    uint64
	eof       bool
	err       error
}

// Next moves cursor to the next unread row.
// It returns false when there are no more rows left
// or an error occurred during reading rows (see LastError() function)
// This function must be called before reading first row
// and continue being called until it returns false.
//  rows, _ := conn.Query("SELECT * FROM people LIMIT 2")
//  rows.Next() // move cursor to the first row
//  // read values from the first row
//  rows.Next() // move cursor to the second row
//  // read values from the second row
//  rows.Next() // drain the stream
// Best practice is to call Next() function in a loop:
//  rows, _ := conn.Query("SELECT * FROM people")
//  for rows.Next() {
//  	// read values from the row
//  }
// It's required to read all rows before performing another query
// because connection contains sequential stream of rows.
//  rows, _ := conn.Query("SELECT name FROM dogs LIMIT 1")
//  rows.Next()   // move cursor to the first row
//  rows.String() // dog's name
//  rows, _ = conn.Query("SELECT name FROM cats LIMIT 2")
//  rows.Next()   // move cursor to the second row of first query
//  rows.String() // still dog's name
//  rows.Next()   // returns false. closes the first stream of rows
//  rows.Next()   // move cursor to the first row of second query
//  rows.String() // cat's name
//  rows.Next()   // returns false. closes the second stream of rows
func (r *Rows) Next() bool {
	if r.eof {
		return false
	}

	if r.err != nil {
		return false
	}

	packet, err := r.resultSet.Row()
	if err != nil {
		r.err = err
		r.eof = true
		return false
	}

	if packet == nil {
		r.eof = true
		return false
	} else {
		r.packet = packet
		r.offset = 0
		return true
	}
}

func (r *Rows) Bytes() []byte {
	value, offset, _ := mysqlproto.ReadRowValue(r.packet, r.offset)
	r.offset = offset
	return value
}

func (r *Rows) NullBytes() ([]byte, bool) {
	value, offset, null := mysqlproto.ReadRowValue(r.packet, r.offset)
	r.offset = offset
	return value, null
}

func (r *Rows) String() string {
	return string(r.Bytes())
}

func (r *Rows) NullString() (string, bool) {
	data, null := r.NullBytes()
	return string(data), null
}

func (r *Rows) Int() int {
	num, _ := r.NullInt()
	return num
}

func (r *Rows) NullInt() (int, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.Atoi(str)
	if err != nil {
		r.err = err
	}

	return num, false
}

func (r *Rows) Int8() int8 {
	num, _ := r.NullInt8()
	return num
}

func (r *Rows) NullInt8() (int8, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 8)
	if err != nil {
		r.err = err
	}

	return int8(num), false
}

func (r *Rows) Int16() int16 {
	num, _ := r.NullInt16()
	return num
}

func (r *Rows) NullInt16() (int16, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 16)
	if err != nil {
		r.err = err
	}

	return int16(num), false
}

func (r *Rows) Int32() int32 {
	num, _ := r.NullInt32()
	return num
}

func (r *Rows) NullInt32() (int32, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 32)
	if err != nil {
		r.err = err
	}

	return int32(num), false
}

func (r *Rows) Int64() int64 {
	num, _ := r.NullInt64()
	return num
}

func (r *Rows) NullInt64() (int64, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		r.err = err
	}

	return int64(num), false
}

func (r *Rows) Float32() float32 {
	num, _ := r.NullFloat32()
	return num
}

func (r *Rows) NullFloat32() (float32, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseFloat(str, 32)
	if err != nil {
		r.err = err
	}

	return float32(num), false
}

func (r *Rows) Float64() float64 {
	num, _ := r.NullFloat64()
	return num
}

func (r *Rows) NullFloat64() (float64, bool) {
	str, null := r.NullString()
	if null {
		return 0, true
	}

	num, err := strconv.ParseFloat(str, 64)
	if err != nil {
		r.err = err
	}

	return num, false
}

func (r *Rows) Bool() bool {
	b, _ := r.NullBool()
	return b
}

func (r *Rows) NullBool() (bool, bool) {
	str, null := r.NullString()
	if null {
		return false, true
	}

	b, err := strconv.ParseBool(str)
	if err != nil {
		r.err = err
	}
	return b, false
}

// LastError returns the error if any occurred during
// reading result set of SELECT query. This method should
// be always called after reading all rows.
//  rows, err := conn.Query("SELECT * FROM dogs")
//  if err != nil {
//  	// handle error
//  }
//  for rows.Next() {
//  	// read values
//  }
//  if err = rows.LastError(); err != nil {
//  	// handle error
//  }
func (r *Rows) LastError() error {
	return r.err
}

func (c Conn) Query(sql string) (*Rows, error) {
	req := mysqlproto.ComQueryRequest([]byte(sql))
	if _, err := c.conn.Write(req); err != nil {
		return nil, err
	}

	resultSet, err := mysqlproto.ComQueryResponse(c.conn)
	if err != nil {
		return nil, err
	}

	return &Rows{resultSet: resultSet}, nil
}

// Exec executes queries or other commands which expect to return OK_PACKET
// including INSERT/UPDATE/DELETE queries. For SELECT query see func (Conn) Query
//  okPacket, err := conn.Exec("DELETE FROM dogs WHERE id = 1")
//	if err == nil {
//  	return nil // query was performed successfully
//  }
//  if errPacket, ok := err.(mysqlproto.ERRPacket); ok {
//  	return errPacket // retrieve more information about the error
//  } else {
//  	return err // generic error
//  }
func (c Conn) Exec(sql string) (mysqlproto.OKPacket, error) {
	req := mysqlproto.ComQueryRequest([]byte(sql))
	if _, err := c.conn.Write(req); err != nil {
		return mysqlproto.OKPacket{}, err
	}

	packet, err := c.conn.NextPacket()
	if err != nil {
		return mysqlproto.OKPacket{}, err
	}

	if packet.Payload[0] == mysqlproto.OK_PACKET {
		pkt, err := mysqlproto.ParseOKPacket(packet.Payload, c.conn.CapabilityFlags)
		return pkt, err
	} else {
		pkt, err := mysqlproto.ParseERRPacket(packet.Payload, c.conn.CapabilityFlags)
		if err == nil {
			return mysqlproto.OKPacket{}, pkt
		} else {
			return mysqlproto.OKPacket{}, err
		}
	}
}
<|endoftext|>


<commit_before>package pgx

import (
	"database/sql"
	"errors"
	"fmt"
	"time"
)

// Row is a convenience wrapper over Rows that is returned by QueryRow.
type Row Rows

// Scan works the same as (*Rows Scan) with the following exceptions. If no
// rows were found it returns ErrNoRows. If multiple rows are returned it
// ignores all but the first.
func (r *Row) Scan(dest ...interface{}) (err error) {
	rows := (*Rows)(r)

	if rows.Err() != nil {
		return rows.Err()
	}

	if !rows.Next() {
		if rows.Err() == nil {
			return ErrNoRows
		}
		return rows.Err()
	}

	rows.Scan(dest...)
	rows.Close()
	return rows.Err()
}

// Rows is the result set returned from *Conn.Query. Rows must be closed before
// the *Conn can be used again. Rows are closed by explicitly calling Close(),
// calling Next() until it returns false, or when a fatal error occurs.
type Rows struct {
	conn       *Conn
	mr         *msgReader
	fields     []FieldDescription
	vr         ValueReader
	rowCount   int
	columnIdx  int
	err        error
	startTime  time.Time
	sql        string
	args       []interface{}
	log        func(lvl int, msg string, ctx ...interface{})
	shouldLog  func(lvl int) bool
	afterClose func(*Rows)
	unlockConn bool
	closed     bool
}

func (rows *Rows) FieldDescriptions() []FieldDescription {
	return rows.fields
}

func (rows *Rows) close() {
	if rows.closed {
		return
	}

	if rows.unlockConn {
		rows.conn.unlock()
		rows.unlockConn = false
	}

	rows.closed = true

	if rows.err == nil {
		if rows.shouldLog(LogLevelInfo) {
			endTime := time.Now()
			rows.log(LogLevelInfo, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args), "time", endTime.Sub(rows.startTime), "rowCount", rows.rowCount)
		}
	} else if rows.shouldLog(LogLevelError) {
		rows.log(LogLevelError, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args))
	}

	if rows.afterClose != nil {
		rows.afterClose(rows)
	}
}

func (rows *Rows) readUntilReadyForQuery() {
	for {
		t, r, err := rows.conn.rxMsg()
		if err != nil {
			rows.close()
			return
		}

		switch t {
		case readyForQuery:
			rows.conn.rxReadyForQuery(r)
			rows.close()
			return
		case rowDescription:
		case dataRow:
		case commandComplete:
		case bindComplete:
		case errorResponse:
			err = rows.conn.rxErrorResponse(r)
			if rows.err == nil {
				rows.err = err
			}
		default:
			err = rows.conn.processContextFreeMsg(t, r)
			if err != nil {
				rows.close()
				return
			}
		}
	}
}

// Close closes the rows, making the connection ready for use again. It is safe
// to call Close after rows is already closed.
func (rows *Rows) Close() {
	if rows.closed {
		return
	}
	rows.readUntilReadyForQuery()
	rows.close()
}

func (rows *Rows) Err() error {
	return rows.err
}

// abort signals that the query was not successfully sent to the server.
// This differs from Fatal in that it is not necessary to readUntilReadyForQuery
func (rows *Rows) abort(err error) {
	if rows.err != nil {
		return
	}

	rows.err = err
	rows.close()
}

// Fatal signals an error occurred after the query was sent to the server. It
// closes the rows automatically.
func (rows *Rows) Fatal(err error) {
	if rows.err != nil {
		return
	}

	rows.err = err
	rows.Close()
}

// Next prepares the next row for reading. It returns true if there is another
// row and false if no more rows are available. It automatically closes rows
// when all rows are read.
func (rows *Rows) Next() bool {
	if rows.closed {
		return false
	}

	rows.rowCount++
	rows.columnIdx = 0
	rows.vr = ValueReader{}

	for {
		t, r, err := rows.conn.rxMsg()
		if err != nil {
			rows.Fatal(err)
			return false
		}

		switch t {
		case readyForQuery:
			rows.conn.rxReadyForQuery(r)
			rows.close()
			return false
		case dataRow:
			fieldCount := r.readInt16()
			if int(fieldCount) != len(rows.fields) {
				rows.Fatal(ProtocolError(fmt.Sprintf("Row description field count (%v) and data row field count (%v) do not match", len(rows.fields), fieldCount)))
				return false
			}

			rows.mr = r
			return true
		case commandComplete:
		case bindComplete:
		default:
			err = rows.conn.processContextFreeMsg(t, r)
			if err != nil {
				rows.Fatal(err)
				return false
			}
		}
	}
}

// Conn returns the *Conn this *Rows is using.
func (rows *Rows) Conn() *Conn {
	return rows.conn
}

func (rows *Rows) nextColumn() (*ValueReader, bool) {
	if rows.closed {
		return nil, false
	}
	if len(rows.fields) <= rows.columnIdx {
		rows.Fatal(ProtocolError("No next column available"))
		return nil, false
	}

	if rows.vr.Len() > 0 {
		rows.mr.readBytes(rows.vr.Len())
	}

	fd := &rows.fields[rows.columnIdx]
	rows.columnIdx++
	size := rows.mr.readInt32()
	rows.vr = ValueReader{mr: rows.mr, fd: fd, valueBytesRemaining: size}
	return &rows.vr, true
}

type scanArgError struct {
	col int
	err error
}

func (e scanArgError) Error() string {
	return fmt.Sprintf("can't scan into dest[%d]: %v", e.col, e.err)
}

// Scan reads the values from the current row into dest values positionally.
// dest can include pointers to core types, values implementing the Scanner
// interface, []byte, and nil. []byte will skip the decoding process and directly
// copy the raw bytes received from PostgreSQL. nil will skip the value entirely.
func (rows *Rows) Scan(dest ...interface{}) (err error) {
	if len(rows.fields) != len(dest) {
		err = fmt.Errorf("Scan received wrong number of arguments, got %d but expected %d", len(dest), len(rows.fields))
		rows.Fatal(err)
		return err
	}

	for i, d := range dest {
		vr, _ := rows.nextColumn()

		if d == nil {
			continue
		}

		// Check for []byte first as we allow sidestepping the decoding process and retrieving the raw bytes
		if b, ok := d.(*[]byte); ok {
			// If it actually is a bytea then pass it through decodeBytea (so it can be decoded if it is in text format)
			// Otherwise read the bytes directly regardless of what the actual type is.
			if vr.Type().DataType == ByteaOid {
				*b = decodeBytea(vr)
			} else {
				if vr.Len() != -1 {
					*b = vr.ReadBytes(vr.Len())
				} else {
					*b = nil
				}
			}
		} else if s, ok := d.(Scanner); ok {
			err = s.Scan(vr)
			if err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		} else if s, ok := d.(sql.Scanner); ok {
			var val interface{}
			if 0 <= vr.Len() {
				switch vr.Type().DataType {
				case BoolOid:
					val = decodeBool(vr)
				case Int8Oid:
					val = int64(decodeInt8(vr))
				case Int2Oid:
					val = int64(decodeInt2(vr))
				case Int4Oid:
					val = int64(decodeInt4(vr))
				case TextOid, VarcharOid:
					val = decodeText(vr)
				case OidOid:
					val = int64(decodeOid(vr))
				case Float4Oid:
					val = float64(decodeFloat4(vr))
				case Float8Oid:
					val = decodeFloat8(vr)
				case DateOid:
					val = decodeDate(vr)
				case TimestampOid:
					val = decodeTimestamp(vr)
				case TimestampTzOid:
					val = decodeTimestampTz(vr)
				default:
					val = vr.ReadBytes(vr.Len())
				}
			}
			err = s.Scan(val)
			if err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		} else if vr.Type().DataType == JsonOid || vr.Type().DataType == JsonbOid {
			decodeJSON(vr, &d)
		} else {
			if err := Decode(vr, d); err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		}
		if vr.Err() != nil {
			rows.Fatal(scanArgError{col: i, err: vr.Err()})
		}

		if rows.Err() != nil {
			return rows.Err()
		}
	}

	return nil
}

// Values returns an array of the row values
func (rows *Rows) Values() ([]interface{}, error) {
	if rows.closed {
		return nil, errors.New("rows is closed")
	}

	values := make([]interface{}, 0, len(rows.fields))

	for range rows.fields {
		vr, _ := rows.nextColumn()

		if vr.Len() == -1 {
			values = append(values, nil)
			continue
		}

		switch vr.Type().FormatCode {
		// All intrinsic types (except string) are encoded with binary
		// encoding so anything else should be treated as a string
		case TextFormatCode:
			values = append(values, vr.ReadString(vr.Len()))
		case BinaryFormatCode:
			switch vr.Type().DataType {
			case BoolOid:
				values = append(values, decodeBool(vr))
			case ByteaOid:
				values = append(values, decodeBytea(vr))
			case Int8Oid:
				values = append(values, decodeInt8(vr))
			case Int2Oid:
				values = append(values, decodeInt2(vr))
			case Int4Oid:
				values = append(values, decodeInt4(vr))
			case OidOid:
				values = append(values, decodeOid(vr))
			case Float4Oid:
				values = append(values, decodeFloat4(vr))
			case Float8Oid:
				values = append(values, decodeFloat8(vr))
			case BoolArrayOid:
				values = append(values, decodeBoolArray(vr))
			case Int2ArrayOid:
				values = append(values, decodeInt2Array(vr))
			case Int4ArrayOid:
				values = append(values, decodeInt4Array(vr))
			case Int8ArrayOid:
				values = append(values, decodeInt8Array(vr))
			case Float4ArrayOid:
				values = append(values, decodeFloat4Array(vr))
			case Float8ArrayOid:
				values = append(values, decodeFloat8Array(vr))
			case TextArrayOid, VarcharArrayOid:
				values = append(values, decodeTextArray(vr))
			case TimestampArrayOid, TimestampTzArrayOid:
				values = append(values, decodeTimestampArray(vr))
			case DateOid:
				values = append(values, decodeDate(vr))
			case TimestampTzOid:
				values = append(values, decodeTimestampTz(vr))
			case TimestampOid:
				values = append(values, decodeTimestamp(vr))
			case InetOid, CidrOid:
				values = append(values, decodeInet(vr))
			case JsonOid:
				var d interface{}
				decodeJSON(vr, &d)
				values = append(values, d)
			case JsonbOid:
				var d interface{}
				decodeJSON(vr, &d)
				values = append(values, d)
			default:
				rows.Fatal(errors.New("Values cannot handle binary format non-intrinsic types"))
			}
		default:
			rows.Fatal(errors.New("Unknown format code"))
		}

		if vr.Err() != nil {
			rows.Fatal(vr.Err())
		}

		if rows.Err() != nil {
			return nil, rows.Err()
		}
	}

	return values, rows.Err()
}

// AfterClose adds f to a LILO queue of functions that will be called when
// rows is closed.
func (rows *Rows) AfterClose(f func(*Rows)) {
	if rows.afterClose == nil {
		rows.afterClose = f
	} else {
		prevFn := rows.afterClose
		rows.afterClose = func(rows *Rows) {
			f(rows)
			prevFn(rows)
		}
	}
}

// Query executes sql with args. If there is an error the returned *Rows will
// be returned in an error state. So it is allowed to ignore the error returned
// from Query and handle it in *Rows.
func (c *Conn) Query(sql string, args ...interface{}) (*Rows, error) {
	c.lastActivityTime = time.Now()

	rows := c.getRows(sql, args)

	if err := c.lock(); err != nil {
		rows.abort(err)
		return rows, err
	}
	rows.unlockConn = true

	ps, ok := c.preparedStatements[sql]
	if !ok {
		var err error
		ps, err = c.Prepare("", sql)
		if err != nil {
			rows.abort(err)
			return rows, rows.err
		}
	}

	rows.fields = ps.FieldDescriptions
	err := c.sendPreparedQuery(ps, args...)
	if err != nil {
		rows.abort(err)
	}
	return rows, rows.err
}

func (c *Conn) getRows(sql string, args []interface{}) *Rows {
	if len(c.preallocatedRows) == 0 {
		c.preallocatedRows = make([]Rows, 64)
		return c.getRows(sql, args)
	}

	r := &c.preallocatedRows[len(c.preallocatedRows)-1]
	c.preallocatedRows = c.preallocatedRows[0 : len(c.preallocatedRows)-1]

	r.conn = c
	r.startTime = c.lastActivityTime
	r.sql = sql
	r.args = args
	r.log = c.log
	r.shouldLog = c.shouldLog

	return r
}

// QueryRow is a convenience wrapper over Query. Any error that occurs while
// querying is deferred until calling Scan on the returned *Row. That *Row will
// error with ErrNoRows if no rows are returned.
func (c *Conn) QueryRow(sql string, args ...interface{}) *Row {
	rows, _ := c.Query(sql, args...)
	return (*Row)(rows)
}
<commit_msg>Prevent every row scan from causing a malloc<commit_after>package pgx

import (
	"database/sql"
	"errors"
	"fmt"
	"time"
)

// Row is a convenience wrapper over Rows that is returned by QueryRow.
type Row Rows

// Scan works the same as (*Rows Scan) with the following exceptions. If no
// rows were found it returns ErrNoRows. If multiple rows are returned it
// ignores all but the first.
func (r *Row) Scan(dest ...interface{}) (err error) {
	rows := (*Rows)(r)

	if rows.Err() != nil {
		return rows.Err()
	}

	if !rows.Next() {
		if rows.Err() == nil {
			return ErrNoRows
		}
		return rows.Err()
	}

	rows.Scan(dest...)
	rows.Close()
	return rows.Err()
}

// Rows is the result set returned from *Conn.Query. Rows must be closed before
// the *Conn can be used again. Rows are closed by explicitly calling Close(),
// calling Next() until it returns false, or when a fatal error occurs.
type Rows struct {
	conn       *Conn
	mr         *msgReader
	fields     []FieldDescription
	vr         ValueReader
	rowCount   int
	columnIdx  int
	err        error
	startTime  time.Time
	sql        string
	args       []interface{}
	log        func(lvl int, msg string, ctx ...interface{})
	shouldLog  func(lvl int) bool
	afterClose func(*Rows)
	unlockConn bool
	closed     bool
}

func (rows *Rows) FieldDescriptions() []FieldDescription {
	return rows.fields
}

func (rows *Rows) close() {
	if rows.closed {
		return
	}

	if rows.unlockConn {
		rows.conn.unlock()
		rows.unlockConn = false
	}

	rows.closed = true

	if rows.err == nil {
		if rows.shouldLog(LogLevelInfo) {
			endTime := time.Now()
			rows.log(LogLevelInfo, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args), "time", endTime.Sub(rows.startTime), "rowCount", rows.rowCount)
		}
	} else if rows.shouldLog(LogLevelError) {
		rows.log(LogLevelError, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args))
	}

	if rows.afterClose != nil {
		rows.afterClose(rows)
	}
}

func (rows *Rows) readUntilReadyForQuery() {
	for {
		t, r, err := rows.conn.rxMsg()
		if err != nil {
			rows.close()
			return
		}

		switch t {
		case readyForQuery:
			rows.conn.rxReadyForQuery(r)
			rows.close()
			return
		case rowDescription:
		case dataRow:
		case commandComplete:
		case bindComplete:
		case errorResponse:
			err = rows.conn.rxErrorResponse(r)
			if rows.err == nil {
				rows.err = err
			}
		default:
			err = rows.conn.processContextFreeMsg(t, r)
			if err != nil {
				rows.close()
				return
			}
		}
	}
}

// Close closes the rows, making the connection ready for use again. It is safe
// to call Close after rows is already closed.
func (rows *Rows) Close() {
	if rows.closed {
		return
	}
	rows.readUntilReadyForQuery()
	rows.close()
}

func (rows *Rows) Err() error {
	return rows.err
}

// abort signals that the query was not successfully sent to the server.
// This differs from Fatal in that it is not necessary to readUntilReadyForQuery
func (rows *Rows) abort(err error) {
	if rows.err != nil {
		return
	}

	rows.err = err
	rows.close()
}

// Fatal signals an error occurred after the query was sent to the server. It
// closes the rows automatically.
func (rows *Rows) Fatal(err error) {
	if rows.err != nil {
		return
	}

	rows.err = err
	rows.Close()
}

// Next prepares the next row for reading. It returns true if there is another
// row and false if no more rows are available. It automatically closes rows
// when all rows are read.
func (rows *Rows) Next() bool {
	if rows.closed {
		return false
	}

	rows.rowCount++
	rows.columnIdx = 0
	rows.vr = ValueReader{}

	for {
		t, r, err := rows.conn.rxMsg()
		if err != nil {
			rows.Fatal(err)
			return false
		}

		switch t {
		case readyForQuery:
			rows.conn.rxReadyForQuery(r)
			rows.close()
			return false
		case dataRow:
			fieldCount := r.readInt16()
			if int(fieldCount) != len(rows.fields) {
				rows.Fatal(ProtocolError(fmt.Sprintf("Row description field count (%v) and data row field count (%v) do not match", len(rows.fields), fieldCount)))
				return false
			}

			rows.mr = r
			return true
		case commandComplete:
		case bindComplete:
		default:
			err = rows.conn.processContextFreeMsg(t, r)
			if err != nil {
				rows.Fatal(err)
				return false
			}
		}
	}
}

// Conn returns the *Conn this *Rows is using.
func (rows *Rows) Conn() *Conn {
	return rows.conn
}

func (rows *Rows) nextColumn() (*ValueReader, bool) {
	if rows.closed {
		return nil, false
	}
	if len(rows.fields) <= rows.columnIdx {
		rows.Fatal(ProtocolError("No next column available"))
		return nil, false
	}

	if rows.vr.Len() > 0 {
		rows.mr.readBytes(rows.vr.Len())
	}

	fd := &rows.fields[rows.columnIdx]
	rows.columnIdx++
	size := rows.mr.readInt32()
	rows.vr = ValueReader{mr: rows.mr, fd: fd, valueBytesRemaining: size}
	return &rows.vr, true
}

type scanArgError struct {
	col int
	err error
}

func (e scanArgError) Error() string {
	return fmt.Sprintf("can't scan into dest[%d]: %v", e.col, e.err)
}

// Scan reads the values from the current row into dest values positionally.
// dest can include pointers to core types, values implementing the Scanner
// interface, []byte, and nil. []byte will skip the decoding process and directly
// copy the raw bytes received from PostgreSQL. nil will skip the value entirely.
func (rows *Rows) Scan(dest ...interface{}) (err error) {
	if len(rows.fields) != len(dest) {
		err = fmt.Errorf("Scan received wrong number of arguments, got %d but expected %d", len(dest), len(rows.fields))
		rows.Fatal(err)
		return err
	}

	for i, d := range dest {
		vr, _ := rows.nextColumn()

		if d == nil {
			continue
		}

		// Check for []byte first as we allow sidestepping the decoding process and retrieving the raw bytes
		if b, ok := d.(*[]byte); ok {
			// If it actually is a bytea then pass it through decodeBytea (so it can be decoded if it is in text format)
			// Otherwise read the bytes directly regardless of what the actual type is.
			if vr.Type().DataType == ByteaOid {
				*b = decodeBytea(vr)
			} else {
				if vr.Len() != -1 {
					*b = vr.ReadBytes(vr.Len())
				} else {
					*b = nil
				}
			}
		} else if s, ok := d.(Scanner); ok {
			err = s.Scan(vr)
			if err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		} else if s, ok := d.(sql.Scanner); ok {
			var val interface{}
			if 0 <= vr.Len() {
				switch vr.Type().DataType {
				case BoolOid:
					val = decodeBool(vr)
				case Int8Oid:
					val = int64(decodeInt8(vr))
				case Int2Oid:
					val = int64(decodeInt2(vr))
				case Int4Oid:
					val = int64(decodeInt4(vr))
				case TextOid, VarcharOid:
					val = decodeText(vr)
				case OidOid:
					val = int64(decodeOid(vr))
				case Float4Oid:
					val = float64(decodeFloat4(vr))
				case Float8Oid:
					val = decodeFloat8(vr)
				case DateOid:
					val = decodeDate(vr)
				case TimestampOid:
					val = decodeTimestamp(vr)
				case TimestampTzOid:
					val = decodeTimestampTz(vr)
				default:
					val = vr.ReadBytes(vr.Len())
				}
			}
			err = s.Scan(val)
			if err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		} else if vr.Type().DataType == JsonOid || vr.Type().DataType == JsonbOid {
			// Because the argument passed to decodeJSON will escape the heap.
			// This allows d to be stack allocated and only copied to the heap when
			// we actually are decoding JSON. This saves one memory allocation per
			// row.
			d2 := d
			decodeJSON(vr, &d2)
		} else {
			if err := Decode(vr, d); err != nil {
				rows.Fatal(scanArgError{col: i, err: err})
			}
		}
		if vr.Err() != nil {
			rows.Fatal(scanArgError{col: i, err: vr.Err()})
		}

		if rows.Err() != nil {
			return rows.Err()
		}
	}

	return nil
}

// Values returns an array of the row values
func (rows *Rows) Values() ([]interface{}, error) {
	if rows.closed {
		return nil, errors.New("rows is closed")
	}

	values := make([]interface{}, 0, len(rows.fields))

	for range rows.fields {
		vr, _ := rows.nextColumn()

		if vr.Len() == -1 {
			values = append(values, nil)
			continue
		}

		switch vr.Type().FormatCode {
		// All intrinsic types (except string) are encoded with binary
		// encoding so anything else should be treated as a string
		case TextFormatCode:
			values = append(values, vr.ReadString(vr.Len()))
		case BinaryFormatCode:
			switch vr.Type().DataType {
			case BoolOid:
				values = append(values, decodeBool(vr))
			case ByteaOid:
				values = append(values, decodeBytea(vr))
			case Int8Oid:
				values = append(values, decodeInt8(vr))
			case Int2Oid:
				values = append(values, decodeInt2(vr))
			case Int4Oid:
				values = append(values, decodeInt4(vr))
			case OidOid:
				values = append(values, decodeOid(vr))
			case Float4Oid:
				values = append(values, decodeFloat4(vr))
			case Float8Oid:
				values = append(values, decodeFloat8(vr))
			case BoolArrayOid:
				values = append(values, decodeBoolArray(vr))
			case Int2ArrayOid:
				values = append(values, decodeInt2Array(vr))
			case Int4ArrayOid:
				values = append(values, decodeInt4Array(vr))
			case Int8ArrayOid:
				values = append(values, decodeInt8Array(vr))
			case Float4ArrayOid:
				values = append(values, decodeFloat4Array(vr))
			case Float8ArrayOid:
				values = append(values, decodeFloat8Array(vr))
			case TextArrayOid, VarcharArrayOid:
				values = append(values, decodeTextArray(vr))
			case TimestampArrayOid, TimestampTzArrayOid:
				values = append(values, decodeTimestampArray(vr))
			case DateOid:
				values = append(values, decodeDate(vr))
			case TimestampTzOid:
				values = append(values, decodeTimestampTz(vr))
			case TimestampOid:
				values = append(values, decodeTimestamp(vr))
			case InetOid, CidrOid:
				values = append(values, decodeInet(vr))
			case JsonOid:
				var d interface{}
				decodeJSON(vr, &d)
				values = append(values, d)
			case JsonbOid:
				var d interface{}
				decodeJSON(vr, &d)
				values = append(values, d)
			default:
				rows.Fatal(errors.New("Values cannot handle binary format non-intrinsic types"))
			}
		default:
			rows.Fatal(errors.New("Unknown format code"))
		}

		if vr.Err() != nil {
			rows.Fatal(vr.Err())
		}

		if rows.Err() != nil {
			return nil, rows.Err()
		}
	}

	return values, rows.Err()
}

// AfterClose adds f to a LILO queue of functions that will be called when
// rows is closed.
func (rows *Rows) AfterClose(f func(*Rows)) {
	if rows.afterClose == nil {
		rows.afterClose = f
	} else {
		prevFn := rows.afterClose
		rows.afterClose = func(rows *Rows) {
			f(rows)
			prevFn(rows)
		}
	}
}

// Query executes sql with args. If there is an error the returned *Rows will
// be returned in an error state. So it is allowed to ignore the error returned
// from Query and handle it in *Rows.
func (c *Conn) Query(sql string, args ...interface{}) (*Rows, error) {
	c.lastActivityTime = time.Now()

	rows := c.getRows(sql, args)

	if err := c.lock(); err != nil {
		rows.abort(err)
		return rows, err
	}
	rows.unlockConn = true

	ps, ok := c.preparedStatements[sql]
	if !ok {
		var err error
		ps, err = c.Prepare("", sql)
		if err != nil {
			rows.abort(err)
			return rows, rows.err
		}
	}

	rows.fields = ps.FieldDescriptions
	err := c.sendPreparedQuery(ps, args...)
	if err != nil {
		rows.abort(err)
	}
	return rows, rows.err
}

func (c *Conn) getRows(sql string, args []interface{}) *Rows {
	if len(c.preallocatedRows) == 0 {
		c.preallocatedRows = make([]Rows, 64)
		return c.getRows(sql, args)
	}

	r := &c.preallocatedRows[len(c.preallocatedRows)-1]
	c.preallocatedRows = c.preallocatedRows[0 : len(c.preallocatedRows)-1]

	r.conn = c
	r.startTime = c.lastActivityTime
	r.sql = sql
	r.args = args
	r.log = c.log
	r.shouldLog = c.shouldLog

	return r
}

// QueryRow is a convenience wrapper over Query. Any error that occurs while
// querying is deferred until calling Scan on the returned *Row. That *Row will
// error with ErrNoRows if no rows are returned.
func (c *Conn) QueryRow(sql string, args ...interface{}) *Row {
	rows, _ := c.Query(sql, args...)
	return (*Row)(rows)
}
<|endoftext|>


<commit_before>package lane

import (
	"errors"
	"sync"
)

type Queue struct {
	sync.RWMutex
	container []interface{}
}

func NewQueue() *Queue {
	return &Queue{
		container: *new([]interface{}),
	}
}

func (q *Queue) Enqueue(item interface{}) {
	q.Lock()

	q.container = append(q.container, item)

	q.Unlock()

	return
}

func (q *Queue) Dequeue() interface{} {
	q.Lock()

	item, err := q.getFirstItem()
	if err != nil {
		return nil
	}

	if len(q.container) > 1 {
		q.container = q.container[1:]
	} else {
		q.container = *new([]interface{})
	}

	q.Unlock()

	return item
}

func (q *Queue) Size() int {
	q.RLock()

	queueSize := len(q.container)

	q.RUnlock()

	return queueSize
}

func (q *Queue) Head() interface{} {
	q.RLock()
	defer q.RUnlock()

	item, err := q.getFirstItem()
	if err != nil {
		return nil
	}

	return item
}

func (q *Queue) getFirstItem() (interface{}, error) {
	if len(q.container) >= 1 {
		return q.container[0], nil
	} else {
		return nil, errors.New("The queue is empty")
	}
}
<commit_msg>Updated unlocking to be defered when possible<commit_after>package lane

import (
	"errors"
	"sync"
)

type Queue struct {
	sync.RWMutex
	container []interface{}
}

func NewQueue() *Queue {
	return &Queue{
		container: *new([]interface{}),
	}
}

func (q *Queue) Enqueue(item interface{}) {
	q.Lock()
	defer q.Unlock()

	q.container = append(q.container, item)

	return
}

func (q *Queue) Dequeue() interface{} {
	q.Lock()
	defer q.Unlock()

	item, err := q.getFirstItem()
	if err != nil {
		return nil
	}

	if len(q.container) > 1 {
		q.container = q.container[1:]
	} else {
		q.container = *new([]interface{})
	}

	return item
}

func (q *Queue) Size() int {
	q.RLock()
	defer q.RUnlock()

	return len(q.container)
}

func (q *Queue) Head() interface{} {
	q.RLock()
	defer q.RUnlock()

	item, err := q.getFirstItem()
	if err != nil {
		return nil
	}

	return item
}

func (q *Queue) getFirstItem() (interface{}, error) {
	if len(q.container) >= 1 {
		return q.container[0], nil
	} else {
		return nil, errors.New("The queue is empty")
	}
}
<|endoftext|>