<commit_before>package gssapi

import (
	"bytes"
	"crypto/hmac"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"

	"gopkg.in/jcmturner/gokrb5.v6/crypto"
	"gopkg.in/jcmturner/gokrb5.v6/iana/keyusage"
	"gopkg.in/jcmturner/gokrb5.v6/types"
)

/*
From RFC 4121, section 4.2.6.1:

   Use of the GSS_GetMIC() call yields a token (referred as the MIC
   token in this document), separate from the user data being protected,
   which can be used to verify the integrity of that data as received.
   The token has the following format:

         Octet no   Name        Description
         --------------------------------------------------------------
         0..1     TOK_ID     Identification field.  Tokens emitted by
                             GSS_GetMIC() contain the hex value 04 04
                             expressed in big-endian order in this
                             field.
         2        Flags      Attributes field, as described in section
                             4.2.2.
         3..7     Filler     Contains five octets of hex value FF.
         8..15    SND_SEQ    Sequence number field in clear text,
                             expressed in big-endian order.
         16..last SGN_CKSUM  Checksum of the "to-be-signed" data and
                             octet 0..15, as described in section 4.2.4.

   The Filler field is included in the checksum calculation for
   simplicity.

*/

const (
	MICHdrLen = 16
)

type MICToken struct {
	// const GSS Token ID: 0x0404
	Flags byte // contains three flags: acceptor, sealed, acceptor subkey
	// const Filler: 0xFF 0xFF 0xFF 0xFF 0xFF
	SndSeqNum uint64 // sender's sequence number. big-endian
	Payload   []byte // your data! :)
	Checksum  []byte // checksum of { payload | header }
}

func getGssMICTokenId() *[2]byte {
	return &[2]byte{0x04, 0x04}
}

func fillerBytes() *[5]byte {
	return &[5]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
}

func (mt *MICToken) Marshal() ([]byte, error) {
	if mt.Checksum == nil {
		return nil, errors.New("checksum has not been set")
	}

	bytes := make([]byte, MICHdrLen+len(mt.Checksum))
	copy(bytes[0:MICHdrLen], getMICChecksumHeader(mt.Flags, mt.SndSeqNum)[:])
	copy(bytes[MICHdrLen:], mt.Checksum)

	return bytes, nil
}

func (mt *MICToken) ComputeAndSetChecksum(key types.EncryptionKey, keyUsage uint32) error {
	if mt.Payload == nil {
		return errors.New("payload has not been set")
	}
	if mt.Checksum != nil {
		return errors.New("checksum has already been computed")
	}
	checksum, err := mt.ComputeChecksum(key, keyUsage)
	if err != nil {
		return err
	}
	mt.Checksum = checksum
	return nil
}

func (mt *MICToken) ComputeChecksum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) {
	if mt.Payload == nil {
		return nil, errors.New("cannot compute checksum with uninitialized payload")
	}
	checksumMe := make([]byte, MICHdrLen+len(mt.Payload))
	copy(checksumMe[0:], mt.Payload)
	copy(checksumMe[len(mt.Payload):], getMICChecksumHeader(mt.Flags, mt.SndSeqNum))

	encType, err := crypto.GetEtype(key.KeyType)
	if err != nil {
		return nil, err
	}
	return encType.GetChecksumHash(key.KeyValue, checksumMe, keyUsage)
}

func getMICChecksumHeader(flags byte, senderSeqNum uint64) []byte {
	header := make([]byte, MICHdrLen)
	copy(header[0:2], getGssMICTokenId()[:])
	header[2] = flags
	copy(header[3:8], fillerBytes()[:])
	binary.BigEndian.PutUint64(header[8:16], senderSeqNum)
	return header
}

func (mt *MICToken) VerifyChecksum(key types.EncryptionKey, keyUsage uint32) (bool, error) {
	computed, err := mt.ComputeChecksum(key, keyUsage)
	if err != nil {
		return false, err
	}
	if !hmac.Equal(computed, mt.Checksum) {
		return false, fmt.Errorf(
			"checksum mismatch. Computed: %s, Contained in token: %s",
			hex.EncodeToString(computed), hex.EncodeToString(mt.Checksum))
	}
	return true, nil
}

func (mt *MICToken) Unmarshal(b []byte, expectFromAcceptor bool) error {
	if len(b) < MICHdrLen {
		return errors.New("bytes shorter than hedaer length")
	}
	if !bytes.Equal(getGssMICTokenId()[:], b[0:2]) {
		return fmt.Errorf("wrong Token ID, Expected %s, was %s",
			hex.EncodeToString(getGssMICTokenId()[:]),
			hex.EncodeToString(b[0:2]))
	}
	flags := b[2]
	isFromAcceptor := flags&0x01 == 1
	if isFromAcceptor && !expectFromAcceptor {
		return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor")
	}
	if !isFromAcceptor && expectFromAcceptor {
		return errors.New("unexpected acceptor flag is not set: expecting a token from the acceptor, not in the initiator")
	}
	if !bytes.Equal(b[3:8], fillerBytes()[:]) {
		return fmt.Errorf("unexpected filler bytes: expecting %s, was %s",
			hex.EncodeToString(fillerBytes()[:]),
			hex.EncodeToString(b[3:8]))
	}

	mt.Flags = flags
	mt.SndSeqNum = binary.BigEndian.Uint64(b[8:16])
	mt.Checksum = b[MICHdrLen:]
	return nil
}

func NewInitiatorMICToken(payload []byte, key types.EncryptionKey) (*MICToken, error) {
	token := MICToken{
		Flags:     0x00,
		SndSeqNum: 0,
		Payload:   payload,
	}

	if err := token.ComputeAndSetChecksum(key, keyusage.GSSAPI_INITIATOR_SIGN); err != nil {
		return nil, err
	}

	return &token, nil
}
<commit_msg>Documentation<commit_after>package gssapi

import (
	"bytes"
	"crypto/hmac"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"

	"gopkg.in/jcmturner/gokrb5.v6/crypto"
	"gopkg.in/jcmturner/gokrb5.v6/iana/keyusage"
	"gopkg.in/jcmturner/gokrb5.v6/types"
)

/*
From RFC 4121, section 4.2.6.1:

   Use of the GSS_GetMIC() call yields a token (referred as the MIC
   token in this document), separate from the user data being protected,
   which can be used to verify the integrity of that data as received.
   The token has the following format:

         Octet no   Name        Description
         --------------------------------------------------------------
         0..1     TOK_ID     Identification field.  Tokens emitted by
                             GSS_GetMIC() contain the hex value 04 04
                             expressed in big-endian order in this
                             field.
         2        Flags      Attributes field, as described in section
                             4.2.2.
         3..7     Filler     Contains five octets of hex value FF.
         8..15    SND_SEQ    Sequence number field in clear text,
                             expressed in big-endian order.
         16..last SGN_CKSUM  Checksum of the "to-be-signed" data and
                             octet 0..15, as described in section 4.2.4.

   The Filler field is included in the checksum calculation for
   simplicity.

*/
const (
	MICHdrLen = 16 // Length of the MIC Token's header
)

// MICToken represents a GSS API MIC token, as defined in RFC 4121.
// It contains the header fields, the payload (this is not transmitted) and
// the checksum, and provides the logic for converting to/from bytes plus
// computing and verifying checksums
type MICToken struct {
	// const GSS Token ID: 0x0404
	Flags byte // contains three flags: acceptor, sealed, acceptor subkey
	// const Filler: 0xFF 0xFF 0xFF 0xFF 0xFF
	SndSeqNum uint64 // sender's sequence number. big-endian
	Payload   []byte // your data! :)
	Checksum  []byte // checksum of { payload | header }
}

// Return the 2 bytes identifying a GSS API MIC token
func getGssMICTokenId() *[2]byte {
	return &[2]byte{0x04, 0x04}
}

// Return the filler bytes used in header
func fillerBytes() *[5]byte {
	return &[5]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
}

// Marshal the MICToken into a byte slice.
// The payload should have been set and the checksum computed, otherwise an error is returned.
func (mt *MICToken) Marshal() ([]byte, error) {
	if mt.Checksum == nil {
		return nil, errors.New("checksum has not been set")
	}

	bytes := make([]byte, MICHdrLen+len(mt.Checksum))
	copy(bytes[0:MICHdrLen], getMICChecksumHeader(mt.Flags, mt.SndSeqNum)[:])
	copy(bytes[MICHdrLen:], mt.Checksum)

	return bytes, nil
}

// ComputeAndSetChecksum uses the passed encryption key and key usage to compute the checksum over the payload and
// the header, and sets the Checksum field of this MICToken.
// If the payload has not been set or the checksum has already been set, an error is returned.
func (mt *MICToken) ComputeAndSetChecksum(key types.EncryptionKey, keyUsage uint32) error {
	if mt.Payload == nil {
		return errors.New("payload has not been set")
	}
	if mt.Checksum != nil {
		return errors.New("checksum has already been computed")
	}
	checksum, err := mt.ComputeChecksum(key, keyUsage)
	if err != nil {
		return err
	}
	mt.Checksum = checksum
	return nil
}

// ComputeChecksum computes and returns the checksum of this token, computed using the passed key and key usage.
// Confirms to RFC 4121 in that the checksum will be computed over { body | header }.
// In the context of Kerberos MIC tokens, mostly keyusage GSSAPI_ACCEPTOR_SIGN (=23)
// and GSSAPI_INITIATOR_SIGN (=25) will be used.
// Note: This will NOT update the struct's Checksum field.
func (mt *MICToken) ComputeChecksum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) {
	if mt.Payload == nil {
		return nil, errors.New("cannot compute checksum with uninitialized payload")
	}
	checksumMe := make([]byte, MICHdrLen+len(mt.Payload))
	copy(checksumMe[0:], mt.Payload)
	copy(checksumMe[len(mt.Payload):], getMICChecksumHeader(mt.Flags, mt.SndSeqNum))

	encType, err := crypto.GetEtype(key.KeyType)
	if err != nil {
		return nil, err
	}
	return encType.GetChecksumHash(key.KeyValue, checksumMe, keyUsage)
}

// Build a header suitable for a checksum computation
func getMICChecksumHeader(flags byte, senderSeqNum uint64) []byte {
	header := make([]byte, MICHdrLen)
	copy(header[0:2], getGssMICTokenId()[:])
	header[2] = flags
	copy(header[3:8], fillerBytes()[:])
	binary.BigEndian.PutUint64(header[8:16], senderSeqNum)
	return header
}

// Verify Checksum computes the token's checksum with the provided key and usage,
// and compares it to the checksum present in the token.
// In case of any failure, (false, err) is returned, with err an explanatory error.
func (mt *MICToken) VerifyChecksum(key types.EncryptionKey, keyUsage uint32) (bool, error) {
	computed, err := mt.ComputeChecksum(key, keyUsage)
	if err != nil {
		return false, err
	}
	if !hmac.Equal(computed, mt.Checksum) {
		return false, fmt.Errorf(
			"checksum mismatch. Computed: %s, Contained in token: %s",
			hex.EncodeToString(computed), hex.EncodeToString(mt.Checksum))
	}
	return true, nil
}

// Unmarshal bytes into the corresponding MICToken.
// If expectFromAcceptor is true we expect the token to have been emitted by the gss acceptor,
// and will check the according flag, returning an error if the token does not match the expectation.
func (mt *MICToken) Unmarshal(b []byte, expectFromAcceptor bool) error {
	if len(b) < MICHdrLen {
		return errors.New("bytes shorter than hedaer length")
	}
	if !bytes.Equal(getGssMICTokenId()[:], b[0:2]) {
		return fmt.Errorf("wrong Token ID, Expected %s, was %s",
			hex.EncodeToString(getGssMICTokenId()[:]),
			hex.EncodeToString(b[0:2]))
	}
	flags := b[2]
	isFromAcceptor := flags&0x01 == 1
	if isFromAcceptor && !expectFromAcceptor {
		return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor")
	}
	if !isFromAcceptor && expectFromAcceptor {
		return errors.New("unexpected acceptor flag is not set: expecting a token from the acceptor, not in the initiator")
	}
	if !bytes.Equal(b[3:8], fillerBytes()[:]) {
		return fmt.Errorf("unexpected filler bytes: expecting %s, was %s",
			hex.EncodeToString(fillerBytes()[:]),
			hex.EncodeToString(b[3:8]))
	}

	mt.Flags = flags
	mt.SndSeqNum = binary.BigEndian.Uint64(b[8:16])
	mt.Checksum = b[MICHdrLen:]
	return nil
}

// NewInitiatorMICToken builds a new initiator token (acceptor flag will be set to 0) and computes the authenticated checksum.
// Other flags are set to 0.
// Note that in certain circumstances you may need to provide a sequence number that has been defined earlier.
// This is currently not supported.
func NewInitiatorMICToken(payload []byte, key types.EncryptionKey) (*MICToken, error) {
	token := MICToken{
		Flags:     0x00,
		SndSeqNum: 0,
		Payload:   payload,
	}

	if err := token.ComputeAndSetChecksum(key, keyusage.GSSAPI_INITIATOR_SIGN); err != nil {
		return nil, err
	}

	return &token, nil
}
<|endoftext|>


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

// HTTP reverse proxy handler

package proxy

import (
	"io"
	"log"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

const (
	stickyCookie = "_backend"
)

// onExitFlushLoop is a callback set by tests to detect the state of the
// flushLoop() goroutine.
var onExitFlushLoop func()

// Hop-by-hop headers. These are removed when sent to the backend.
// https://tools.ietf.org/html/rfc7230#section-6.1
var (
	hopHeaders = []string{
		"Te", // canonicalized version of "TE"
		"Trailers",
		"Transfer-Encoding",
	}

	serviceUnavailable = []byte("Service Unavailable\n")
)

// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
type ReverseProxy struct {
	// The transport used to perform proxy requests.
	transport *transport

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger
}

// NewReverseProxy initializes a new ReverseProxy with a callback to get
// backends, a stickyKey for encrypting sticky session cookies, and a flag
// sticky to enable sticky sessions.
func NewReverseProxy(bf BackendListFunc, stickyKey *[32]byte, sticky bool) *ReverseProxy {
	return &ReverseProxy{
		transport: &transport{
			getBackends:       bf,
			stickyCookieKey:   stickyKey,
			useStickySessions: sticky,
		},
		FlushInterval: 10 * time.Millisecond,
	}
}

// ServeHTTP implements http.Handler.
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}

	outreq := prepareRequest(req)

	if isConnectionUpgrade(req.Header) {
		p.serveUpgrade(rw, outreq)
		return
	}

	res, err := transport.RoundTrip(outreq)
	if err != nil {
		p.logf("router: proxy error: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer res.Body.Close()

	p.writeResponse(rw, res)
}

// ServeConn takes an inbound conn and proxies it to a backend.
func (p *ReverseProxy) ServeConn(dconn net.Conn) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}
	defer dconn.Close()

	uconn, err := transport.Connect()
	if err != nil {
		p.logf("router: proxy error: %v", err)
		return
	}
	defer uconn.Close()

	joinConns(uconn, dconn)
}

func (p *ReverseProxy) serveUpgrade(rw http.ResponseWriter, req *http.Request) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}

	res, uconn, err := transport.UpgradeHTTP(req)
	if err != nil {
		p.logf("router: proxy error: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer uconn.Close()

	dconn, bufrw, err := rw.(http.Hijacker).Hijack()
	if err != nil {
		p.logf("router: hijack failed: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer dconn.Close()

	prepareResponseHeaders(res)
	if res.StatusCode != 101 {
		res.Header.Set("Connection", "close")
	}
	if err := res.Write(dconn); err != nil {
		return
	}

	if res.StatusCode != 101 {
		return
	}

	joinConns(uconn, &streamConn{bufrw.Reader, dconn})
}

func prepareResponseHeaders(res *http.Response) {
	// remove global hop-by-hop headers.
	for _, h := range hopHeaders {
		res.Header.Del(h)
	}

	// remove the Upgrade header and headers referenced in the Connection
	// header if HTTP < 1.1 or if Connection header didn't contain "upgrade":
	// https://tools.ietf.org/html/rfc7230#section-6.7
	if !res.ProtoAtLeast(1, 1) || !isConnectionUpgrade(res.Header) {
		res.Header.Del("Upgrade")

		// A proxy or gateway MUST parse a received Connection header field before a
		// message is forwarded and, for each connection-option in this field, remove
		// any header field(s) from the message with the same name as the
		// connection-option, and then remove the Connection header field itself (or
		// replace it with the intermediary's own connection options for the
		// forwarded message): https://tools.ietf.org/html/rfc7230#section-6.1
		tokens := strings.Split(res.Header.Get("Connection"), ",")
		for _, hdr := range tokens {
			res.Header.Del(hdr)
		}
		res.Header.Del("Connection")
	}
}

func (p *ReverseProxy) writeResponse(rw http.ResponseWriter, res *http.Response) {
	prepareResponseHeaders(res)
	copyHeader(rw.Header(), res.Header)

	rw.WriteHeader(res.StatusCode)
	p.copyResponse(rw, res.Body)
}

func isConnectionUpgrade(h http.Header) bool {
	for _, token := range strings.Split(h.Get("Connection"), ",") {
		if v := strings.ToLower(strings.TrimSpace(token)); v == "upgrade" {
			return true
		}
	}
	return false
}

func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
	if p.FlushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:     wf,
				latency: p.FlushInterval,
				done:    make(chan bool),
			}
			go mlw.flushLoop()
			defer mlw.stop()
			dst = mlw
		}
	}

	io.Copy(dst, src)
}

func (p *ReverseProxy) logf(format string, args ...interface{}) {
	if p.ErrorLog != nil {
		p.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

type closeWriter interface {
	CloseWrite() error
}

func closeWrite(conn net.Conn) {
	if cw, ok := conn.(closeWriter); ok {
		cw.CloseWrite()
	} else {
		conn.Close()
	}
}

func joinConns(uconn, dconn net.Conn) {
	done := make(chan struct{})

	go func() {
		io.Copy(uconn, dconn)
		closeWrite(uconn)
		done <- struct{}{}
	}()

	io.Copy(dconn, uconn)
	closeWrite(dconn)
	<-done
}

func prepareRequest(req *http.Request) *http.Request {
	outreq := new(http.Request)
	*outreq = *req // includes shallow copies of maps, but okay

	// Pass the Request-URI verbatim without any modifications
	outreq.URL.Opaque = strings.Split(strings.TrimPrefix(req.RequestURI, req.URL.Scheme+":"), "?")[0]
	outreq.URL.Scheme = "http"
	outreq.Proto = "HTTP/1.1"
	outreq.ProtoMajor = 1
	outreq.ProtoMinor = 1
	outreq.Close = false

	// Remove hop-by-hop headers to the backend.
	outreq.Header = make(http.Header)
	copyHeader(outreq.Header, req.Header)
	for _, h := range hopHeaders {
		outreq.Header.Del(h)
	}

	// remove the Upgrade header and headers referenced in the Connection
	// header if HTTP < 1.1 or if Connection header didn't contain "upgrade":
	// https://tools.ietf.org/html/rfc7230#section-6.7
	if !req.ProtoAtLeast(1, 1) || !isConnectionUpgrade(req.Header) {
		outreq.Header.Del("Upgrade")

		// Especially important is "Connection" because we want a persistent
		// connection, regardless of what the client sent to us.
		outreq.Header.Del("Connection")

		// A proxy or gateway MUST parse a received Connection header field before a
		// message is forwarded and, for each connection-option in this field, remove
		// any header field(s) from the message with the same name as the
		// connection-option, and then remove the Connection header field itself (or
		// replace it with the intermediary's own connection options for the
		// forwarded message): https://tools.ietf.org/html/rfc7230#section-6.1
		tokens := strings.Split(req.Header.Get("Connection"), ",")
		for _, hdr := range tokens {
			outreq.Header.Del(hdr)
		}
	}

	return outreq
}

type writeFlusher interface {
	io.Writer
	http.Flusher
}

type maxLatencyWriter struct {
	dst     writeFlusher
	latency time.Duration

	lk   sync.Mutex // protects Write + Flush
	done chan bool
}

func (m *maxLatencyWriter) Write(p []byte) (int, error) {
	m.lk.Lock()
	defer m.lk.Unlock()
	return m.dst.Write(p)
}

func (m *maxLatencyWriter) flushLoop() {
	t := time.NewTicker(m.latency)
	defer t.Stop()
	for {
		select {
		case <-m.done:
			if onExitFlushLoop != nil {
				onExitFlushLoop()
			}
			return
		case <-t.C:
			m.lk.Lock()
			m.dst.Flush()
			m.lk.Unlock()
		}
	}
}

func (m *maxLatencyWriter) stop() { m.done <- true }
<commit_msg>router: refactor status code check in ReverseProxy.serveUpgrade<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// HTTP reverse proxy handler

package proxy

import (
	"io"
	"log"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

const (
	stickyCookie = "_backend"
)

// onExitFlushLoop is a callback set by tests to detect the state of the
// flushLoop() goroutine.
var onExitFlushLoop func()

// Hop-by-hop headers. These are removed when sent to the backend.
// https://tools.ietf.org/html/rfc7230#section-6.1
var (
	hopHeaders = []string{
		"Te", // canonicalized version of "TE"
		"Trailers",
		"Transfer-Encoding",
	}

	serviceUnavailable = []byte("Service Unavailable\n")
)

// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
type ReverseProxy struct {
	// The transport used to perform proxy requests.
	transport *transport

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger
}

// NewReverseProxy initializes a new ReverseProxy with a callback to get
// backends, a stickyKey for encrypting sticky session cookies, and a flag
// sticky to enable sticky sessions.
func NewReverseProxy(bf BackendListFunc, stickyKey *[32]byte, sticky bool) *ReverseProxy {
	return &ReverseProxy{
		transport: &transport{
			getBackends:       bf,
			stickyCookieKey:   stickyKey,
			useStickySessions: sticky,
		},
		FlushInterval: 10 * time.Millisecond,
	}
}

// ServeHTTP implements http.Handler.
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}

	outreq := prepareRequest(req)

	if isConnectionUpgrade(req.Header) {
		p.serveUpgrade(rw, outreq)
		return
	}

	res, err := transport.RoundTrip(outreq)
	if err != nil {
		p.logf("router: proxy error: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer res.Body.Close()

	prepareResponseHeaders(res)
	p.writeResponse(rw, res)
}

// ServeConn takes an inbound conn and proxies it to a backend.
func (p *ReverseProxy) ServeConn(dconn net.Conn) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}
	defer dconn.Close()

	uconn, err := transport.Connect()
	if err != nil {
		p.logf("router: proxy error: %v", err)
		return
	}
	defer uconn.Close()

	joinConns(uconn, dconn)
}

func (p *ReverseProxy) serveUpgrade(rw http.ResponseWriter, req *http.Request) {
	transport := p.transport
	if transport == nil {
		panic("router: nil transport for proxy")
	}

	res, uconn, err := transport.UpgradeHTTP(req)
	if err != nil {
		p.logf("router: proxy error: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer uconn.Close()

	prepareResponseHeaders(res)
	if res.StatusCode != 101 {
		res.Header.Set("Connection", "close")
		p.writeResponse(rw, res)
		return
	}

	dconn, bufrw, err := rw.(http.Hijacker).Hijack()
	if err != nil {
		p.logf("router: hijack failed: %v", err)
		rw.WriteHeader(http.StatusServiceUnavailable)
		rw.Write(serviceUnavailable)
		return
	}
	defer dconn.Close()

	if err := res.Write(dconn); err != nil {
		p.logf("router: proxy error: %v", err)
		return
	}
	joinConns(uconn, &streamConn{bufrw.Reader, dconn})
}

func prepareResponseHeaders(res *http.Response) {
	// remove global hop-by-hop headers.
	for _, h := range hopHeaders {
		res.Header.Del(h)
	}

	// remove the Upgrade header and headers referenced in the Connection
	// header if HTTP < 1.1 or if Connection header didn't contain "upgrade":
	// https://tools.ietf.org/html/rfc7230#section-6.7
	if !res.ProtoAtLeast(1, 1) || !isConnectionUpgrade(res.Header) {
		res.Header.Del("Upgrade")

		// A proxy or gateway MUST parse a received Connection header field before a
		// message is forwarded and, for each connection-option in this field, remove
		// any header field(s) from the message with the same name as the
		// connection-option, and then remove the Connection header field itself (or
		// replace it with the intermediary's own connection options for the
		// forwarded message): https://tools.ietf.org/html/rfc7230#section-6.1
		tokens := strings.Split(res.Header.Get("Connection"), ",")
		for _, hdr := range tokens {
			res.Header.Del(hdr)
		}
		res.Header.Del("Connection")
	}
}

func (p *ReverseProxy) writeResponse(rw http.ResponseWriter, res *http.Response) {
	copyHeader(rw.Header(), res.Header)

	rw.WriteHeader(res.StatusCode)
	p.copyResponse(rw, res.Body)
}

func isConnectionUpgrade(h http.Header) bool {
	for _, token := range strings.Split(h.Get("Connection"), ",") {
		if v := strings.ToLower(strings.TrimSpace(token)); v == "upgrade" {
			return true
		}
	}
	return false
}

func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
	if p.FlushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:     wf,
				latency: p.FlushInterval,
				done:    make(chan bool),
			}
			go mlw.flushLoop()
			defer mlw.stop()
			dst = mlw
		}
	}

	io.Copy(dst, src)
}

func (p *ReverseProxy) logf(format string, args ...interface{}) {
	if p.ErrorLog != nil {
		p.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

type closeWriter interface {
	CloseWrite() error
}

func closeWrite(conn net.Conn) {
	if cw, ok := conn.(closeWriter); ok {
		cw.CloseWrite()
	} else {
		conn.Close()
	}
}

func joinConns(uconn, dconn net.Conn) {
	done := make(chan struct{})

	go func() {
		io.Copy(uconn, dconn)
		closeWrite(uconn)
		done <- struct{}{}
	}()

	io.Copy(dconn, uconn)
	closeWrite(dconn)
	<-done
}

func prepareRequest(req *http.Request) *http.Request {
	outreq := new(http.Request)
	*outreq = *req // includes shallow copies of maps, but okay

	// Pass the Request-URI verbatim without any modifications
	outreq.URL.Opaque = strings.Split(strings.TrimPrefix(req.RequestURI, req.URL.Scheme+":"), "?")[0]
	outreq.URL.Scheme = "http"
	outreq.Proto = "HTTP/1.1"
	outreq.ProtoMajor = 1
	outreq.ProtoMinor = 1
	outreq.Close = false

	// Remove hop-by-hop headers to the backend.
	outreq.Header = make(http.Header)
	copyHeader(outreq.Header, req.Header)
	for _, h := range hopHeaders {
		outreq.Header.Del(h)
	}

	// remove the Upgrade header and headers referenced in the Connection
	// header if HTTP < 1.1 or if Connection header didn't contain "upgrade":
	// https://tools.ietf.org/html/rfc7230#section-6.7
	if !req.ProtoAtLeast(1, 1) || !isConnectionUpgrade(req.Header) {
		outreq.Header.Del("Upgrade")

		// Especially important is "Connection" because we want a persistent
		// connection, regardless of what the client sent to us.
		outreq.Header.Del("Connection")

		// A proxy or gateway MUST parse a received Connection header field before a
		// message is forwarded and, for each connection-option in this field, remove
		// any header field(s) from the message with the same name as the
		// connection-option, and then remove the Connection header field itself (or
		// replace it with the intermediary's own connection options for the
		// forwarded message): https://tools.ietf.org/html/rfc7230#section-6.1
		tokens := strings.Split(req.Header.Get("Connection"), ",")
		for _, hdr := range tokens {
			outreq.Header.Del(hdr)
		}
	}

	return outreq
}

type writeFlusher interface {
	io.Writer
	http.Flusher
}

type maxLatencyWriter struct {
	dst     writeFlusher
	latency time.Duration

	lk   sync.Mutex // protects Write + Flush
	done chan bool
}

func (m *maxLatencyWriter) Write(p []byte) (int, error) {
	m.lk.Lock()
	defer m.lk.Unlock()
	return m.dst.Write(p)
}

func (m *maxLatencyWriter) flushLoop() {
	t := time.NewTicker(m.latency)
	defer t.Stop()
	for {
		select {
		case <-m.done:
			if onExitFlushLoop != nil {
				onExitFlushLoop()
			}
			return
		case <-t.C:
			m.lk.Lock()
			m.dst.Flush()
			m.lk.Unlock()
		}
	}
}

func (m *maxLatencyWriter) stop() { m.done <- true }
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package grpc

import (
	"io"
	"net/http"
	"strconv"

	"github.com/ligato/cn-infra/infra"
	"github.com/ligato/cn-infra/rpc/rest"
	"github.com/unrolled/render"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

// Plugin maintains the GRPC netListener (see Init, AfterInit, Close methods)
type Plugin struct {
	Deps

	*Config

	// GRPC server instance
	grpcServer *grpc.Server
	// GRPC network listener
	netListener io.Closer
	// Plugin availability flag
	disabled bool
}

// Deps is a list of injected dependencies of the GRPC plugin.
type Deps struct {
	infra.PluginDeps
	HTTP rest.HTTPHandlers
}

// Init prepares GRPC netListener for registration of individual service
func (p *Plugin) Init() (err error) {
	// Get GRPC configuration file
	if p.Config == nil {
		p.Config, err = p.getGrpcConfig()
		if err != nil || p.disabled {
			return err
		}
	}

	// Prepare GRPC server
	if p.grpcServer == nil {
		opts := p.Config.getGrpcOptions()
		p.grpcServer = grpc.NewServer(opts...)
		grpclog.SetLogger(p.Log.NewLogger("grpc-server"))
	}

	return nil
}

// AfterInit starts the HTTP netListener.
func (p *Plugin) AfterInit() (err error) {
	if p.Deps.HTTP != nil {
		p.Log.Infof("exposing GRPC services via HTTP (port %v) on: /service",
			strconv.Itoa(p.Deps.HTTP.GetPort()))
		p.Deps.HTTP.RegisterHTTPHandler("/service", func(formatter *render.Render) http.HandlerFunc {
			return p.grpcServer.ServeHTTP
		}, "GET", "PUT", "POST")
	} else {
		p.Log.Infof("HTTP not set, skip exposing GRPC services")
	}

	// Start GRPC listener
	p.netListener, err = ListenAndServe(p.Config, p.grpcServer)
	if err != nil {
		return err
	}
	p.Log.Infof("Listening GRPC on: %v", p.Config.Endpoint)

	return nil
}

// Close stops the HTTP netListener.
func (p *Plugin) Close() error {
	if p.grpcServer != nil {
		p.grpcServer.Stop()
	}
	return nil
}

// GetServer is a getter for accessing grpc.Server
func (p *Plugin) GetServer() *grpc.Server {
	return p.grpcServer
}

// IsDisabled returns *true* if the plugin is not in use due to missing
// grpc configuration.
func (p *Plugin) IsDisabled() bool {
	return p.disabled
}

func (p *Plugin) getGrpcConfig() (*Config, error) {
	var grpcCfg Config
	found, err := p.Cfg.LoadValue(&grpcCfg)
	if err != nil {
		return &grpcCfg, err
	}
	if !found {
		p.Log.Info("GRPC config not found, skip loading this plugin")
		p.disabled = true
	}
	return &grpcCfg, nil
}
<commit_msg>Fix panic if GRPC is disabled<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package grpc

import (
	"io"
	"net/http"
	"strconv"

	"github.com/ligato/cn-infra/infra"
	"github.com/ligato/cn-infra/rpc/rest"
	"github.com/unrolled/render"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

// Plugin maintains the GRPC netListener (see Init, AfterInit, Close methods)
type Plugin struct {
	Deps

	*Config

	// GRPC server instance
	grpcServer *grpc.Server
	// GRPC network listener
	netListener io.Closer
	// Plugin availability flag
	disabled bool
}

// Deps is a list of injected dependencies of the GRPC plugin.
type Deps struct {
	infra.PluginDeps
	HTTP rest.HTTPHandlers
}

// Init prepares GRPC netListener for registration of individual service
func (p *Plugin) Init() (err error) {
	// Get GRPC configuration file
	if p.Config == nil {
		p.Config, err = p.getGrpcConfig()
		if err != nil || p.disabled {
			return err
		}
	}

	// Prepare GRPC server
	if p.grpcServer == nil {
		opts := p.Config.getGrpcOptions()
		p.grpcServer = grpc.NewServer(opts...)
		grpclog.SetLogger(p.Log.NewLogger("grpc-server"))
	}

	return nil
}

// AfterInit starts the HTTP netListener.
func (p *Plugin) AfterInit() (err error) {
	if p.disabled {
		return nil
	}

	if p.Deps.HTTP != nil {
		p.Log.Infof("exposing GRPC services via HTTP (port %v) on: /service",
			strconv.Itoa(p.Deps.HTTP.GetPort()))
		p.Deps.HTTP.RegisterHTTPHandler("/service", func(formatter *render.Render) http.HandlerFunc {
			return p.grpcServer.ServeHTTP
		}, "GET", "PUT", "POST")
	} else {
		p.Log.Infof("HTTP not set, skip exposing GRPC services")
	}

	// Start GRPC listener
	p.netListener, err = ListenAndServe(p.Config, p.grpcServer)
	if err != nil {
		return err
	}
	p.Log.Infof("Listening GRPC on: %v", p.Config.Endpoint)

	return nil
}

// Close stops the HTTP netListener.
func (p *Plugin) Close() error {
	if p.grpcServer != nil {
		p.grpcServer.Stop()
	}
	return nil
}

// GetServer is a getter for accessing grpc.Server
func (p *Plugin) GetServer() *grpc.Server {
	return p.grpcServer
}

// IsDisabled returns *true* if the plugin is not in use due to missing
// grpc configuration.
func (p *Plugin) IsDisabled() bool {
	return p.disabled
}

func (p *Plugin) getGrpcConfig() (*Config, error) {
	var grpcCfg Config
	found, err := p.Cfg.LoadValue(&grpcCfg)
	if err != nil {
		return &grpcCfg, err
	}
	if !found {
		p.Log.Info("GRPC config not found, skip loading this plugin")
		p.disabled = true
	}
	return &grpcCfg, nil
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2018 Dean Jackson <deanishe@deanishe.net>
//
// MIT Licence. See http://opensource.org/licenses/MIT
//
// Created on 2018-01-26
//

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/gobwas/glob"
)

var (
	locateDBPath = "/var/db/locate.database"
	scanners     = map[string]Scanner{
		"find":   &findScanner{},
		"mdfind": &mdfindScanner{},
		"locate": &locateScanner{},
	}
)

// Scanner finds Sublime Text project files.
type Scanner interface {
	Name() string                             // name of scanner
	Scan(conf *config) (<-chan string, error) // scan for projects
}

// ScanManager loads and runs Scanners.
type ScanManager struct {
	conf      *config
	Scanners  map[string]Scanner
	intervals map[string]time.Duration
}

// NewScanManager initialises a ScanManager.
func NewScanManager(conf *config) *ScanManager {
	sm := &ScanManager{
		conf:      conf,
		Scanners:  map[string]Scanner{},
		intervals: map[string]time.Duration{},
	}

	for name, sc := range scanners {
		var d time.Duration
		switch name {
		case "mdfind":
			d = conf.MDFindInterval
		case "locate":
			d = conf.LocateInterval
		case "find":
			d = conf.FindInterval
		default:
			log.Printf("[scan] unknown scanner: %s", name)
			d = conf.FindInterval
		}
		sm.Scanners[name] = sc
		sm.intervals[name] = d
	}

	return sm
}

// ScanDue returns true if one or more scanners needs updating.
func (sm *ScanManager) ScanDue() bool {

	if !wf.Cache.Exists(cacheKey) {
		return true
	}

	if len(sm.dueScanners()) > 0 {
		return true
	}

	return false
}

// Scan updates the cached lists of projects.
func (sm *ScanManager) Scan() error {

	var (
		due   = map[string]bool{}
		ins   []<-chan string
		out   <-chan Project
		projs []Project
		f     = &Filter{}
		err   error
	)

	for _, name := range sm.dueScanners() {
		due[name] = true
	}

	for name := range sm.Scanners {

		if !sm.IsActive(name) {
			// Clear any cached results
			if err := wf.Cache.Store(sm.cacheName(name), nil); err != nil {
				log.Printf("[scan] error clearing cache: %s", err)
			}
			log.Printf("[%s] inactive", name)
			continue
		}

		if due[name] {
			sc := sm.Scanners[name]
			if c, err := sc.Scan(sm.conf); err == nil {
				log.Printf("[%s] reloading ...", name)
				ins = append(ins, cacheProjects(sm.cacheName(name), c))
			} else {
				log.Printf("[%s] error: %v", name, err)
			}
		} else {
			log.Printf("[%s] loading from cache ...", name)
			ins = append(ins, sm.scanFromCache(name))
		}
	}

	// real programs have middleware
	f.Use(makeFilterExcludes(conf.Excludes))
	f.Use(filterNotExist)
	f.Use(filterDupes)
	f.Use(filterNotProject)

	out = resultToProject(f.Apply(merge(ins...)))

	for proj := range out {
		projs = append(projs, proj)
	}

	err = wf.Cache.StoreJSON(cacheKey, projs)

	return err
}

// IsActive returns true if a scanner exists and is active.
func (sm *ScanManager) IsActive(name string) bool {
	_, ok := sm.Scanners[name]
	if !ok {
		return false
	}
	return sm.intervals[name] != 0
}

// IsDue returns true if a scanner is active and due.
func (sm *ScanManager) IsDue(name string) bool {
	if !sm.IsActive(name) {
		return false
	}

	return wf.Cache.Expired(sm.cacheName(name), sm.intervals[name])
}

// load data from cache.
func (sm *ScanManager) scanFromCache(name string) <-chan string {

	var (
		key = sm.cacheName(name)
		out = make(chan string)
	)

	go func() {

		defer timed(time.Now(), fmt.Sprintf(`[cache] loaded "%s"`, name))

		defer close(out)

		if !wf.Cache.Exists(key) {
			return
		}

		data, err := wf.Cache.Load(key)
		if err != nil {
			log.Printf("[scan] error reading cache: %v", err)
			return
		}

		scanner := bufio.NewScanner(bytes.NewReader(data))
		for scanner.Scan() {
			out <- scanner.Text()
		}
		if err := scanner.Err(); err != nil {
			log.Printf("[scan] error reading cache: %v", err)
		}
	}()

	return out
}

func (sm *ScanManager) dueScanners() []string {

	var (
		due   []string
		force bool
	)

	if !wf.Cache.Exists(cacheKey) {
		force = true
	}

	for name := range sm.Scanners {

		if !sm.IsActive(name) {
			continue
		}

		if force || sm.IsDue(name) {
			due = append(due, name)
		}
	}

	return due
}

func (sm *ScanManager) cacheName(name string) string {
	return "projects-" + name + ".txt"
}

// Load loads cached Projects.
func (sm *ScanManager) Load() ([]Project, error) {

	var (
		projs []Project
		err   error
	)

	if wf.Cache.Exists(cacheKey) {
		err = wf.Cache.LoadJSON(cacheKey, &projs)
	}

	return projs, err
}

// Find .sublime-project files with `mdfind`
type mdfindScanner struct{}

func (s *mdfindScanner) Name() string { return "mdfind" }
func (s *mdfindScanner) Scan(conf *config) (<-chan string, error) {
	cmd := exec.Command("/usr/bin/mdfind", "-name", ".sublime-project")
	return lineCommand(cmd, s.Name())
}

// Find *.sublime-project files with `locate`
type locateScanner struct{}

func (s *locateScanner) Name() string { return "locate" }
func (s *locateScanner) Scan(conf *config) (<-chan string, error) {
	cmd := exec.Command("/usr/bin/locate", "*.sublime-project")
	return lineCommand(cmd, s.Name())
}

type findScanner struct{}

func (s *findScanner) Name() string { return "find" }
func (s *findScanner) Scan(conf *config) (<-chan string, error) {

	var chs []<-chan string

	for _, sp := range conf.SearchPaths {

		argv := []string{sp.Path, "-maxdepth", fmt.Sprintf("%d", sp.Depth)}
		argv = append(argv, "-type", "f", "-name", "*.sublime-project")

		cmd := exec.Command("/usr/bin/find", argv...)

		ch, err := lineCommand(cmd, fmt.Sprintf("[%s] %s", s.Name(), sp.Path))
		if err != nil {
			return nil, err
		}

		chs = append(chs, ch)
	}

	return merge(chs...), nil
}

// Run a command and write the lines of its output to a channel.
func lineCommand(cmd *exec.Cmd, name string) (chan string, error) {

	var (
		out = make(chan string, 100)
		err error
	)

	go func() {

		defer close(out)
		defer timed(time.Now(), fmt.Sprintf("%s scan", name))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Printf("[%s] command failed: %v", name, err)
			return
		}

		if err := cmd.Start(); err != nil {
			log.Printf("[%s] command failed: %v", name, err)
			return
		}

		// Read mdfind output and send it to channel
		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			out <- scanner.Text()
		}
		if err := scanner.Err(); err != nil {
			log.Printf("[%s] couldn't parse output: %v", name, err)
		}

		if err != cmd.Wait() {
			log.Printf("[%s] command failed: %v", name, err)
		}
	}()

	return out, err
}

func makeFilterExcludes(patterns []string) Filterer {
	return func(in <-chan string) <-chan string {
		return filterExcludes(in, patterns)
	}
}

// Filter files that match any of the glob patterns.
func filterExcludes(in <-chan string, patterns []string) <-chan string {
	var globs []glob.Glob

	// Compile patterns
	for _, s := range patterns {
		if g, err := glob.Compile(s); err == nil {
			globs = append(globs, g)
		} else {
			log.Printf("[filter] invalid pattern (%s): %v", s, err)
		}
	}

	return filterMatches(in, func(r string) bool {
		for _, g := range globs {
			if g.Match(r) {
				// log.Printf("[filter] ignored (%s): %s", g, r.String())
				return true
			}
		}
		return false
	})
}

func filterNotProject(in <-chan string) <-chan string {
	return filterMatches(in, func(r string) bool {
		return !strings.HasSuffix(r, ".sublime-project")
	})
}

// Filter files that don't exist.
func filterNotExist(in <-chan string) <-chan string {
	return filterMatches(in, func(r string) bool {
		if _, err := os.Stat(r); err != nil {
			// log.Printf("[filter] doesn't exist: %s", p)
			return true
		}
		return false
	})
}

// Filter files that have already passed through.
func filterDupes(in <-chan string) <-chan string {

	seen := map[string]bool{}

	return filterMatches(in, func(r string) bool {

		if seen[r] {
			// log.Printf("[filter] duplicate: %s", r.String())
			return true
		}

		seen[r] = true
		return false
	})
}

// passes through paths from in to out, ignoring those for which ignore(path) returns true.
func filterMatches(in <-chan string, ignore func(r string) bool) <-chan string {

	var out = make(chan string)

	go func() {
		defer close(out)

		for p := range in {
			if ignore(p) {
				continue
			}
			out <- p
		}
	}()

	return out
}

func cacheProjects(key string, in <-chan string) <-chan string {

	projs := []string{}

	var out = make(chan string)

	go func() {

		defer close(out)

		for p := range in {
			projs = append(projs, p)
			out <- p
		}

		data := []byte(strings.Join(projs, "\n"))
		if err := wf.Cache.Store(key, data); err != nil {
			log.Printf("[cache] error storing %s: %v", key, err)
		} else {
			log.Printf("[cache] saved %d project(s) to %s", len(projs), key)
		}
	}()

	return out
}

// Read .sublime-project files
func resultToProject(in <-chan string) <-chan Project {

	var out = make(chan Project)

	go func() {
		defer close(out)

		for p := range in {

			var proj = Project{}

			proj, err := NewProject(p)
			if err != nil {
				log.Printf("[scan] couldn't read project file (%s): %v", p, err)
				continue
			}

			out <- proj
		}
	}()

	return out
}

// Combine the output of multiple channels into one.
func merge(ins ...<-chan string) <-chan string {
	var (
		wg  sync.WaitGroup
		out = make(chan string)
	)

	wg.Add(len(ins))

	for _, in := range ins {

		go func(in <-chan string) {
			defer wg.Done()
			for p := range in {
				out <- p
			}
		}(in)
	}

	go func() {
		wg.Wait()
		close(out)
	}()

	return out
}
<commit_msg>Log found projects<commit_after>//
// Copyright (c) 2018 Dean Jackson <deanishe@deanishe.net>
//
// MIT Licence. See http://opensource.org/licenses/MIT
//
// Created on 2018-01-26
//

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/deanishe/awgo/util"
	"github.com/gobwas/glob"
)

var (
	locateDBPath = "/var/db/locate.database"
	scanners     = map[string]Scanner{
		"find":   &findScanner{},
		"mdfind": &mdfindScanner{},
		"locate": &locateScanner{},
	}
)

// Scanner finds Sublime Text project files.
type Scanner interface {
	Name() string                             // name of scanner
	Scan(conf *config) (<-chan string, error) // scan for projects
}

// ScanManager loads and runs Scanners.
type ScanManager struct {
	conf      *config
	Scanners  map[string]Scanner
	intervals map[string]time.Duration
}

// NewScanManager initialises a ScanManager.
func NewScanManager(conf *config) *ScanManager {
	sm := &ScanManager{
		conf:      conf,
		Scanners:  map[string]Scanner{},
		intervals: map[string]time.Duration{},
	}

	for name, sc := range scanners {
		var d time.Duration
		switch name {
		case "mdfind":
			d = conf.MDFindInterval
		case "locate":
			d = conf.LocateInterval
		case "find":
			d = conf.FindInterval
		default:
			log.Printf("[scan] unknown scanner: %s", name)
			d = conf.FindInterval
		}
		sm.Scanners[name] = sc
		sm.intervals[name] = d
	}

	return sm
}

// ScanDue returns true if one or more scanners needs updating.
func (sm *ScanManager) ScanDue() bool {

	if !wf.Cache.Exists(cacheKey) {
		return true
	}

	if len(sm.dueScanners()) > 0 {
		return true
	}

	return false
}

// Scan updates the cached lists of projects.
func (sm *ScanManager) Scan() error {

	var (
		due   = map[string]bool{}
		ins   []<-chan string
		out   <-chan Project
		projs []Project
		f     = &Filter{}
		err   error
	)

	for _, name := range sm.dueScanners() {
		due[name] = true
	}

	for name := range sm.Scanners {

		if !sm.IsActive(name) {
			// Clear any cached results
			if err := wf.Cache.Store(sm.cacheName(name), nil); err != nil {
				log.Printf("[scan] error clearing cache: %s", err)
			}
			log.Printf("[%s] inactive", name)
			continue
		}

		if due[name] {
			sc := sm.Scanners[name]
			if c, err := sc.Scan(sm.conf); err == nil {
				log.Printf("[%s] reloading ...", name)
				ins = append(ins, cacheProjects(sm.cacheName(name), c))
			} else {
				log.Printf("[%s] error: %v", name, err)
			}
		} else {
			log.Printf("[%s] loading from cache ...", name)
			ins = append(ins, sm.scanFromCache(name))
		}
	}

	// real programs have middleware
	f.Use(makeFilterExcludes(conf.Excludes))
	f.Use(filterNotExist)
	f.Use(filterDupes)
	f.Use(filterNotProject)

	out = resultToProject(f.Apply(merge(ins...)))

	for proj := range out {
		log.Printf("[scan] project: %s (%s)", proj.Name(), util.PrettyPath(proj.Path))
		projs = append(projs, proj)
	}

	err = wf.Cache.StoreJSON(cacheKey, projs)

	return err
}

// IsActive returns true if a scanner exists and is active.
func (sm *ScanManager) IsActive(name string) bool {
	_, ok := sm.Scanners[name]
	if !ok {
		return false
	}
	return sm.intervals[name] != 0
}

// IsDue returns true if a scanner is active and due.
func (sm *ScanManager) IsDue(name string) bool {
	if !sm.IsActive(name) {
		return false
	}

	return wf.Cache.Expired(sm.cacheName(name), sm.intervals[name])
}

// load data from cache.
func (sm *ScanManager) scanFromCache(name string) <-chan string {

	var (
		key = sm.cacheName(name)
		out = make(chan string)
	)

	go func() {

		defer timed(time.Now(), fmt.Sprintf(`[cache] loaded "%s"`, name))

		defer close(out)

		if !wf.Cache.Exists(key) {
			return
		}

		data, err := wf.Cache.Load(key)
		if err != nil {
			log.Printf("[scan] error reading cache: %v", err)
			return
		}

		scanner := bufio.NewScanner(bytes.NewReader(data))
		for scanner.Scan() {
			out <- scanner.Text()
		}
		if err := scanner.Err(); err != nil {
			log.Printf("[scan] error reading cache: %v", err)
		}
	}()

	return out
}

func (sm *ScanManager) dueScanners() []string {

	var (
		due   []string
		force bool
	)

	if !wf.Cache.Exists(cacheKey) {
		force = true
	}

	for name := range sm.Scanners {

		if !sm.IsActive(name) {
			continue
		}

		if force || sm.IsDue(name) {
			due = append(due, name)
		}
	}

	return due
}

func (sm *ScanManager) cacheName(name string) string {
	return "projects-" + name + ".txt"
}

// Load loads cached Projects.
func (sm *ScanManager) Load() ([]Project, error) {

	var (
		projs []Project
		err   error
	)

	if wf.Cache.Exists(cacheKey) {
		err = wf.Cache.LoadJSON(cacheKey, &projs)
	}

	return projs, err
}

// Find .sublime-project files with `mdfind`
type mdfindScanner struct{}

func (s *mdfindScanner) Name() string { return "mdfind" }
func (s *mdfindScanner) Scan(conf *config) (<-chan string, error) {
	cmd := exec.Command("/usr/bin/mdfind", "-name", ".sublime-project")
	return lineCommand(cmd, s.Name())
}

// Find *.sublime-project files with `locate`
type locateScanner struct{}

func (s *locateScanner) Name() string { return "locate" }
func (s *locateScanner) Scan(conf *config) (<-chan string, error) {
	cmd := exec.Command("/usr/bin/locate", "*.sublime-project")
	return lineCommand(cmd, s.Name())
}

type findScanner struct{}

func (s *findScanner) Name() string { return "find" }
func (s *findScanner) Scan(conf *config) (<-chan string, error) {

	var chs []<-chan string

	for _, sp := range conf.SearchPaths {

		argv := []string{sp.Path, "-maxdepth", fmt.Sprintf("%d", sp.Depth)}
		argv = append(argv, "-type", "f", "-name", "*.sublime-project")

		cmd := exec.Command("/usr/bin/find", argv...)

		ch, err := lineCommand(cmd, fmt.Sprintf("[%s] %s", s.Name(), sp.Path))
		if err != nil {
			return nil, err
		}

		chs = append(chs, ch)
	}

	return merge(chs...), nil
}

// Run a command and write the lines of its output to a channel.
func lineCommand(cmd *exec.Cmd, name string) (chan string, error) {

	var (
		out = make(chan string, 100)
		err error
	)

	go func() {

		defer close(out)
		defer timed(time.Now(), fmt.Sprintf("%s scan", name))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Printf("[%s] command failed: %v", name, err)
			return
		}

		if err := cmd.Start(); err != nil {
			log.Printf("[%s] command failed: %v", name, err)
			return
		}

		// Read mdfind output and send it to channel
		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			out <- scanner.Text()
		}
		if err := scanner.Err(); err != nil {
			log.Printf("[%s] couldn't parse output: %v", name, err)
		}

		if err != cmd.Wait() {
			log.Printf("[%s] command failed: %v", name, err)
		}
	}()

	return out, err
}

func makeFilterExcludes(patterns []string) Filterer {
	return func(in <-chan string) <-chan string {
		return filterExcludes(in, patterns)
	}
}

// Filter files that match any of the glob patterns.
func filterExcludes(in <-chan string, patterns []string) <-chan string {
	var globs []glob.Glob

	// Compile patterns
	for _, s := range patterns {
		if g, err := glob.Compile(s); err == nil {
			globs = append(globs, g)
		} else {
			log.Printf("[filter] invalid pattern (%s): %v", s, err)
		}
	}

	return filterMatches(in, func(r string) bool {
		for _, g := range globs {
			if g.Match(r) {
				// log.Printf("[filter] ignored (%s): %s", g, r.String())
				return true
			}
		}
		return false
	})
}

func filterNotProject(in <-chan string) <-chan string {
	return filterMatches(in, func(r string) bool {
		return !strings.HasSuffix(r, ".sublime-project")
	})
}

// Filter files that don't exist.
func filterNotExist(in <-chan string) <-chan string {
	return filterMatches(in, func(r string) bool {
		if _, err := os.Stat(r); err != nil {
			// log.Printf("[filter] doesn't exist: %s", p)
			return true
		}
		return false
	})
}

// Filter files that have already passed through.
func filterDupes(in <-chan string) <-chan string {

	seen := map[string]bool{}

	return filterMatches(in, func(r string) bool {

		if seen[r] {
			// log.Printf("[filter] duplicate: %s", r.String())
			return true
		}

		seen[r] = true
		return false
	})
}

// passes through paths from in to out, ignoring those for which ignore(path) returns true.
func filterMatches(in <-chan string, ignore func(r string) bool) <-chan string {

	var out = make(chan string)

	go func() {
		defer close(out)

		for p := range in {
			if ignore(p) {
				continue
			}
			out <- p
		}
	}()

	return out
}

func cacheProjects(key string, in <-chan string) <-chan string {

	projs := []string{}

	var out = make(chan string)

	go func() {

		defer close(out)

		for p := range in {
			projs = append(projs, p)
			out <- p
		}

		data := []byte(strings.Join(projs, "\n"))
		if err := wf.Cache.Store(key, data); err != nil {
			log.Printf("[cache] error storing %s: %v", key, err)
		} else {
			log.Printf("[cache] saved %d project(s) to %s", len(projs), key)
		}
	}()

	return out
}

// Read .sublime-project files
func resultToProject(in <-chan string) <-chan Project {

	var out = make(chan Project)

	go func() {
		defer close(out)

		for p := range in {

			var proj = Project{}

			proj, err := NewProject(p)
			if err != nil {
				log.Printf("[scan] couldn't read project file (%s): %v", p, err)
				continue
			}

			out <- proj
		}
	}()

	return out
}

// Combine the output of multiple channels into one.
func merge(ins ...<-chan string) <-chan string {
	var (
		wg  sync.WaitGroup
		out = make(chan string)
	)

	wg.Add(len(ins))

	for _, in := range ins {

		go func(in <-chan string) {
			defer wg.Done()
			for p := range in {
				out <- p
			}
		}(in)
	}

	go func() {
		wg.Wait()
		close(out)
	}()

	return out
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"io"
	"unicode"
)

// Token represents a lexical token.
type Token int

// Tokens
const (
	ILLEGAL Token = iota
	WS
	EOF

	IDENT
	INTEGER

	LEFTPAREN
	RIGHTPAREN

	GAMETYPE
	ROMTYPE
)

func (t Token) String() string {
	switch t {
	case ILLEGAL:
		return "ILLEGAL"
	case WS:
		return "WS"
	case EOF:
		return "EOF"
	case IDENT:
		return "IDENT"
	case INTEGER:
		return "INTEGER"
	case LEFTPAREN:
		return "LEFTPAREN"
	case RIGHTPAREN:
		return "RIGHTPAREN"
	case GAMETYPE:
		return "GAMETYPE"
	case ROMTYPE:
		return "ROMTYPE"
	default:
		return ""
	}
}

var eof = rune(0)

// Scanner represents a lexical scanner.
type Scanner struct {
	r *bufio.Reader
}

// NewScanner returns a new instance of Scanner.
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r: bufio.NewReader(r),
	}
}

func (s *Scanner) read() rune {
	ch, _, err := s.r.ReadRune()
	if err != nil {
		return eof
	}
	return ch
}

func (s *Scanner) unread() {
	_ = s.r.UnreadRune()
}

// Scan returns the next token and its value.
func (s *Scanner) Scan() (Token, string) {
	ch := s.read()

	if unicode.IsSpace(ch) {
		s.unread()
		return s.scanSpace()
	} else if unicode.IsLetter(ch) || unicode.IsDigit(ch) {
		s.unread()
		return s.scanIdent()
	} else if isQuote(ch) {
		s.unread()
		return s.scanQuote()
	} else if isParen(ch) {
		if ch == '(' {
			return LEFTPAREN, "("
		} else if ch == ')' {
			return RIGHTPAREN, ")"
		}
	} else if ch == eof {
		return EOF, ""
	}

	return ILLEGAL, ""
}

func isQuote(ch rune) bool {
	return ch == '"'
}

func isParen(ch rune) bool {
	return ch == '(' || ch == ')'
}

func (s *Scanner) scanSpace() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if !unicode.IsSpace(ch) {
			s.unread()
			break
		} else {
			buf.WriteRune(ch)
		}
	}

	return WS, " "
}

func (s *Scanner) scanIdent() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '-' {
			s.unread()
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}

	return IDENT, buf.String()
}

func (s *Scanner) scanInt() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if !unicode.IsDigit(ch) {
			s.unread()
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}

	return INTEGER, buf.String()
}

func (s *Scanner) scanQuote() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if isQuote(ch) {
			_, _ = buf.WriteRune(ch)
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}

	return IDENT, buf.String()
}
<commit_msg>Remove unused integer stuff<commit_after>package main

import (
	"bufio"
	"bytes"
	"io"
	"unicode"
)

// Token represents a lexical token.
type Token int

// Tokens
const (
	ILLEGAL Token = iota
	WS
	EOF
	IDENT
	LEFTPAREN
	RIGHTPAREN
	GAMETYPE
	ROMTYPE
)

func (t Token) String() string {
	switch t {
	case ILLEGAL:
		return "ILLEGAL"
	case WS:
		return "WS"
	case EOF:
		return "EOF"
	case IDENT:
		return "IDENT"
	case LEFTPAREN:
		return "LEFTPAREN"
	case RIGHTPAREN:
		return "RIGHTPAREN"
	case GAMETYPE:
		return "GAMETYPE"
	case ROMTYPE:
		return "ROMTYPE"
	default:
		return ""
	}
}

var eof = rune(0)

// Scanner represents a lexical scanner.
type Scanner struct {
	r *bufio.Reader
}

// NewScanner returns a new instance of Scanner.
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r: bufio.NewReader(r),
	}
}

func (s *Scanner) read() rune {
	ch, _, err := s.r.ReadRune()
	if err != nil {
		return eof
	}
	return ch
}

func (s *Scanner) unread() {
	_ = s.r.UnreadRune()
}

// Scan returns the next token and its value.
func (s *Scanner) Scan() (Token, string) {
	ch := s.read()

	if unicode.IsSpace(ch) {
		s.unread()
		return s.scanSpace()
	} else if unicode.IsLetter(ch) || unicode.IsDigit(ch) {
		s.unread()
		return s.scanIdent()
	} else if isQuote(ch) {
		s.unread()
		return s.scanQuote()
	} else if isParen(ch) {
		if ch == '(' {
			return LEFTPAREN, "("
		} else if ch == ')' {
			return RIGHTPAREN, ")"
		}
	} else if ch == eof {
		return EOF, ""
	}

	return ILLEGAL, ""
}

func isQuote(ch rune) bool {
	return ch == '"'
}

func isParen(ch rune) bool {
	return ch == '(' || ch == ')'
}

func (s *Scanner) scanSpace() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if !unicode.IsSpace(ch) {
			s.unread()
			break
		} else {
			buf.WriteRune(ch)
		}
	}

	return WS, " "
}

func (s *Scanner) scanIdent() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '-' {
			s.unread()
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}

	return IDENT, buf.String()
}

func (s *Scanner) scanQuote() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())

	for {
		if ch := s.read(); ch == eof {
			break
		} else if isQuote(ch) {
			_, _ = buf.WriteRune(ch)
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}

	return IDENT, buf.String()
}
<|endoftext|>


<commit_before>package hbase

import (
	"math"
	"time"

	pb "github.com/golang/protobuf/proto"
	"github.com/lazyshot/go-hbase/proto"

	"bytes"
	"fmt"
	"strings"
)

type Scan struct {
	client *Client

	id    uint64
	table []byte

	StartRow []byte
	StopRow  []byte

	families   [][]byte
	qualifiers [][][]byte

	nextStartRow []byte

	numCached int
	closed    bool

	//for filters
	timeRange *TimeRange

	location *regionInfo
	server   *connection
}

const (
	// copy from golang source code time/time.go
	// since it is private in time package, just copy it
	secondsPerHour       = 60 * 60
	secondsPerDay        = 24 * secondsPerHour
	unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
)

var maxTimestamp time.Time

func init() {
	// because golang's internal time represent is from Jan 1st, 1
	// so if we want the max timestamp, we have to minus time.unixToInternal
	// and as hbase accept a microsecond based timestamp, we divided it by 1000
	maxTimestamp = time.Unix((math.MaxInt64-unixToInternal)/1000, 0)
}

func newScan(table []byte, client *Client) *Scan {
	return &Scan{
		client:       client,
		table:        table,
		nextStartRow: nil,

		families:   make([][]byte, 0),
		qualifiers: make([][][]byte, 0),

		numCached: 100,
		closed:    false,

		timeRange: nil,
	}
}

// set scan time range
func (s *Scan) SetTimeRange(from time.Time, to time.Time) {
	if s.timeRange == nil {
		s.timeRange = &TimeRange{
			From: from,
			To:   to,
		}
	} else {
		s.timeRange.From = from
		s.timeRange.To = to
	}
}

// set scan time start only.
// if set start only, use a max timestamp as end automaticly.
// but since max timestamp is not a precise value,
// you'd better use `SetTimeRange()` set start and end yourself.
func (s *Scan) SetTimeRangeFrom(from time.Time) {
	s.SetTimeRange(from, maxTimestamp)
}

// set scan time end only.
//if only set end, use time.Unix(0, 0)(Jan 1st, 1970) as start automaticly
func (s *Scan) SetTimeRangeTo(to time.Time) {
	s.SetTimeRange(time.Unix(0, 0), to)
}

func (s *Scan) SetCached(n int) {
	s.numCached = n
}

func (s *Scan) Map(f func(*ResultRow)) {
	for {
		results := s.next()

		if results == nil {
			break
		}

		for _, v := range results {
			f(v)

			if s.closed {
				return
			}
		}
	}
}

func (s *Scan) Close() {
	if s.closed == false {
		log.Debug("Closing scan: %d", s.id)
		s.closeScan(s.server, s.location, s.id)
		s.closed = true
	}
}

func (s *Scan) AddString(famqual string) error {
	parts := strings.Split(famqual, ":")

	if len(parts) > 2 {
		return fmt.Errorf("Too many colons were found in the family:qualifier string. '%s'", famqual)
	} else if len(parts) == 2 {
		s.AddStringColumn(parts[0], parts[1])
	} else {
		s.AddStringFamily(famqual)
	}

	return nil
}

func (s *Scan) AddStringColumn(family, qual string) {
	s.AddColumn([]byte(family), []byte(qual))
}

func (s *Scan) AddStringFamily(family string) {
	s.AddFamily([]byte(family))
}

func (s *Scan) AddColumn(family, qual []byte) {
	s.AddFamily(family)

	pos := s.posOfFamily(family)

	s.qualifiers[pos] = append(s.qualifiers[pos], qual)
}

func (s *Scan) AddFamily(family []byte) {
	pos := s.posOfFamily(family)

	if pos == -1 {
		s.families = append(s.families, family)
		s.qualifiers = append(s.qualifiers, make([][]byte, 0))
	}
}

func (s *Scan) posOfFamily(family []byte) int {
	for p, v := range s.families {
		if bytes.Equal(family, v) {
			return p
		}
	}
	return -1
}

func (s *Scan) getData(nextStart []byte) []*ResultRow {
	if s.closed {
		return nil
	}

	server, location := s.getServerAndLocation(s.table, nextStart)

	req := &proto.ScanRequest{
		Region: &proto.RegionSpecifier{
			Type:  proto.RegionSpecifier_REGION_NAME.Enum(),
			Value: []byte(location.name),
		},
		NumberOfRows: pb.Uint32(uint32(s.numCached)),
		Scan:         &proto.Scan{},
	}

	if s.id > 0 {
		req.ScannerId = pb.Uint64(s.id)
	} else {
		if s.StartRow != nil {
			req.Scan.StartRow = s.StartRow
		}
		if s.StopRow != nil {
			req.Scan.StopRow = s.StopRow
		}
		if s.timeRange != nil {
			req.Scan.TimeRange = &proto.TimeRange{
				From: pb.Uint64(uint64(s.timeRange.From.Unix()) * 1000),
				To:   pb.Uint64(uint64(s.timeRange.To.Unix()) * 1000),
			}
		}
	}

	for i, v := range s.families {
		req.Scan.Column = append(req.Scan.Column, &proto.Column{
			Family:    v,
			Qualifier: s.qualifiers[i],
		})
	}

	log.Debug("sending scan request: [server=%s] [id=%d]", server.name, s.id)

	cl := newCall(req)
	server.call(cl)

	log.Debug("sent scan request: [server=%s] [id=%d]", server.name, s.id)

	select {
	case msg := <-cl.responseCh:
		return s.processResponse(msg)
	}
}

var lastRegionRows int = 0

func (s *Scan) processResponse(response pb.Message) []*ResultRow {
	var res *proto.ScanResponse
	switch r := response.(type) {
	case *proto.ScanResponse:
		res = r
	default:
		log.Error("Invalid response returned: %T", response)
		return nil
	}

	nextRegion := true
	s.nextStartRow = nil
	s.id = res.GetScannerId()

	results := res.GetResults()
	n := len(results)

	lastRegionRows += n

	if (n == s.numCached) ||
		len(s.location.endKey) == 0 ||
		(s.StopRow != nil && bytes.Compare(s.location.endKey, s.StopRow) > 0 && n < s.numCached) ||
		(res.GetMoreResults() && n > 0) {
		nextRegion = false
	}

	if n < s.numCached {
		s.nextStartRow = incrementByteString(s.location.endKey, len(s.location.endKey)-1)
	}

	if nextRegion {
		log.Debug("Finished %s. Num results from region: %d. On to the next one.", s.location.name, lastRegionRows)
		s.closeScan(s.server, s.location, s.id)
		s.server = nil
		s.location = nil
		s.id = 0
		lastRegionRows = 0
	}

	if n == 0 && !nextRegion {
		log.Debug("N == 0 and !nextRegion")
		s.Close()
	}

	tbr := make([]*ResultRow, n)
	for i, v := range results {
		tbr[i] = newResultRow(v)
	}

	return tbr
}

func (s *Scan) next() []*ResultRow {
	startRow := s.nextStartRow
	if startRow == nil {
		startRow = s.StartRow
	}

	return s.getData(startRow)
}

func (s *Scan) closeScan(server *connection, location *regionInfo, id uint64) {

	req := &proto.ScanRequest{
		Region: &proto.RegionSpecifier{
			Type:  proto.RegionSpecifier_REGION_NAME.Enum(),
			Value: []byte(location.name),
		},
		ScannerId:    pb.Uint64(id),
		CloseScanner: pb.Bool(true),
	}
	cl := newCall(req)
	server.call(cl)
	<-cl.responseCh
}

func (s *Scan) getServerAndLocation(table, startRow []byte) (server *connection, location *regionInfo) {
	if s.server != nil && s.location != nil {
		server = s.server
		location = s.location
		return
	}
	log.Debug("Get next region to scan [table=%s] [startRow=%s]", table, startRow)

	location = s.client.locateRegion(table, startRow, true)
	server = s.client.getRegionConnection(location.server)

	log.Debug("Got the next region to scan [table=%s] [regionName=%s] [conn=%s]", table, location.name, server.name)

	s.server = server
	s.location = location
	return
}
<commit_msg>use UnixNano instead of Unix<commit_after>package hbase

import (
	"math"
	"time"

	pb "github.com/golang/protobuf/proto"
	"github.com/lazyshot/go-hbase/proto"

	"bytes"
	"fmt"
	"strings"
)

type Scan struct {
	client *Client

	id    uint64
	table []byte

	StartRow []byte
	StopRow  []byte

	families   [][]byte
	qualifiers [][][]byte

	nextStartRow []byte

	numCached int
	closed    bool

	//for filters
	timeRange *TimeRange

	location *regionInfo
	server   *connection
}

const (
	// copy from golang source code time/time.go
	// since it is private in time package, just copy it
	secondsPerHour       = 60 * 60
	secondsPerDay        = 24 * secondsPerHour
	unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
)

var maxTimestamp time.Time

func init() {
	// because golang's internal time represent is from Jan 1st, 1
	// so if we want the max timestamp, we have to minus time.unixToInternal
	// and as hbase accept a microsecond based timestamp, we divided it by 1000
	maxTimestamp = time.Unix((math.MaxInt64-unixToInternal)/1e9, 0)
}

func newScan(table []byte, client *Client) *Scan {
	return &Scan{
		client:       client,
		table:        table,
		nextStartRow: nil,

		families:   make([][]byte, 0),
		qualifiers: make([][][]byte, 0),

		numCached: 100,
		closed:    false,

		timeRange: nil,
	}
}

// set scan time range
func (s *Scan) SetTimeRange(from time.Time, to time.Time) {
	if s.timeRange == nil {
		s.timeRange = &TimeRange{
			From: from,
			To:   to,
		}
	} else {
		s.timeRange.From = from
		s.timeRange.To = to
	}
}

// set scan time start only.
// if set start only, use a max timestamp as end automaticly.
// but since max timestamp is not a precise value,
// you'd better use `SetTimeRange()` set start and end yourself.
func (s *Scan) SetTimeRangeFrom(from time.Time) {
	s.SetTimeRange(from, maxTimestamp)
}

// set scan time end only.
//if only set end, use time.Unix(0, 0)(Jan 1st, 1970) as start automaticly
func (s *Scan) SetTimeRangeTo(to time.Time) {
	s.SetTimeRange(time.Unix(0, 0), to)
}

func (s *Scan) SetCached(n int) {
	s.numCached = n
}

func (s *Scan) Map(f func(*ResultRow)) {
	for {
		results := s.next()

		if results == nil {
			break
		}

		for _, v := range results {
			f(v)

			if s.closed {
				return
			}
		}
	}
}

func (s *Scan) Close() {
	if s.closed == false {
		log.Debug("Closing scan: %d", s.id)
		s.closeScan(s.server, s.location, s.id)
		s.closed = true
	}
}

func (s *Scan) AddString(famqual string) error {
	parts := strings.Split(famqual, ":")

	if len(parts) > 2 {
		return fmt.Errorf("Too many colons were found in the family:qualifier string. '%s'", famqual)
	} else if len(parts) == 2 {
		s.AddStringColumn(parts[0], parts[1])
	} else {
		s.AddStringFamily(famqual)
	}

	return nil
}

func (s *Scan) AddStringColumn(family, qual string) {
	s.AddColumn([]byte(family), []byte(qual))
}

func (s *Scan) AddStringFamily(family string) {
	s.AddFamily([]byte(family))
}

func (s *Scan) AddColumn(family, qual []byte) {
	s.AddFamily(family)

	pos := s.posOfFamily(family)

	s.qualifiers[pos] = append(s.qualifiers[pos], qual)
}

func (s *Scan) AddFamily(family []byte) {
	pos := s.posOfFamily(family)

	if pos == -1 {
		s.families = append(s.families, family)
		s.qualifiers = append(s.qualifiers, make([][]byte, 0))
	}
}

func (s *Scan) posOfFamily(family []byte) int {
	for p, v := range s.families {
		if bytes.Equal(family, v) {
			return p
		}
	}
	return -1
}

func (s *Scan) getData(nextStart []byte) []*ResultRow {
	if s.closed {
		return nil
	}

	server, location := s.getServerAndLocation(s.table, nextStart)

	req := &proto.ScanRequest{
		Region: &proto.RegionSpecifier{
			Type:  proto.RegionSpecifier_REGION_NAME.Enum(),
			Value: []byte(location.name),
		},
		NumberOfRows: pb.Uint32(uint32(s.numCached)),
		Scan:         &proto.Scan{},
	}

	if s.id > 0 {
		req.ScannerId = pb.Uint64(s.id)
	} else {
		if s.StartRow != nil {
			req.Scan.StartRow = s.StartRow
		}
		if s.StopRow != nil {
			req.Scan.StopRow = s.StopRow
		}
		if s.timeRange != nil {
			req.Scan.TimeRange = &proto.TimeRange{
				From: pb.Uint64(uint64(s.timeRange.From.UnixNano() / 1e6)),
				To:   pb.Uint64(uint64(s.timeRange.To.UnixNano() / 1e6)),
			}
		}
	}

	for i, v := range s.families {
		req.Scan.Column = append(req.Scan.Column, &proto.Column{
			Family:    v,
			Qualifier: s.qualifiers[i],
		})
	}

	log.Debug("sending scan request: [server=%s] [id=%d]", server.name, s.id)

	cl := newCall(req)
	server.call(cl)

	log.Debug("sent scan request: [server=%s] [id=%d]", server.name, s.id)

	select {
	case msg := <-cl.responseCh:
		return s.processResponse(msg)
	}
}

var lastRegionRows int = 0

func (s *Scan) processResponse(response pb.Message) []*ResultRow {
	var res *proto.ScanResponse
	switch r := response.(type) {
	case *proto.ScanResponse:
		res = r
	default:
		log.Error("Invalid response returned: %T", response)
		return nil
	}

	nextRegion := true
	s.nextStartRow = nil
	s.id = res.GetScannerId()

	results := res.GetResults()
	n := len(results)

	lastRegionRows += n

	if (n == s.numCached) ||
		len(s.location.endKey) == 0 ||
		(s.StopRow != nil && bytes.Compare(s.location.endKey, s.StopRow) > 0 && n < s.numCached) ||
		(res.GetMoreResults() && n > 0) {
		nextRegion = false
	}

	if n < s.numCached {
		s.nextStartRow = incrementByteString(s.location.endKey, len(s.location.endKey)-1)
	}

	if nextRegion {
		log.Debug("Finished %s. Num results from region: %d. On to the next one.", s.location.name, lastRegionRows)
		s.closeScan(s.server, s.location, s.id)
		s.server = nil
		s.location = nil
		s.id = 0
		lastRegionRows = 0
	}

	if n == 0 && !nextRegion {
		log.Debug("N == 0 and !nextRegion")
		s.Close()
	}

	tbr := make([]*ResultRow, n)
	for i, v := range results {
		tbr[i] = newResultRow(v)
	}

	return tbr
}

func (s *Scan) next() []*ResultRow {
	startRow := s.nextStartRow
	if startRow == nil {
		startRow = s.StartRow
	}

	return s.getData(startRow)
}

func (s *Scan) closeScan(server *connection, location *regionInfo, id uint64) {

	req := &proto.ScanRequest{
		Region: &proto.RegionSpecifier{
			Type:  proto.RegionSpecifier_REGION_NAME.Enum(),
			Value: []byte(location.name),
		},
		ScannerId:    pb.Uint64(id),
		CloseScanner: pb.Bool(true),
	}
	cl := newCall(req)
	server.call(cl)
	<-cl.responseCh
}

func (s *Scan) getServerAndLocation(table, startRow []byte) (server *connection, location *regionInfo) {
	if s.server != nil && s.location != nil {
		server = s.server
		location = s.location
		return
	}
	log.Debug("Get next region to scan [table=%s] [startRow=%s]", table, startRow)

	location = s.client.locateRegion(table, startRow, true)
	server = s.client.getRegionConnection(location.server)

	log.Debug("Got the next region to scan [table=%s] [regionName=%s] [conn=%s]", table, location.name, server.name)

	s.server = server
	s.location = location
	return
}
<|endoftext|>


<commit_before>package middlewares

import (
	"net/http"

	"github.com/gorilla/context"
	"github.com/solher/zest/domain"
)

type AbstractAccountInter interface {
	CurrentSessionFromToken(authToken string) (*domain.Session, error)
}

type Sessions struct {
	interactor AbstractAccountInter
}

func NewSessions(accountInteractor AbstractAccountInter) *Sessions {
	return &Sessions{interactor: accountInteractor}
}

func (s *Sessions) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	authToken := r.Header.Get("Authorization")

	if authToken == "" {
		cookie, err := r.Cookie("authToken")
		if err == nil {
			authToken = cookie.Value
		}
	}

	if authToken != "" {
		session, _ := s.interactor.CurrentSessionFromToken(authToken)
		if session != nil {
			context.Set(r, "currentSession", *session)
		}
	}

	next(w, r)

	context.Clear(r)
}
<commit_msg>Now getting auth token properly.<commit_after>package middlewares

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/gorilla/context"
	"github.com/solher/zest/domain"
)

type AbstractAccountInter interface {
	CurrentSessionFromToken(authToken string) (*domain.Session, error)
}

type Sessions struct {
	interactor AbstractAccountInter
}

func NewSessions(accountInteractor AbstractAccountInter) *Sessions {
	return &Sessions{interactor: accountInteractor}
}

func (s *Sessions) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	authorizations := strings.Split(r.Header.Get("Authorization"), ",")
	var authToken string

	for _, v := range authorizations {
		fmt.Sscanf(strings.Trim(v, " "), "AuthToken authToken=%s", &authToken)
		if authToken != "" {
			break
		}
	}

	if authToken == "" {
		cookie, err := r.Cookie("authToken")
		if err == nil {
			authToken = cookie.Value
		}
	}

	if authToken != "" {
		session, _ := s.interactor.CurrentSessionFromToken(authToken)
		if session != nil {
			context.Set(r, "currentSession", *session)
		}
	}

	next(w, r)

	context.Clear(r)
}
<|endoftext|>


<commit_before>package buildkite

import "fmt"
import "strings"

// You can overriden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/buildkite.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "1.0-beta.24"
var buildVersion string = ""

func Version() string {
	// Only output the build version if a pre-release
	if strings.Contains(baseVersion, "beta") || strings.Contains(baseVersion, "alpha") {
		// Use a default buildVersion if one doesn't exist
		actualBuildVersion := buildVersion
		if actualBuildVersion == "" {
			actualBuildVersion = "x"
		}

		return fmt.Sprintf("%s.%s", baseVersion, actualBuildVersion)
	} else {
		return baseVersion
	}
}
<commit_msg>Bumping to 1.0-beta.25<commit_after>package buildkite

import "fmt"
import "strings"

// You can overriden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/buildkite.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "1.0-beta.25"
var buildVersion string = ""

func Version() string {
	// Only output the build version if a pre-release
	if strings.Contains(baseVersion, "beta") || strings.Contains(baseVersion, "alpha") {
		// Use a default buildVersion if one doesn't exist
		actualBuildVersion := buildVersion
		if actualBuildVersion == "" {
			actualBuildVersion = "x"
		}

		return fmt.Sprintf("%s.%s", baseVersion, actualBuildVersion)
	} else {
		return baseVersion
	}
}
<|endoftext|>


<commit_before>package quicktemplate

import (
	"testing"
)

func BenchmarkQWriterVString(b *testing.B) {
	v := createTestS(100)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.V(v)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterVInt(b *testing.B) {
	v := 1233455
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.V(v)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterQ(b *testing.B) {
	s := createTestS(100)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.Q(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterJ(b *testing.B) {
	s := createTestS(100)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.J(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterU(b *testing.B) {
	s := createTestS(100)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.U(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterF(b *testing.B) {
	f := 123.456
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.F(f)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterD(b *testing.B) {
	n := 123456
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.D(n)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterZ1Byte(b *testing.B) {
	benchmarkQWriterZ(b, 1)
}

func BenchmarkQWriterZ10Bytes(b *testing.B) {
	benchmarkQWriterZ(b, 10)
}

func BenchmarkQWriterZ100Byte(b *testing.B) {
	benchmarkQWriterZ(b, 100)
}

func BenchmarkQWriterZ1KByte(b *testing.B) {
	benchmarkQWriterZ(b, 1000)
}

func BenchmarkQWriterZ10KByte(b *testing.B) {
	benchmarkQWriterZ(b, 10000)
}

func BenchmarkQWriterS1Byte(b *testing.B) {
	benchmarkQWriterS(b, 1)
}

func BenchmarkQWriterS10Bytes(b *testing.B) {
	benchmarkQWriterS(b, 10)
}

func BenchmarkQWriterS100Byte(b *testing.B) {
	benchmarkQWriterS(b, 100)
}

func BenchmarkQWriterS1KByte(b *testing.B) {
	benchmarkQWriterS(b, 1000)
}

func BenchmarkQWriterS10KByte(b *testing.B) {
	benchmarkQWriterS(b, 10000)
}

func benchmarkQWriterZ(b *testing.B, size int) {
	z := createTestZ(size)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.Z(z)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func benchmarkQWriterS(b *testing.B, size int) {
	s := createTestS(size)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.S(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func createTestS(size int) string {
	return string(createTestZ(size))
}

var sample = []byte("\n\t\r\f\u0000" + `'"<>&;+ =@%\/?1234567890-_#$^sdffds`)

func createTestZ(size int) []byte {
	var b []byte
	for i := 0; i < size; i++ {
		b = append(b, sample[i%len(sample)])
	}
	return b
}
<commit_msg>Added more QWriter benchmarks<commit_after>package quicktemplate

import (
	"testing"
)

func BenchmarkQWriterVString(b *testing.B) {
	v := createTestS(100)
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.V(v)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterVInt(b *testing.B) {
	v := 1233455
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.V(v)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterQ1(b *testing.B) {
	benchmarkQWriterQ(b, 1)
}

func BenchmarkQWriterQ10(b *testing.B) {
	benchmarkQWriterQ(b, 10)
}

func BenchmarkQWriterQ100(b *testing.B) {
	benchmarkQWriterQ(b, 100)
}

func BenchmarkQWriterQ1K(b *testing.B) {
	benchmarkQWriterQ(b, 1000)
}

func BenchmarkQWriterQ10K(b *testing.B) {
	benchmarkQWriterQ(b, 10000)
}

func benchmarkQWriterQ(b *testing.B, size int) {
	s := createTestS(size)
	b.SetBytes(int64(size))
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.Q(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterJ1(b *testing.B) {
	benchmarkQWriterJ(b, 1)
}

func BenchmarkQWriterJ10(b *testing.B) {
	benchmarkQWriterJ(b, 10)
}

func BenchmarkQWriterJ100(b *testing.B) {
	benchmarkQWriterJ(b, 100)
}

func BenchmarkQWriterJ1K(b *testing.B) {
	benchmarkQWriterJ(b, 1000)
}

func BenchmarkQWriterJ10K(b *testing.B) {
	benchmarkQWriterJ(b, 10000)
}

func benchmarkQWriterJ(b *testing.B, size int) {
	s := createTestS(size)
	b.SetBytes(int64(size))
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.J(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterU1(b *testing.B) {
	benchmarkQWriterU(b, 1)
}

func BenchmarkQWriterU10(b *testing.B) {
	benchmarkQWriterU(b, 10)
}

func BenchmarkQWriterU100(b *testing.B) {
	benchmarkQWriterU(b, 100)
}

func BenchmarkQWriterU1K(b *testing.B) {
	benchmarkQWriterU(b, 1000)
}

func BenchmarkQWriterU10K(b *testing.B) {
	benchmarkQWriterU(b, 10000)
}

func benchmarkQWriterU(b *testing.B, size int) {
	s := createTestS(size)
	b.SetBytes(int64(size))
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.U(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterF(b *testing.B) {
	f := 123.456
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.F(f)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterD(b *testing.B) {
	n := 123456
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.D(n)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func BenchmarkQWriterZ1(b *testing.B) {
	benchmarkQWriterZ(b, 1)
}

func BenchmarkQWriterZ10(b *testing.B) {
	benchmarkQWriterZ(b, 10)
}

func BenchmarkQWriterZ100(b *testing.B) {
	benchmarkQWriterZ(b, 100)
}

func BenchmarkQWriterZ1K(b *testing.B) {
	benchmarkQWriterZ(b, 1000)
}

func BenchmarkQWriterZ10K(b *testing.B) {
	benchmarkQWriterZ(b, 10000)
}

func BenchmarkQWriterS1(b *testing.B) {
	benchmarkQWriterS(b, 1)
}

func BenchmarkQWriterS10(b *testing.B) {
	benchmarkQWriterS(b, 10)
}

func BenchmarkQWriterS100(b *testing.B) {
	benchmarkQWriterS(b, 100)
}

func BenchmarkQWriterS1K(b *testing.B) {
	benchmarkQWriterS(b, 1000)
}

func BenchmarkQWriterS10K(b *testing.B) {
	benchmarkQWriterS(b, 10000)
}

func benchmarkQWriterZ(b *testing.B, size int) {
	z := createTestZ(size)
	b.SetBytes(int64(size))
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.Z(z)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func benchmarkQWriterS(b *testing.B, size int) {
	s := createTestS(size)
	b.SetBytes(int64(size))
	b.RunParallel(func(pb *testing.PB) {
		var w QWriter
		bb := AcquireByteBuffer()
		w.w = bb
		for pb.Next() {
			w.S(s)
			bb.Reset()
		}
		ReleaseByteBuffer(bb)
	})
}

func createTestS(size int) string {
	return string(createTestZ(size))
}

var sample = []byte(`0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM`)

func createTestZ(size int) []byte {
	var b []byte
	for i := 0; i < size; i++ {
		b = append(b, sample[i%len(sample)])
	}
	return b
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"bufio"
	"os"
	"log"
	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	q, err := ch.QueueDeclare(
		"hello", // name
		false,   // durable
		false,   // delete when unused
		false,   // exclusive
		false,   // no-wait
		nil,     // arguments
	)

	failOnError(err, "Failed to declare a queue")

	scanner := bufio.NewScanner(os.Stdin)
    	var text string

    	for text != "exit" {
		fmt.Print("Enter your text: ")
		scanner.Scan()
		text = scanner.Text()

		if text != "exit" {
			err = ch.Publish(
			"",     // exchange
			q.Name, // routing key
			false,  // mandatory
			false,  // immediate
			amqp.Publishing{
				ContentType: "text/plain",
				Body:        []byte(text),
			})

			log.Printf(" [x] Sent %s", text)
			failOnError(err, "Failed to publish a message")
        	}
    	}
}
<commit_msg>The simplest thing that does something.<commit_after>package main

import (
	"fmt"
	"bufio"
	"os"
	"log"
	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
	failOnError(err, "Failed to connect to RabbitMQ!")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel!")
	defer ch.Close()

	q, err := ch.QueueDeclare(
		"hello", // name
		false,   // durable
		false,   // delete when unused
		false,   // exclusive
		false,   // no-wait
		nil,     // arguments
	)

	failOnError(err, "Failed to declare a queue!")

	scanner := bufio.NewScanner(os.Stdin)
    	var text string

    	for text != "exit" {
		fmt.Print("Enter your text: ")
		scanner.Scan()
		text = scanner.Text()

		if text != "exit" {
			err = ch.Publish(
			"",     // exchange
			q.Name, // routing key
			false,  // mandatory
			false,  // immediate
			amqp.Publishing{
				ContentType: "text/plain",
				Body:        []byte(text),
			})

			log.Printf(" [x] Sent %s", text)
			failOnError(err, "Failed to publish a message!")
        	}
    	}
}
<|endoftext|>


<commit_before>package converter

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestConvertBytesToBase64(t *testing.T) {
	Convey("Testing ConvertBytesToBase64", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToBase64(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "aGVsbG8gd29ybGQh")
	})
}

func TestConvertBase64ToBytes(t *testing.T) {
	Convey("Testing ConvertBase64ToBytes", t, func() {
		input := "aGVsbG8gd29ybGQh"
		var output interface{}
		err := ConvertBase64ToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToBase32(t *testing.T) {
	Convey("Testing ConvertBytesToBase32", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToBase32(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "NBSWY3DPEB3W64TMMQQQ====")
	})
}

func TestConvertBase32ToBytes(t *testing.T) {
	Convey("Testing ConvertBase32ToBytes", t, func() {
		input := "NBSWY3DPEB3W64TMMQQQ===="
		var output interface{}
		err := ConvertBase32ToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToString(t *testing.T) {
	Convey("Testing ConvertBytesToString", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "hello world!")
	})
}

func TestConvertStringToBytes(t *testing.T) {
	Convey("Testing ConvertStringToBytes", t, func() {
		input := "hello world!"
		var output interface{}
		err := ConvertStringToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToHex(t *testing.T) {
	Convey("Testing ConvertBytesToHex", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToHex(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "68656c6c6f20776f726c6421")
	})
}

func TestConvertHexToBytes(t *testing.T) {
	Convey("Testing ConvertHexToBytes", t, func() {
		input := "68656c6c6f20776f726c6421"
		var output interface{}
		err := ConvertHexToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertIntegerToString(t *testing.T) {
	Convey("Testing ConvertIntegerToString", t, func() {
		input := 1234567890
		var output interface{}
		err := ConvertIntegerToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "1234567890")
	})
}

func TestConvertStringToInteger(t *testing.T) {
	Convey("Testing ConvertStringToInteger", t, func() {
		input := "1234567890"
		var output interface{}
		err := ConvertStringToInteger(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, 1234567890)
	})
}

func TestConvertStringToFloat(t *testing.T) {
	Convey("Testing ConvertStringToFloat", t, func() {
		input := "3.1415"
		var output interface{}
		err := ConvertStringToFloat(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, 3.1415)
	})
}

func TestConvertFloatToString(t *testing.T) {
	Convey("Testing ConvertStringToFloat", t, func() {
		input := 3.1415
		var output interface{}
		err := ConvertFloatToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "3.1415")
	})
}
<commit_msg>Add a chaining example<commit_after>package converter

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func Test_chaining(t *testing.T) {
	Convey("Testing chaining", t, func() {
		input := "hello world!"
		var output1 interface{}
		var err error

		err = ConvertStringToBytes(input, &output1)
		So(err, ShouldBeNil)
		So(output1, ShouldResemble, []byte("hello world!"))

		var output2 interface{}
		err = ConvertBytesToHex(output1, &output2)
		So(err, ShouldBeNil)
		So(output2, ShouldEqual, "68656c6c6f20776f726c6421")

		var output3 interface{}
		err = ConvertHexToBytes(output2, &output3)
		So(err, ShouldBeNil)
		So(output3, ShouldResemble, []byte("hello world!"))

		var output4 interface{}
		err = ConvertBytesToString(output3, &output4)
		So(err, ShouldBeNil)
		So(output4, ShouldEqual, input)
	})
}

func TestConvertBytesToBase64(t *testing.T) {
	Convey("Testing ConvertBytesToBase64", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToBase64(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "aGVsbG8gd29ybGQh")
	})
}

func TestConvertBase64ToBytes(t *testing.T) {
	Convey("Testing ConvertBase64ToBytes", t, func() {
		input := "aGVsbG8gd29ybGQh"
		var output interface{}
		err := ConvertBase64ToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToBase32(t *testing.T) {
	Convey("Testing ConvertBytesToBase32", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToBase32(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "NBSWY3DPEB3W64TMMQQQ====")
	})
}

func TestConvertBase32ToBytes(t *testing.T) {
	Convey("Testing ConvertBase32ToBytes", t, func() {
		input := "NBSWY3DPEB3W64TMMQQQ===="
		var output interface{}
		err := ConvertBase32ToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToString(t *testing.T) {
	Convey("Testing ConvertBytesToString", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "hello world!")
	})
}

func TestConvertStringToBytes(t *testing.T) {
	Convey("Testing ConvertStringToBytes", t, func() {
		input := "hello world!"
		var output interface{}
		err := ConvertStringToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertBytesToHex(t *testing.T) {
	Convey("Testing ConvertBytesToHex", t, func() {
		input := []byte("hello world!")
		var output interface{}
		err := ConvertBytesToHex(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "68656c6c6f20776f726c6421")
	})
}

func TestConvertHexToBytes(t *testing.T) {
	Convey("Testing ConvertHexToBytes", t, func() {
		input := "68656c6c6f20776f726c6421"
		var output interface{}
		err := ConvertHexToBytes(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldResemble, []byte("hello world!"))
	})
}

func TestConvertIntegerToString(t *testing.T) {
	Convey("Testing ConvertIntegerToString", t, func() {
		input := 1234567890
		var output interface{}
		err := ConvertIntegerToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "1234567890")
	})
}

func TestConvertStringToInteger(t *testing.T) {
	Convey("Testing ConvertStringToInteger", t, func() {
		input := "1234567890"
		var output interface{}
		err := ConvertStringToInteger(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, 1234567890)
	})
}

func TestConvertStringToFloat(t *testing.T) {
	Convey("Testing ConvertStringToFloat", t, func() {
		input := "3.1415"
		var output interface{}
		err := ConvertStringToFloat(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, 3.1415)
	})
}

func TestConvertFloatToString(t *testing.T) {
	Convey("Testing ConvertStringToFloat", t, func() {
		input := 3.1415
		var output interface{}
		err := ConvertFloatToString(input, &output)
		So(err, ShouldBeNil)
		So(output, ShouldEqual, "3.1415")
	})
}
<|endoftext|>