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

// Package tls partially implements TLS 1.2, as specified in RFC 5246.
package tls

// BUG(agl): The crypto/tls package does not implement countermeasures
// against Lucky13 attacks on CBC-mode encryption. See
// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"time"
)

// Server returns a new TLS server side connection
// using conn as the underlying transport.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func Server(conn net.Conn, config *Config) *Conn {
	return &Conn{conn: conn, config: config}
}

// Client returns a new TLS client side connection
// using conn as the underlying transport.
// The config cannot be nil: users must set either ServerName or
// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
	return &Conn{conn: conn, config: config, isClient: true}
}

// A listener implements a network listener (net.Listener) for TLS connections.
type listener struct {
	net.Listener
	config *Config
}

// Accept waits for and returns the next incoming TLS connection.
// The returned connection c is a *tls.Conn.
func (l *listener) Accept() (c net.Conn, err error) {
	c, err = l.Listener.Accept()
	if err != nil {
		return
	}
	c = Server(c, l.config)
	return
}

// NewListener creates a Listener which accepts connections from an inner
// Listener and wraps each connection with Server.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func NewListener(inner net.Listener, config *Config) net.Listener {
	l := new(listener)
	l.Listener = inner
	l.config = config
	return l
}

// Listen creates a TLS listener accepting connections on the
// given network address using net.Listen.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func Listen(network, laddr string, config *Config) (net.Listener, error) {
	if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) {
		return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config")
	}
	l, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewListener(l, config), nil
}

type timeoutError struct{}

func (timeoutError) Error() string   { return "tls: DialWithDialer timed out" }
func (timeoutError) Timeout() bool   { return true }
func (timeoutError) Temporary() bool { return true }

// DialWithDialer connects to the given network address using dialer.Dial and
// then initiates a TLS handshake, returning the resulting TLS connection. Any
// timeout or deadline given in the dialer apply to connection and TLS
// handshake as a whole.
//
// DialWithDialer interprets a nil configuration as equivalent to the zero
// configuration; see the documentation of Config for the defaults.
func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
	// We want the Timeout and Deadline values from dialer to cover the
	// whole process: TCP connection and TLS handshake. This means that we
	// also need to start our own timers now.
	timeout := dialer.Timeout

	if !dialer.Deadline.IsZero() {
		deadlineTimeout := dialer.Deadline.Sub(time.Now())
		if timeout == 0 || deadlineTimeout < timeout {
			timeout = deadlineTimeout
		}
	}

	var errChannel chan error

	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- timeoutError{}
		})
	}

	rawConn, err := dialer.Dial(network, addr)
	if err != nil {
		return nil, err
	}

	colonPos := strings.LastIndex(addr, ":")
	if colonPos == -1 {
		colonPos = len(addr)
	}
	hostname := addr[:colonPos]

	if config == nil {
		config = defaultConfig()
	}
	// If no ServerName is set, infer the ServerName
	// from the hostname we're connecting to.
	if config.ServerName == "" {
		// Make a copy to avoid polluting argument or default.
		c := *config
		c.ServerName = hostname
		config = &c
	}

	conn := Client(rawConn, config)

	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()

		err = <-errChannel
	}

	if err != nil {
		rawConn.Close()
		return nil, err
	}

	return conn, nil
}

// Dial connects to the given network address using net.Dial
// and then initiates a TLS handshake, returning the resulting
// TLS connection.
// Dial interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config
// for the defaults.
func Dial(network, addr string, config *Config) (*Conn, error) {
	return DialWithDialer(new(net.Dialer), network, addr, config)
}

// LoadX509KeyPair reads and parses a public/private key pair from a pair of
// files. The files must contain PEM encoded data.
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
	certPEMBlock, err := ioutil.ReadFile(certFile)
	if err != nil {
		return Certificate{}, err
	}
	keyPEMBlock, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return Certificate{}, err
	}
	return X509KeyPair(certPEMBlock, keyPEMBlock)
}

// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data.
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
	fail := func(err error) (Certificate, error) { return Certificate{}, err }

	var cert Certificate
	var skippedBlockTypes []string
	for {
		var certDERBlock *pem.Block
		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
		if certDERBlock == nil {
			break
		}
		if certDERBlock.Type == "CERTIFICATE" {
			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
		} else {
			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
		}
	}

	if len(cert.Certificate) == 0 {
		if len(skippedBlockTypes) == 0 {
			return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input"))
		} else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
			return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
		} else {
			return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
		}
	}

	skippedBlockTypes = skippedBlockTypes[:0]
	var keyDERBlock *pem.Block
	for {
		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
		if keyDERBlock == nil {
			if len(skippedBlockTypes) == 0 {
				return fail(errors.New("crypto/tls: failed to find any PEM data in key input"))
			} else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
				return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key"))
			} else {
				return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
			}
		}
		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
			break
		}
		skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
	}

	var err error
	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
	if err != nil {
		return fail(err)
	}

	// We don't need to parse the public key for TLS, but we so do anyway
	// to check that it looks sane and matches the private key.
	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
	if err != nil {
		return fail(err)
	}

	switch pub := x509Cert.PublicKey.(type) {
	case *rsa.PublicKey:
		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
		if !ok {
			return fail(errors.New("crypto/tls: private key type does not match public key type"))
		}
		if pub.N.Cmp(priv.N) != 0 {
			return fail(errors.New("crypto/tls: private key does not match public key"))
		}
	case *ecdsa.PublicKey:
		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
		if !ok {
			return fail(errors.New("crypto/tls: private key type does not match public key type"))

		}
		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
			return fail(errors.New("crypto/tls: private key does not match public key"))
		}
	default:
		return fail(errors.New("crypto/tls: unknown public key algorithm"))
	}

	return cert, nil
}

// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
		return key, nil
	}
	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
		switch key := key.(type) {
		case *rsa.PrivateKey, *ecdsa.PrivateKey:
			return key, nil
		default:
			return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
		}
	}
	if key, err := x509.ParseECPrivateKey(der); err == nil {
		return key, nil
	}

	return nil, errors.New("crypto/tls: failed to parse private key")
}
<commit_msg>crypto/tls: note in comment that Certificate.Leaf is nil after parsing.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package tls partially implements TLS 1.2, as specified in RFC 5246.
package tls

// BUG(agl): The crypto/tls package does not implement countermeasures
// against Lucky13 attacks on CBC-mode encryption. See
// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"time"
)

// Server returns a new TLS server side connection
// using conn as the underlying transport.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func Server(conn net.Conn, config *Config) *Conn {
	return &Conn{conn: conn, config: config}
}

// Client returns a new TLS client side connection
// using conn as the underlying transport.
// The config cannot be nil: users must set either ServerName or
// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
	return &Conn{conn: conn, config: config, isClient: true}
}

// A listener implements a network listener (net.Listener) for TLS connections.
type listener struct {
	net.Listener
	config *Config
}

// Accept waits for and returns the next incoming TLS connection.
// The returned connection c is a *tls.Conn.
func (l *listener) Accept() (c net.Conn, err error) {
	c, err = l.Listener.Accept()
	if err != nil {
		return
	}
	c = Server(c, l.config)
	return
}

// NewListener creates a Listener which accepts connections from an inner
// Listener and wraps each connection with Server.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func NewListener(inner net.Listener, config *Config) net.Listener {
	l := new(listener)
	l.Listener = inner
	l.config = config
	return l
}

// Listen creates a TLS listener accepting connections on the
// given network address using net.Listen.
// The configuration config must be non-nil and must include
// at least one certificate or else set GetCertificate.
func Listen(network, laddr string, config *Config) (net.Listener, error) {
	if config == nil || (len(config.Certificates) == 0 && config.GetCertificate == nil) {
		return nil, errors.New("tls: neither Certificates nor GetCertificate set in Config")
	}
	l, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return NewListener(l, config), nil
}

type timeoutError struct{}

func (timeoutError) Error() string   { return "tls: DialWithDialer timed out" }
func (timeoutError) Timeout() bool   { return true }
func (timeoutError) Temporary() bool { return true }

// DialWithDialer connects to the given network address using dialer.Dial and
// then initiates a TLS handshake, returning the resulting TLS connection. Any
// timeout or deadline given in the dialer apply to connection and TLS
// handshake as a whole.
//
// DialWithDialer interprets a nil configuration as equivalent to the zero
// configuration; see the documentation of Config for the defaults.
func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
	// We want the Timeout and Deadline values from dialer to cover the
	// whole process: TCP connection and TLS handshake. This means that we
	// also need to start our own timers now.
	timeout := dialer.Timeout

	if !dialer.Deadline.IsZero() {
		deadlineTimeout := dialer.Deadline.Sub(time.Now())
		if timeout == 0 || deadlineTimeout < timeout {
			timeout = deadlineTimeout
		}
	}

	var errChannel chan error

	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- timeoutError{}
		})
	}

	rawConn, err := dialer.Dial(network, addr)
	if err != nil {
		return nil, err
	}

	colonPos := strings.LastIndex(addr, ":")
	if colonPos == -1 {
		colonPos = len(addr)
	}
	hostname := addr[:colonPos]

	if config == nil {
		config = defaultConfig()
	}
	// If no ServerName is set, infer the ServerName
	// from the hostname we're connecting to.
	if config.ServerName == "" {
		// Make a copy to avoid polluting argument or default.
		c := *config
		c.ServerName = hostname
		config = &c
	}

	conn := Client(rawConn, config)

	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()

		err = <-errChannel
	}

	if err != nil {
		rawConn.Close()
		return nil, err
	}

	return conn, nil
}

// Dial connects to the given network address using net.Dial
// and then initiates a TLS handshake, returning the resulting
// TLS connection.
// Dial interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config
// for the defaults.
func Dial(network, addr string, config *Config) (*Conn, error) {
	return DialWithDialer(new(net.Dialer), network, addr, config)
}

// LoadX509KeyPair reads and parses a public/private key pair from a pair of
// files. The files must contain PEM encoded data. On successful return,
// Certificate.Leaf will be nil because the parsed form of the certificate is
// not retained.
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
	certPEMBlock, err := ioutil.ReadFile(certFile)
	if err != nil {
		return Certificate{}, err
	}
	keyPEMBlock, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return Certificate{}, err
	}
	return X509KeyPair(certPEMBlock, keyPEMBlock)
}

// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data. On successful return, Certificate.Leaf will be nil because
// the parsed form of the certificate is not retained.
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
	fail := func(err error) (Certificate, error) { return Certificate{}, err }

	var cert Certificate
	var skippedBlockTypes []string
	for {
		var certDERBlock *pem.Block
		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
		if certDERBlock == nil {
			break
		}
		if certDERBlock.Type == "CERTIFICATE" {
			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
		} else {
			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
		}
	}

	if len(cert.Certificate) == 0 {
		if len(skippedBlockTypes) == 0 {
			return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input"))
		} else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
			return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
		} else {
			return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
		}
	}

	skippedBlockTypes = skippedBlockTypes[:0]
	var keyDERBlock *pem.Block
	for {
		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
		if keyDERBlock == nil {
			if len(skippedBlockTypes) == 0 {
				return fail(errors.New("crypto/tls: failed to find any PEM data in key input"))
			} else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
				return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key"))
			} else {
				return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
			}
		}
		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
			break
		}
		skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
	}

	var err error
	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
	if err != nil {
		return fail(err)
	}

	// We don't need to parse the public key for TLS, but we so do anyway
	// to check that it looks sane and matches the private key.
	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
	if err != nil {
		return fail(err)
	}

	switch pub := x509Cert.PublicKey.(type) {
	case *rsa.PublicKey:
		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
		if !ok {
			return fail(errors.New("crypto/tls: private key type does not match public key type"))
		}
		if pub.N.Cmp(priv.N) != 0 {
			return fail(errors.New("crypto/tls: private key does not match public key"))
		}
	case *ecdsa.PublicKey:
		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
		if !ok {
			return fail(errors.New("crypto/tls: private key type does not match public key type"))

		}
		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
			return fail(errors.New("crypto/tls: private key does not match public key"))
		}
	default:
		return fail(errors.New("crypto/tls: unknown public key algorithm"))
	}

	return cert, nil
}

// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
		return key, nil
	}
	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
		switch key := key.(type) {
		case *rsa.PrivateKey, *ecdsa.PrivateKey:
			return key, nil
		default:
			return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
		}
	}
	if key, err := x509.ParseECPrivateKey(der); err == nil {
		return key, nil
	}

	return nil, errors.New("crypto/tls: failed to parse private key")
}
<|endoftext|>


<commit_before>package rest_server

import (
    "net/http"

    "github.com/gorilla/mux"
)

type Route struct {
    Name        string
    Method      string
    Pattern     string
    HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    for _, route := range routes {
        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(route.HandlerFunc)
    }

    return router
}

var routes = Routes{
    Route{
        "Index",
        "GET",
        "/",
        authenticator.Wrap(Index),
    },
    Route{
        "RegisterUser",
        "POST",
        "/user/register/",
        RegisterUser,
    },
    Route{
        "SetUserFullName",
        "PUT",
        "/user/full-name/",
        authenticator.Wrap(SetUserFullName),
    },
    Route{
        "UnsetUserFullName",
        "DELETE",
        "/user/full-name/",
        authenticator.Wrap(UnsetUserFullName),
    },
    Route{
        "GetUserInfo",
        "GET",
        "/user/info/",
        authenticator.Wrap(GetUserInfo),
    },
    Route{
        "SetUserDefaultGroupId",
        "PUT",
        "/user/default-group-id/",
        authenticator.Wrap(SetUserDefaultGroupId),
    },
    Route{
        "UnsetUserDefaultGroupId",
        "DELETE",
        "/user/default-group-id/",
        authenticator.Wrap(UnsetUserDefaultGroupId),
    },
    Route{
        "GetUngroupedEvents",
        "GET",
        "/event/ungrouped/",
        authenticator.Wrap(GetUngroupedEvents),
    },
    Route{
        "GetGroupList",
        "GET",
        "/event/groups/",
        authenticator.Wrap(GetGroupList),
    },
    Route{
        "AddGroup",
        "POST",
        "/event/groups/",
        authenticator.Wrap(AddGroup),
    },
    Route{
        "UpdateGroup",
        "PUT",
        "/event/groups/{groupId}/",
        authenticator.Wrap(UpdateGroup),
    },
    Route{
        "GetGroup",
        "GET",
        "/event/groups/{groupId}/",
        authenticator.Wrap(GetGroup),
    },
    Route{
        "DeleteGroup",
        "DELETE",
        "/event/groups/{groupId}/",
        authenticator.Wrap(DeleteGroup),
    },
    Route{
        "GetGroupEventList",
        "GET",
        "/event/groups/{groupId}/events/",
        authenticator.Wrap(GetGroupEventList),
    },
    Route{
        "GetGroupEventsFull",
        "GET",
        "/event/groups/{groupId}/events-full/",
        authenticator.Wrap(GetGroupEventsFull),
    },
    Route{
        "GetGroupModifiedEvents",
        "GET",
        "/event/groups/{groupId}/modified-events/{sinceDateTime}/",
        authenticator.Wrap(GetGroupModifiedEvents),
    },
    Route{
        "GetGroupMovedEvents",
        "GET",
        "/event/groups/{groupId}/moved-events/{sinceDateTime}/",
        authenticator.Wrap(GetGroupMovedEvents),
    },
    Route{
        "DeleteEvent",
        "DELETE",
        "/event/{eventType}/{eventId}/",// we ignore {eventType}
        authenticator.Wrap(DeleteEvent),
    },
    Route{
        "CopyEvent",
        "POST",
        "/event/copy/",
        authenticator.Wrap(CopyEvent),
    },
    Route{
        "SetEventGroupId",
        "PUT",
        "/event/{eventType}/{eventId}/groupId/",
        authenticator.Wrap(SetEventGroupId),
    },
    Route{
        "AddTask",
        "POST",
        "/event/task/",
        authenticator.Wrap(AddTask),
    },
    Route{
        "GetTask",
        "GET",
        "/event/task/{eventId}/",
        authenticator.Wrap(GetTask),
    },
    Route{
        "UpdateTask",
        "PUT",
        "/event/task/{eventId}/",
        authenticator.Wrap(UpdateTask),
    },
}

<commit_msg>comment in routes.go<commit_after>package rest_server

import (
    "net/http"

    "github.com/gorilla/mux"
)

type Route struct {
    Name        string
    Method      string
    Pattern     string
    HandlerFunc http.HandlerFunc
}

type Routes []Route

func NewRouter() *mux.Router {
    router := mux.NewRouter().StrictSlash(true)
    for _, route := range routes {
        router.
            Methods(route.Method).
            Path(route.Pattern).
            Name(route.Name).
            Handler(route.HandlerFunc)
    }

    return router
}

var routes = Routes{
    Route{
        "Index",
        "GET",
        "/",
        authenticator.Wrap(Index),
    },
    Route{
        "RegisterUser",
        "POST",
        "/user/register/",
        RegisterUser,
    },
    Route{
        "SetUserFullName",
        "PUT",
        "/user/full-name/",
        authenticator.Wrap(SetUserFullName),
    },
    Route{
        "UnsetUserFullName",
        "DELETE",
        "/user/full-name/",
        authenticator.Wrap(UnsetUserFullName),
    },
    Route{
        "GetUserInfo",
        "GET",
        "/user/info/",
        authenticator.Wrap(GetUserInfo),
    },
    Route{
        "SetUserDefaultGroupId",
        "PUT",
        "/user/default-group-id/",
        authenticator.Wrap(SetUserDefaultGroupId),
    },
    Route{
        "UnsetUserDefaultGroupId",
        "DELETE",
        "/user/default-group-id/",
        authenticator.Wrap(UnsetUserDefaultGroupId),
    },
    Route{
        "GetUngroupedEvents",
        "GET",
        "/event/ungrouped/",
        authenticator.Wrap(GetUngroupedEvents),
    },
    Route{
        "GetGroupList",
        "GET",
        "/event/groups/",
        authenticator.Wrap(GetGroupList),
    },
    Route{
        "AddGroup",
        "POST",
        "/event/groups/",
        authenticator.Wrap(AddGroup),
    },
    Route{
        "UpdateGroup",
        "PUT",
        "/event/groups/{groupId}/",
        authenticator.Wrap(UpdateGroup),
    },
    Route{
        "GetGroup",
        "GET",
        "/event/groups/{groupId}/",
        authenticator.Wrap(GetGroup),
    },
    Route{
        "DeleteGroup",
        "DELETE",
        "/event/groups/{groupId}/",
        authenticator.Wrap(DeleteGroup),
    },
    Route{
        "GetGroupEventList",
        "GET",
        "/event/groups/{groupId}/events/",
        authenticator.Wrap(GetGroupEventList),
    },
    Route{
        "GetGroupEventsFull",
        "GET",
        "/event/groups/{groupId}/events-full/",
        authenticator.Wrap(GetGroupEventsFull),
    },
    Route{
        "GetGroupModifiedEvents",
        "GET",
        "/event/groups/{groupId}/modified-events/{sinceDateTime}/",
        authenticator.Wrap(GetGroupModifiedEvents),
    },
    Route{
        "GetGroupMovedEvents",
        "GET",
        "/event/groups/{groupId}/moved-events/{sinceDateTime}/",
        authenticator.Wrap(GetGroupMovedEvents),
    },
    Route{
        "DeleteEvent",
        "DELETE",
        "/event/{eventType}/{eventId}/",// we ignore {eventType}
        authenticator.Wrap(DeleteEvent),
    },
    Route{
        "CopyEvent",
        "POST",
        "/event/copy/",
        authenticator.Wrap(CopyEvent),
    },
    Route{
        "SetEventGroupId",
        "PUT",
        "/event/{eventType}/{eventId}/groupId/",// we ignore {eventType}
        authenticator.Wrap(SetEventGroupId),
    },
    Route{
        "AddTask",
        "POST",
        "/event/task/",
        authenticator.Wrap(AddTask),
    },
    Route{
        "GetTask",
        "GET",
        "/event/task/{eventId}/",
        authenticator.Wrap(GetTask),
    },
    Route{
        "UpdateTask",
        "PUT",
        "/event/task/{eventId}/",
        authenticator.Wrap(UpdateTask),
    },
}

<|endoftext|>


<commit_before>package main
import (
	"fmt"
	"strings"
	"strconv"
	"bufio"
	"os"
	"os/exec"
	"github.com/codegangsta/cli"
)

var CONFIG = make(map[string]string)
var REMOTE_REFS = make([]string, 0)

func listPr(c *cli.Context) {
	if err := validateRepo(c); err != nil {
		fmt.Println("Could not list Pull Reqests")
		os.Exit(1)
	}

	refSpec := fmt.Sprintf("refs/pull/*/head:refs/remotes/%s/pr/*", CONFIG["DEFAULT_REMOTE_REF"])

	_, err := exec.Command("git", "fetch", CONFIG["DEFAULT_REMOTE_REF"], refSpec).Output()
	if err != nil {
		fmt.Println("Could not fetch remote Pull Requests")
		os.Exit(1)
	}

	outputString , _ := exec.Command("git", "branch", "-r").Output()
	branches := fmt.Sprintf("%s", string(outputString[:]))
	refs := strings.Split(branches, "\n")

	for i := range refs {
		remoteBranch := refs[i]
		refSplits := strings.Split(remoteBranch, "/")
		if length := len(refSplits); length == 3  {
			if strings.TrimSpace(refSplits[0]) == CONFIG["DEFAULT_REMOTE_REF"] {
				fmt.Printf("%s\n", remoteBranch)
				fmt.Printf("%s\n", refSplits[2])
			}
		}
	}
	// filter the branches from default_remote_ref
}

func applyPr(c *cli.Context) {
	if err := validateRepo(c); err != nil {
		fmt.Println("Could not apply the Pull Request")
		os.Exit(1)
	}
	args := c.Args()
	fmt.Printf("%s\n", args)
}

func revertMaster(c *cli.Context) {
	if err := validateRepo(c); err != nil { fmt.Println("Could not revert to master branch")
		os.Exit(1)
	}
}

func switchRef(c *cli.Context) {
	// switch ref

}

func validateRepo(c *cli.Context) (err error){
	_, gitErr := exec.Command("git", "rev-parse").Output()
	if gitErr != nil {
		fmt.Println("Current directory not under git version control")
		return gitErr
	} else {
		initializeConfig()
		return nil
	}
}

func initializeConfig() {
	output, err := exec.Command("git", "remote", "show").Output()

	if err != nil {
		fmt.Println("Error running 'git remote show'")
		os.Exit(1)
	}
	outputString := fmt.Sprintf("%s", string(output[:]))
	refs := strings.Split(outputString, "\n")
	for index := range refs {
		if len(refs[index]) != 0 {
			REMOTE_REFS = append(REMOTE_REFS, refs[index])
		}
	}
	if len(REMOTE_REFS) == 0 {
		fmt.Println("No remote refs defined")
		refName, refUrl := getRef()
		_, err := exec.Command("git", "remote", "add", refName, refUrl).Output()
		if err != nil {
			fmt.Println("Error while inserting new git ref")
			os.Exit(1)
		}
		CONFIG["DEFAULT_REMOTE_REF"] = refName
		REMOTE_REFS[0] = refName
	} else if len(REMOTE_REFS) == 1 {
		CONFIG["DEFAULT_REMOTE_REF"] = REMOTE_REFS[0]
	} else {
		CONFIG["DEFAULT_REMOTE_REF"] = REMOTE_REFS[0]
		CONFIG["DEFAULT_REMOTE_REF"] = getDefaultRef()
	}

	CONFIG["DEFAULT_BRANCH"] = "master"
}

func getDefaultRef() (string) {
	fmt.Println("Choose ref to set as remote")
	for index := range REMOTE_REFS {
		fmt.Println("\t","(", (index+1), ") ", REMOTE_REFS[index])
	}
	reader := bufio.NewReader(os.Stdin)
	selected, _ := reader.ReadString('\n')
	selected = strings.TrimSpace(selected)
	index, _ := strconv.Atoi(selected)
	return REMOTE_REFS[index - 1]
}

func getRef() (string, string) {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Enter ref name (e.g. parent): ")
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	fmt.Print("Enter the url (e.g. git@github.com:ric03uec/tpr.git: ")
	refUrl, _ := reader.ReadString('\n')
	refUrl = strings.TrimSpace(refUrl)

	return name, refUrl
}

func main() {
	app := cli.NewApp()
	app.Name = "tpr"
	app.Usage = "Test github pull requests locally"
	app.Version = "0.1.0"
	app.Commands = []cli.Command{
		{
			Name: "list",
			ShortName: "l",
			Usage: "List of all the Pull Requests",
			Action: listPr,

		},
		{
			Name: "apply",
			ShortName: "a",
			Usage: "Apply the specified Pull Request",
			Action: applyPr,
		},
		{
			Name: "revert",
			ShortName: "r",
			Usage: "Revert back to master branch",
			Action: revertMaster,

		},
		{
			Name: "switch",
			ShortName: "s",
			Usage: "Switch default remote ref",
			Action: switchRef,
		},
	}

	app.Run(os.Args)
}
<commit_msg>completing the apply and revert flow<commit_after>package main
import (
	"fmt"
	"strings"
	"strconv"
	"bufio"
	"os"
	"os/exec"
	"github.com/codegangsta/cli"
)

var CONFIG = make(map[string]string)
var REMOTE_REFS = make([]string, 0)

func listPr(c *cli.Context) {
	if err := validateRepo(c); err != nil {
		fmt.Println("Could not list Pull Reqests")
		os.Exit(1)
	}

	outputString , _ := exec.Command("git", "branch", "-r").Output()
	branches := fmt.Sprintf("%s", string(outputString[:]))
	refs := strings.Split(branches, "\n")

	for i := range refs {
		remoteBranch := refs[i]
		refSplits := strings.Split(remoteBranch, "/")
		if length := len(refSplits); length == 3  {
			if strings.TrimSpace(refSplits[0]) == CONFIG["DEFAULT_REMOTE_REF"] {
				fmt.Printf("%s\n", remoteBranch)
			}
		}
	}
}

func applyPr(c *cli.Context) {
	if err := validateRepo(c); err != nil {
		fmt.Println("Could not apply the Pull Request")
		os.Exit(1)
	}

	fmt.Print(fmt.Sprintf("Enter the PR number to apply for ref %s (e.g. 42): ", CONFIG["DEFAULT_REMOTE_REF"]))
	reader := bufio.NewReader(os.Stdin)
	pr, _ := reader.ReadString('\n')
	pr = strings.TrimSpace(pr)
	prNumber, _ := strconv.Atoi(pr)

	outputString , _ := exec.Command("git", "branch", "-r").Output()
	branches := fmt.Sprintf("%s", string(outputString[:]))
	refs := strings.Split(branches, "\n")

	prExists := false
	for i := range refs {
		remoteBranch := refs[i]
		refSplits := strings.Split(remoteBranch, "/")
		if length := len(refSplits); length == 3  {
			if strings.TrimSpace(refSplits[0]) == CONFIG["DEFAULT_REMOTE_REF"] {
				remotePRNumber, _ := strconv.Atoi(refSplits[2])
				if remotePRNumber == prNumber {
					prExists = true
				}
			}
		}
	}
	if prExists {
		remoteRefPath := fmt.Sprintf("%s/pr/%s", CONFIG["DEFAULT_REMOTE_REF"], strconv.Itoa(prNumber))
		_, err := exec.Command("git", "checkout", remoteRefPath).Output()
		if err != nil {
			fmt.Println("Error occured while patching ")
			os.Exit(1)
		}
		fmt.Println("Successfully patched branch with ", remoteRefPath)
		os.Exit(0)
	} else {
		fmt.Println("No PR exists for ref : \n Try refreshing using 'tpr fetch'", CONFIG["DEFAULT_REMOTE_REF"])
		os.Exit(0)
	}
}

func revertMaster(c *cli.Context) {
	outputString, err := exec.Command("git", "checkout", "master").Output()
	if err != nil {
		fmt.Println("Error occured while reverting to master")
		os.Exit(1)
	}
	fmt.Println(fmt.Sprintf("%s", outputString))
	os.Exit(0)
}

func switchRef(c *cli.Context) {
	// switch ref

}

func fetch(c *cli.Context) {
	if err := validateRepo(c); err != nil {
		fmt.Println("Could not list Pull Reqests")
		os.Exit(1)
	}

	fmt.Println("Fetching pull requests for remote ref: ", CONFIG["DEFAULT_REMOTE_REF"])
	refSpec := fmt.Sprintf("refs/pull/*/head:refs/remotes/%s/pr/*", CONFIG["DEFAULT_REMOTE_REF"])

	_, err := exec.Command("git", "fetch", CONFIG["DEFAULT_REMOTE_REF"], refSpec).Output()
	if err != nil {
		fmt.Println("Could not fetch remote Pull Requests")
		os.Exit(1)
	}
	fmt.Println("Successfully fetched PR's for remote ref: ", CONFIG["DEFAULT_REMOTE_REF"])
}

func validateRepo(c *cli.Context) (err error){
	_, gitErr := exec.Command("git", "rev-parse").Output()
	if gitErr != nil {
		fmt.Println("Current directory not under git version control")
		return gitErr
	} else {
		initializeConfig()
		return nil
	}
}

func initializeConfig() {
	output, err := exec.Command("git", "remote", "show").Output()

	if err != nil {
		fmt.Println("Error running 'git remote show'")
		os.Exit(1)
	}
	outputString := fmt.Sprintf("%s", string(output[:]))
	refs := strings.Split(outputString, "\n")
	for index := range refs {
		if len(refs[index]) != 0 {
			REMOTE_REFS = append(REMOTE_REFS, refs[index])
		}
	}
	if len(REMOTE_REFS) == 0 {
		fmt.Println("No remote refs defined")
		refName, refUrl := getRef()
		_, err := exec.Command("git", "remote", "add", refName, refUrl).Output()
		if err != nil {
			fmt.Println("Error while inserting new git ref")
			os.Exit(1)
		}
		CONFIG["DEFAULT_REMOTE_REF"] = refName
		REMOTE_REFS[0] = refName
	} else if len(REMOTE_REFS) == 1 {
		CONFIG["DEFAULT_REMOTE_REF"] = REMOTE_REFS[0]
	} else {
		CONFIG["DEFAULT_REMOTE_REF"] = REMOTE_REFS[0]
		CONFIG["DEFAULT_REMOTE_REF"] = getDefaultRef()
	}

	CONFIG["DEFAULT_BRANCH"] = "master"
}

func getDefaultRef() (string) {
	fmt.Println("Choose ref to set as remote")
	for index := range REMOTE_REFS {
		fmt.Println("\t","(", (index+1), ") ", REMOTE_REFS[index])
	}
	reader := bufio.NewReader(os.Stdin)
	selected, _ := reader.ReadString('\n')
	selected = strings.TrimSpace(selected)
	index, _ := strconv.Atoi(selected)
	return REMOTE_REFS[index - 1]
}

func getRef() (string, string) {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Enter ref name (e.g. parent): ")
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	fmt.Print("Enter the url (e.g. git@github.com:ric03uec/tpr.git: ")
	refUrl, _ := reader.ReadString('\n')
	refUrl = strings.TrimSpace(refUrl)

	return name, refUrl
}

func main() {
	app := cli.NewApp()
	app.Name = "tpr"
	app.Usage = "Test github pull requests locally"
	app.Version = "0.1.0"
	app.Commands = []cli.Command{
		{
			Name: "list",
			ShortName: "l",
			Usage: "List of all the Pull Requests",
			Action: listPr,

		},
		{
			Name: "apply",
			ShortName: "a",
			Usage: "Apply the specified Pull Request",
			Action: applyPr,
		},
		{
			Name: "revert",
			ShortName: "r",
			Usage: "Revert back to master branch",
			Action: revertMaster,

		},
		{
			Name: "fetch",
			ShortName: "f",
			Usage: "Fetch latest upstream Pull Requests",
			Action: fetch,
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


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

package builder

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestBuilder_Select(t *testing.T) {
	sql, args, err := Select("c, d").From("table1").ToSQL()
	assert.NoError(t, err)
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? RIGHT JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		FullJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? FULL JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		CrossJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? CROSS JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		InnerJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? INNER JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)
}

func TestBuilderSelectGroupBy(t *testing.T) {
	sql, args, err := Select("c").From("table1").GroupBy("c").Having("count(c)=1").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c FROM table1 GROUP BY c HAVING count(c)=1", sql)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)
}

func TestBuilderSelectOrderBy(t *testing.T) {
	sql, args, err := Select("c").From("table1").OrderBy("c DESC").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c FROM table1 ORDER BY c DESC", sql)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)
}

func TestBuilder_From(t *testing.T) {
	// simple one
	sql, args, err := Select("c").From("table1").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// from sub
	sql, args, err = Select("sub.id").From("sub",
		Select("id").From("table1").Where(Eq{"a": 1})).Where(Eq{"b": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// from union
	sql, args, err = Select("sub.id").From("sub",
		Select("id").From("table1").Where(Eq{"a": 1}).
			Union("all", Select("id").From("table1").Where(Eq{"a": 2}))).Where(Eq{"b": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 3, len(args))
	fmt.Println(sql, args)

	// will raise error
	sql, args, err = Select("c").From("table1", Insert(Eq{"a": 1}).From("table1")).ToSQL()
	assert.Error(t, err)
	fmt.Println(err)
}

func TestBuilder_Limit(t *testing.T) {
	// simple -- OracleSQL style
	sql, args, err := Dialect(ORACLE).Select("a", "b", "c").From("table1").OrderBy("a ASC").
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple with join -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1 t1").
		InnerJoin("table2 t2", "t1.id = t2.ref_id").OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 1, len(args))
	fmt.Println(sql, args)

	// simple with where -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").Where(Eq{"f1": "v1", "f2": "v2"}).
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 4, len(args))
	fmt.Println(sql, args)

	// simple -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// simple -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// simple with where -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
		Where(Eq{"f1": "v1", "f2": "v2"}).OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple -- MsSQL style
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").PK("id").From("table1").
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// raise error
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.Error(t, err)
	fmt.Println(err)

	// union with limit -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").
		Where(Eq{"a": 1}).OrderBy("a ASC").Limit(5, 10).Union("ALL",
		Select("a", "b", "c").From("table1").Where(Eq{"a": 2}).OrderBy("a DESC").Limit(10)).
		Limit(3).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 6, len(args))
	assert.EqualValues(t, "[1 15 10 2 10 3]", fmt.Sprintf("%v", args))
	fmt.Println(sql, args)

	// union -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").Where(Eq{"a": 1}).
		OrderBy("a ASC").Limit(5, 9).Union("ALL",
		Select("a", "b", "c").From("table1").Where(Eq{"a": 2}).OrderBy("a DESC").Limit(10)).
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// union with limit -- MsSQL style
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").From("table1").
		PK("id1").Where(Eq{"a": 1}).OrderBy("a ASC").Limit(5, 6).Union("ALL",
		Select("a", "b").From("table1").Where(Eq{"b": 2}).OrderBy("a DESC").Limit(10)).
		OrderBy("b DESC").Limit(7).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 4, len(args))
	fmt.Println(sql, args)
}
<commit_msg>more test cases<commit_after>// Copyright 2018 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package builder

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestBuilder_Select(t *testing.T) {
	sql, args, err := Select("c, d").From("table1").ToSQL()
	assert.NoError(t, err)
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	fmt.Println(sql, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? RIGHT JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		FullJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? FULL JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		CrossJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? CROSS JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)

	sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
		InnerJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c, d FROM table1 LEFT JOIN table2 ON table1.id=? AND table2.id<? INNER JOIN table3 ON table2.id = table3.tid WHERE a=?",
		sql)
	assert.EqualValues(t, []interface{}{1, 3, 1}, args)
}

func TestBuilderSelectGroupBy(t *testing.T) {
	sql, args, err := Select("c").From("table1").GroupBy("c").Having("count(c)=1").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c FROM table1 GROUP BY c HAVING count(c)=1", sql)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)
}

func TestBuilderSelectOrderBy(t *testing.T) {
	sql, args, err := Select("c").From("table1").OrderBy("c DESC").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, "SELECT c FROM table1 ORDER BY c DESC", sql)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)
}

func TestBuilder_From(t *testing.T) {
	// simple one
	sql, args, err := Select("c").From("table1").ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// from sub
	sql, args, err = Select("sub.id").From("sub",
		Select("id").From("table1").Where(Eq{"a": 1})).Where(Eq{"b": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// from union
	sql, args, err = Select("sub.id").From("sub",
		Select("id").From("table1").Where(Eq{"a": 1}).
			Union("all", Select("id").From("table1").Where(Eq{"a": 2}))).Where(Eq{"b": 1}).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 3, len(args))
	fmt.Println(sql, args)

	// will raise error
	sql, args, err = Select("c").From("table1", Insert(Eq{"a": 1}).From("table1")).ToSQL()
	assert.Error(t, err)
	fmt.Println(err)
}

func TestBuilder_Limit(t *testing.T) {
	// simple -- OracleSQL style
	sql, args, err := Dialect(ORACLE).Select("a", "b", "c").From("table1").OrderBy("a ASC").
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple with join -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1 t1").
		InnerJoin("table2 t2", "t1.id = t2.ref_id").OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 1, len(args))
	fmt.Println(sql, args)

	// simple with where -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").Where(Eq{"f1": "v1", "f2": "v2"}).
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 4, len(args))
	fmt.Println(sql, args)

	// simple -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").OrderBy("a ASC").
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// simple -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// simple with where -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").
		Where(Eq{"f1": "v1", "f2": "v2"}).OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// simple -- MsSQL style
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").PK("id").From("table1").
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 0, len(args))
	fmt.Println(sql, args)

	// simple with where -- MsSQL style
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").PK("id").From("table1").
		Where(Eq{"a": "3"}).OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 3, len(args))
	fmt.Println(sql, args)

	// raise error
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").From("table1").
		OrderBy("a ASC").Limit(5, 10).ToSQL()
	assert.Error(t, err)
	fmt.Println(err)

	// union with limit -- OracleSQL style
	sql, args, err = Dialect(ORACLE).Select("a", "b", "c").From("table1").
		Where(Eq{"a": 1}).OrderBy("a ASC").Limit(5, 10).Union("ALL",
		Select("a", "b", "c").From("table1").Where(Eq{"a": 2}).OrderBy("a DESC").Limit(10)).
		Limit(3).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 6, len(args))
	assert.EqualValues(t, "[1 15 10 2 10 3]", fmt.Sprintf("%v", args))
	fmt.Println(sql, args)

	// union -- MySQL/SQLite/PostgreSQL style
	sql, args, err = Dialect(MYSQL).Select("a", "b", "c").From("table1").Where(Eq{"a": 1}).
		OrderBy("a ASC").Limit(5, 9).Union("ALL",
		Select("a", "b", "c").From("table1").Where(Eq{"a": 2}).OrderBy("a DESC").Limit(10)).
		Limit(5, 10).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 2, len(args))
	fmt.Println(sql, args)

	// union with limit -- MsSQL style
	sql, args, err = Dialect(MSSQL).Select("a", "b", "c").From("table1").
		PK("id1").Where(Eq{"a": 1}).OrderBy("a ASC").Limit(5, 6).Union("ALL",
		Select("a", "b").From("table1").Where(Eq{"b": 2}).OrderBy("a DESC").Limit(10)).
		OrderBy("b DESC").Limit(7).ToSQL()
	assert.NoError(t, err)
	assert.EqualValues(t, 4, len(args))
	fmt.Println(sql, args)
}
<|endoftext|>


<commit_before>package cache

import (
	//"bytes"
	//"encoding/gob"
	"time"

	"github.com/garyburd/redigo/redis"
)

//Cache storage implementation using redis as key/value storage
type RedisCacheStorage struct {
	redisPool      	redis.Pool
	ttlReadTimeout 	int
	cacheArea      	string
	enableTTL	 	bool
	Serializer     	Serializer // usually SerializerGOB implementation
}

var _=SerializerGOB{} // this is the usual serializer used above!!

//recover all cacheregistries of keys
func (s RedisCacheStorage) GetValuesMap(cacheKeys ...string) (map[string]CacheRegistry, error) {

	ttlMapChan := make(chan map[string]int, 1)
	if (s.enableTTL) {
		go func() {
			defer func() {
				if r := recover(); r != nil {
					log.Critical("Error trying to get ttl for registries %v!", cacheKeys)

					//in case of error, retur an empty map
					ttlMapChan <- make(map[string]int, 0)
				}
			}()

			//put result on channel
			ttlMapChan <- s.GetTTLMap(cacheKeys)
		}()
	}

	mapCacheRegistry := make(map[string]CacheRegistry)

	if len(cacheKeys) <= 0 {
		log.Debug("Nenhuma chave informada para busca. len(arrKeys)=0!")
		return mapCacheRegistry, nil //empty map
	}

	conn := s.redisPool.Get()
	defer conn.Close()
	var err error = nil

	//log.Debug(cacheKeys)

	replyMget, err := conn.Do("MGET", (s.getKeys(cacheKeys))...)
	if err != nil || replyMget == nil {
		log.Error("Error trying to get values from cache %v", err)
		log.Error("Returning an empty registry!")

		return mapCacheRegistry, err // error trying to search cache keys
	}

	arrResults, isArray := replyMget.([]interface{}) //try to convert the returned value to array

	if !isArray {
		log.Error("Value returned by a MGET query is not array for keys %v! No error will be returned!", cacheKeys) //formal check
		return make(map[string]CacheRegistry), nil
	}

	for _, cacheRegistryNotBytes := range arrResults {
		if cacheRegistryNotBytes != nil {

/*
			cacheRegistryBytes, isByteArr := cacheRegistryNotBytes.(string)
			if(isByteArr){
				log.Error("error trying to deserialize! not a byte array")
				return mapCacheRegistry, errors.New("not byte array!")
			}
*/

			cacheRegistryBytes, errBytes := redis.Bytes(cacheRegistryNotBytes, err)
			if errBytes != nil || replyMget == nil {
				return mapCacheRegistry, errBytes
			}

			cacheRegistry := CacheRegistry{}

			interfaceResp, _, errUnm := s.Serializer.UnmarshalMsg(cacheRegistry,cacheRegistryBytes)
			if errUnm!=nil {
				log.Error("error trying to deserialize!",errUnm)
				return mapCacheRegistry, errUnm
			}

			cacheRegistry, isCR := interfaceResp.(CacheRegistry)
			if(!isCR){
				log.Error("error trying to deserialize! object is not a CacheRegistry object type!")
				return mapCacheRegistry, nil
			}

			if err != nil {
				log.Error("Warning!! Error trying to recover data from redis!", err)
			} else {
				if cacheRegistry.Payload == nil {
					log.Error("ATENCAO! NENHUM PAYLOAD FOI RETORNADO DO REDIS!")
				}
				//Everything is alright
				mapCacheRegistry[cacheRegistry.CacheKey] = cacheRegistry
			}
		}
	}

	if (s.enableTTL) {
		select {
		//wait for ttl channel
		case ttlMap := <-ttlMapChan:
			mapCacheRegistry = s.zipTTL(mapCacheRegistry, ttlMap)
		//in case of timeout, returt an empty map
		case <-time.After(time.Duration(s.ttlReadTimeout) * time.Millisecond):
			log.Warning("Retrieve TTL for cachekeys %v from redis timeout after %dms, continuing without it.", cacheKeys, s.ttlReadTimeout)
			mapCacheRegistry = s.zipTTL(mapCacheRegistry, make(map[string]int, 0))
		}
	}

	return mapCacheRegistry, nil // err=nil by default, if everything is alright
}

//Recover current ttl information about registry
func (s RedisCacheStorage) GetTTL(key string) (int, error) {
	oneItemMap := make(map[string]CacheRegistry, 1)

	oneItemMap[key] = CacheRegistry{key, "", -2 /*not found*/, true, ""}

	respMap, errTTL := s.GetActualTTL(oneItemMap)
	return respMap[key].Ttl, errTTL

}

//Recover current ttl information about registries
func (s RedisCacheStorage) zipTTL(mapCacheRegistry map[string]CacheRegistry, ttlMap map[string]int) map[string]CacheRegistry {
	//prepare a keyval pair array
	for key, cacheRegistry := range mapCacheRegistry {
		if ttl, hasTtl := ttlMap[key]; hasTtl {
			cacheRegistry.Ttl = ttl
		} else {
			cacheRegistry.Ttl = -1
		}
		mapCacheRegistry[key] = cacheRegistry
	}

	return mapCacheRegistry
}

//Recover current ttl information about registries
func (s RedisCacheStorage) GetActualTTL(mapCacheRegistry map[string]CacheRegistry) (map[string]CacheRegistry, error) {

	conn := s.redisPool.Get()
	defer conn.Close()

	//prepare a keyval pair array
	for keyMap, cacheRegistry := range mapCacheRegistry {

		respTtl, err := conn.Do("ttl", s.getKey(keyMap))
		log.Debug("TTL %v that came from redis %v", keyMap, respTtl)

		if err != nil {
			log.Error("Error trying to retrieve ttl of key " + keyMap, err)
			cacheRegistry.Ttl = -2
			return mapCacheRegistry, err

		} else {
			intResp, _ := respTtl.(int64)
			cacheRegistry.Ttl = int(intResp)
		}

		mapCacheRegistry[keyMap] = setTTLToPayload(&cacheRegistry)
	}

	return mapCacheRegistry, nil
}

//Recover current ttl information about registries
func (s RedisCacheStorage) GetTTLMap(keys []string) map[string]int {

	ttlMap := make(map[string]int, len(keys))

	conn := s.redisPool.Get()
	defer conn.Close()

	//prepare a keyval pair array
	for _, key := range keys {

		respTtl, err := conn.Do("ttl", s.getKey(key))
		log.Debug("TTL %v that came from redis %v", key, respTtl)

		if err != nil {
			log.Error("Error trying to retrieve ttl of key " + key, err)
			ttlMap[key] = -2

		} else {
			intResp, _ := respTtl.(int64)
			ttlMap[key] = int(intResp)
		}

	}

	return ttlMap
}

//transfer the ttl information from cacheRegistry to paylaod interface, if it is ExposeTTL
func setTTLToPayload(cacheRegistry *CacheRegistry) CacheRegistry {

	payload := cacheRegistry.Payload

	exposeTTL, hasTtl := payload.(ExposeTTL)

	if hasTtl {
		log.Debug("Transfering ttl from redis (%d seconds) registry to ttl attribute of object %s", cacheRegistry.Ttl, cacheRegistry.CacheKey)
		payload = exposeTTL.SetTtl(cacheRegistry.Ttl) // assure the same type, from set ttl
		cacheRegistry.Payload = payload
		log.Debug("Setting ttl to %v, ttl value %v", cacheRegistry.CacheKey, exposeTTL.GetTtl())
	} else {
		log.Debug("Payload doesn't ExposeTTL %v", cacheRegistry.CacheKey)
	}

	return *cacheRegistry
}

//save informed registries on redis
func (s RedisCacheStorage) SetValues(registries ...CacheRegistry) error {

	var cacheRegistry CacheRegistry
	var index int

	defer func(cacheRegistry *CacheRegistry) {
		if r := recover(); r != nil {
			log.Error("Error trying to save cacheRegistry! recover= %v", r)
		}
	}(&cacheRegistry)

	conn := s.redisPool.Get()
	defer conn.Close()

	keyValPairs := make([]interface{}, 2 * len(registries))

	//prepare a keyval pair array
	for index, cacheRegistry = range registries {

		if len(cacheRegistry.CacheKey) == 0 {
			log.Error("cache key vazio !!!")
			//panic(errors.New("cache key vazio"))
		}

		var bytes = []byte{}
		bytes, err := s.Serializer.MarshalMsg(cacheRegistry,bytes)
		if(err!=nil){
			return err
		}

		if len(bytes) == 0 {
			log.Error("Error trying to decode value for key %v", cacheRegistry.CacheKey)
		}

		keyValPairs[(index * 2)] = s.getKey(cacheRegistry.CacheKey)
		keyValPairs[(index * 2) + 1] = bytes

	}

	_, errDo := conn.Do("MSET", keyValPairs...)
	if errDo != nil {
		log.Error("Error trying to save registry! %v %v", s.getKey(cacheRegistry.CacheKey), errDo)
		return errDo
	} else {
		log.Debug("Updating cache reg key %v ", s.getKey(cacheRegistry.CacheKey))
	}

	errF := conn.Flush()
	if errF != nil {
		log.Error("Error trying to flush connection! %v", errF)
		return errF
	}
	s.SetExpireTTL(registries...)
	return nil
}

//set defined ttl to the cache registries
func (s RedisCacheStorage) SetExpireTTL(cacheRegistries ...CacheRegistry) {
	conn := s.redisPool.Get()
	defer conn.Close()

	//prepare a keyval pair array
	for _, cacheRegistry := range cacheRegistries {
		if cacheRegistry.GetTTL() > 0 {
			//log.Debug("Setting ttl to key %s ", cacheRegistry.CacheKey)
			_, err := conn.Do("expire", s.getKey(cacheRegistry.CacheKey), cacheRegistry.GetTTL())
			if err != nil {
				log.Error("Error trying to save cache registry w! %v", err)
				return
			}

		} else {
			log.Debug("TTL for %s, ttl=%d will not be setted! ", s.getKey(cacheRegistry.CacheKey), cacheRegistry.GetTTL())
		}
	}

	err := conn.Flush()
	if err != nil {
		log.Error("Error trying to save cache registry z! %v", err)
		return
	}
}

//delete values from redis
func (s RedisCacheStorage) DeleteValues(cacheKeys ...string) error {

	c := s.redisPool.Get()
	defer func() {
		c.Close()
	}()

	//apply a prefix to cache area
	keys := s.getKeys(cacheKeys)

	reply, err := c.Do("DEL", keys...)
	if err != nil {
		log.Error("Erro ao tentar invalidar registro no cache!", err, reply)
		return err
	}

	return nil
}

//apply a prefix to cache area
func (s RedisCacheStorage) getKey(key string) string {
	var newKey string

	var serPredix = s.Serializer.GetPrefix()

	if len(s.cacheArea) > 0 {
		newKey = s.cacheArea + serPredix + key
	} else {
		newKey = key
	}

	return newKey
}

//apply a prefix to cachearea
func (s RedisCacheStorage) getKeys(keys []string) []interface{} {

	newKeys := make([]interface{}, len(keys))

	for index, key := range keys {
		newKey := s.getKey(key)
		newKeys[index] = newKey
	}

	return newKeys
}

//instantiate a new cachestorage redis
func NewRedisCacheStorage(hostPort string, password string, maxIdle int, readTimeout int, ttlReadTimeout int, cacheArea string, serializer Serializer, enableTTL bool) RedisCacheStorage {

	redisCacheStorage := RedisCacheStorage{
		*newPoolRedis(hostPort, password, maxIdle, readTimeout),
		ttlReadTimeout,
		cacheArea,
		enableTTL,
		serializer,
	}

	return redisCacheStorage
}

//create a redis connection pool
func newPoolRedis(server, password string, maxIdle int, readTimeout int) *redis.Pool {

	return &redis.Pool{
		MaxIdle:     maxIdle,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {

			c, err := redis.Dial("tcp", server, redis.DialReadTimeout(time.Duration(readTimeout) * time.Millisecond))
			if err != nil {
				log.Error("Erro ao tentar se conectar ao redis! ", err)
				return nil, err
			}

			return c, err
		},

		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}
<commit_msg>implemening recover protection for redis storage<commit_after>package cache

import (
	//"bytes"
	//"encoding/gob"
	"time"

	"github.com/garyburd/redigo/redis"
	"errors"
)

//Cache storage implementation using redis as key/value storage
type RedisCacheStorage struct {
	redisPool      	redis.Pool
	ttlReadTimeout 	int
	cacheArea      	string
	enableTtl	 	bool
	Serializer     	Serializer // usually SerializerGOB implementation
}

var _=SerializerGOB{} // this is the usual serializer used above!!

//recover all cacheregistries of keys
func (s RedisCacheStorage) GetValuesMap(cacheKeys ...string) (mapResp map[string]CacheRegistry, retError error) {

	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("Recovering error from Redis Cache Storage!!  %v", r)
			log.Error("Returning as no cached registry found!!")

			mapResp = make(map[string]CacheRegistry)
			retError = errors.New("Error trying to get values map")
			return
		}
	}()

	ttlMapChan := make(chan map[string]int, 1)

	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Critical("Error trying to get ttl for registries %v!", cacheKeys)

				//in case of error, retur an empty map
				ttlMapChan <- make(map[string]int, 0)
			}
		}()

		if (s.enableTtl) {
			//put result on channel
			ttlMapChan <- s.GetTTLMap(cacheKeys)
		}
	}()

	mapCacheRegistry := make(map[string]CacheRegistry)

	if len(cacheKeys) <= 0 {
		log.Debug("Nenhuma chave informada para busca. len(arrKeys)=0!")
		return mapCacheRegistry, nil //empty map
	}

	conn := s.redisPool.Get()
	if(conn==nil){
		log.Error("Error trying to acquire redis conn! null connection")
		return make(map[string]CacheRegistry), errors.New("Redis conn is null! Check conn errors!")
	}

	defer conn.Close()
	var err error = nil

	//log.Debug(cacheKeys)

	replyMget, err := conn.Do("MGET", (s.getKeys(cacheKeys))...)
	if err != nil || replyMget == nil {
		log.Error("Error trying to get values from cache %v", err)
		log.Error("Returning an empty registry!")

		return mapCacheRegistry, err // error trying to search cache keys
	}

	arrResults, isArray := replyMget.([]interface{}) //try to convert the returned value to array

	if !isArray {
		log.Error("Value returned by a MGET query is not array for keys %v! No error will be returned!", cacheKeys) //formal check
		return make(map[string]CacheRegistry), nil
	}

	for _, cacheRegistryNotBytes := range arrResults {
		if cacheRegistryNotBytes != nil {

/*
			cacheRegistryBytes, isByteArr := cacheRegistryNotBytes.(string)
			if(isByteArr){
				log.Error("error trying to deserialize! not a byte array")
				return mapCacheRegistry, errors.New("not byte array!")
			}
*/

			cacheRegistryBytes, errBytes := redis.Bytes(cacheRegistryNotBytes, err)
			if errBytes != nil || replyMget == nil {
				return mapCacheRegistry, errBytes
			}

			cacheRegistry := CacheRegistry{}

			interfaceResp, _, errUnm := s.Serializer.UnmarshalMsg(cacheRegistry,cacheRegistryBytes)
			if errUnm!=nil {
				log.Error("error trying to deserialize!",errUnm)
				return mapCacheRegistry, errUnm
			}

			cacheRegistry, isCR := interfaceResp.(CacheRegistry)
			if(!isCR){
				log.Error("error trying to deserialize! object is not a CacheRegistry object type!")
				return mapCacheRegistry, nil
			}

			if err != nil {
				log.Error("Warning!! Error trying to recover data from redis!", err)
			} else {
				if cacheRegistry.Payload == nil {
					log.Error("ATENCAO! NENHUM PAYLOAD FOI RETORNADO DO REDIS!")
				}
				//Everything is alright
				mapCacheRegistry[cacheRegistry.CacheKey] = cacheRegistry
			}
		}
	}

	if (s.enableTtl) {
		select {
		//wait for ttl channel
		case ttlMap := <-ttlMapChan:
			mapCacheRegistry = s.zipTTL(mapCacheRegistry, ttlMap)
		//in case of timeout, returt an empty map
		case <-time.After(time.Duration(s.ttlReadTimeout) * time.Millisecond):
			log.Warning("Retrieve TTL for cachekeys %v from redis timeout after %dms, continuing without it.", cacheKeys, s.ttlReadTimeout)
			mapCacheRegistry = s.zipTTL(mapCacheRegistry, make(map[string]int, 0))
		}
	}

	return mapCacheRegistry, nil // err=nil by default, if everything is alright
}

//Recover current ttl information about registry
func (s RedisCacheStorage) GetTTL(key string) (int, error) {
	oneItemMap := make(map[string]CacheRegistry, 1)

	oneItemMap[key] = CacheRegistry{key, "", -2 /*not found*/, true, ""}

	respMap, errTTL := s.GetActualTTL(oneItemMap)
	return respMap[key].Ttl, errTTL

}

//Recover current ttl information about registries
func (s RedisCacheStorage) zipTTL(mapCacheRegistry map[string]CacheRegistry, ttlMap map[string]int) map[string]CacheRegistry {
	//prepare a keyval pair array
	for key, cacheRegistry := range mapCacheRegistry {
		if ttl, hasTtl := ttlMap[key]; hasTtl {
			cacheRegistry.Ttl = ttl
		} else {
			cacheRegistry.Ttl = -1
		}
		mapCacheRegistry[key] = cacheRegistry
	}

	return mapCacheRegistry
}

//Recover current ttl information about registries
func (s RedisCacheStorage) GetActualTTL(mapCacheRegistry map[string]CacheRegistry) (returnMap map[string]CacheRegistry, retError error) {

	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("TTL Recovering error from Redis Cache Storage!!  %v", r)
			log.Error("Returning as no TTL info found!!")

			returnMap = mapCacheRegistry
			retError = errors.New("Error trying to get actual ttl val!")

			return
		}
	}()

	conn := s.redisPool.Get()
	if(conn==nil){
		log.Error("TTL: Error trying to acquire redis conn! null connection")
		return make(map[string]CacheRegistry), errors.New("TTL: Redis conn is null! Check conn errors!")
	}
	defer conn.Close()

	//prepare a keyval pair array
	for keyMap, cacheRegistry := range mapCacheRegistry {

		respTtl, err := conn.Do("ttl", s.getKey(keyMap))
		log.Debug("TTL %v that came from redis %v", keyMap, respTtl)

		if err != nil {
			log.Error("Error trying to retrieve ttl of key " + keyMap, err)
			cacheRegistry.Ttl = -2
			return mapCacheRegistry, err

		} else {
			intResp, _ := respTtl.(int64)
			cacheRegistry.Ttl = int(intResp)
		}

		mapCacheRegistry[keyMap] = setTTLToPayload(&cacheRegistry)
	}

	return mapCacheRegistry, nil
}

//Recover current ttl information about registries
func (s RedisCacheStorage) GetTTLMap(keys []string)  (retTTLMap map[string]int ){

	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("TTL error from Redis Cache Storage!!  %v", r)
			log.Error("Returning as emptu ttl map !!")

			retTTLMap = make(map[string]int, 0)
			return
		}
	}()

	ttlMap := make(map[string]int, len(keys))

	conn := s.redisPool.Get()
	if(conn==nil){
		log.Error("TTLMap: Error trying to acquire redis conn! null connection")
		return make(map[string]int)
	}
	defer conn.Close()

	//prepare a keyval pair array
	for _, key := range keys {

		respTtl, err := conn.Do("ttl", s.getKey(key))
		log.Debug("TTL %v that came from redis %v", key, respTtl)

		if err != nil {
			log.Error("Error trying to retrieve ttl of key " + key, err)
			ttlMap[key] = -2

		} else {
			intResp, _ := respTtl.(int64)
			ttlMap[key] = int(intResp)
		}

	}

	return ttlMap
}

//transfer the ttl information from cacheRegistry to paylaod interface, if it is ExposeTTL
func setTTLToPayload(cacheRegistry *CacheRegistry) CacheRegistry {

	payload := cacheRegistry.Payload

	exposeTTL, hasTtl := payload.(ExposeTTL)

	if hasTtl {
		log.Debug("Transfering ttl from redis (%d seconds) registry to ttl attribute of object %s", cacheRegistry.Ttl, cacheRegistry.CacheKey)
		payload = exposeTTL.SetTtl(cacheRegistry.Ttl) // assure the same type, from set ttl
		cacheRegistry.Payload = payload
		log.Debug("Setting ttl to %v, ttl value %v", cacheRegistry.CacheKey, exposeTTL.GetTtl())
	} else {
		log.Debug("Payload doesn't ExposeTTL %v", cacheRegistry.CacheKey)
	}

	return *cacheRegistry
}

//save informed registries on redis
func (s RedisCacheStorage) SetValues(registries ...CacheRegistry) (retErr error) {

	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("Error trying to save cacheRegs!!  %v", r)
			log.Error("Returning recovered error!")

			retErr = errors.New("Error trying to save cacheReg")
			return
		}
	}()

	var cacheRegistry CacheRegistry
	var index int

	conn := s.redisPool.Get()
	if(conn==nil){
		log.Error("SetValues: Error trying to acquire redis conn! null connection")
		return errors.New("SetValues: Redis conn is null! Check conn errors!")
	}

	defer conn.Close()

	keyValPairs := make([]interface{}, 2 * len(registries))

	//prepare a keyval pair array
	for index, cacheRegistry = range registries {

		if len(cacheRegistry.CacheKey) == 0 {
			log.Error("cache key vazio !!!")
			//panic(errors.New("cache key vazio"))
		}

		var bytes = []byte{}
		bytes, err := s.Serializer.MarshalMsg(cacheRegistry,bytes)
		if(err!=nil){
			return err
		}

		if len(bytes) == 0 {
			log.Error("Error trying to decode value for key %v", cacheRegistry.CacheKey)
		}

		keyValPairs[(index * 2)] = s.getKey(cacheRegistry.CacheKey)
		keyValPairs[(index * 2) + 1] = bytes

	}

	_, errDo := conn.Do("MSET", keyValPairs...)
	if errDo != nil {
		log.Error("Error trying to save registry! %v %v", s.getKey(cacheRegistry.CacheKey), errDo)
		return errDo
	} else {
		log.Debug("Updating cache reg key %v ", s.getKey(cacheRegistry.CacheKey))
	}

	errF := conn.Flush()
	if errF != nil {
		log.Error("Error trying to flush connection! %v", errF)
		return errF
	}
	s.SetExpireTTL(registries...)
	return nil
}

//set defined ttl to the cache registries
func (s RedisCacheStorage) SetExpireTTL(cacheRegistries ...CacheRegistry) {
	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("Error trying to set expire ttl!!  %v", r)
			return
		}
	}()

	conn := s.redisPool.Get()
	if(conn==nil){
		log.Error("SetExpires: Error trying to acquire redis conn! null connection")
		return
	}

	defer conn.Close()

	//prepare a keyval pair array
	for _, cacheRegistry := range cacheRegistries {
		if cacheRegistry.GetTTL() > 0 {
			//log.Debug("Setting ttl to key %s ", cacheRegistry.CacheKey)
			_, err := conn.Do("expire", s.getKey(cacheRegistry.CacheKey), cacheRegistry.GetTTL())
			if err != nil {
				log.Error("Error trying to save cache registry w! %v", err)
				return
			}

		} else {
			log.Debug("TTL for %s, ttl=%d will not be setted! ", s.getKey(cacheRegistry.CacheKey), cacheRegistry.GetTTL())
		}
	}

	err := conn.Flush()
	if err != nil {
		log.Error("Error trying to save cache registry z! %v", err)
		return
	}
}

//delete values from redis
func (s RedisCacheStorage) DeleteValues(cacheKeys ...string) ( retErr error) {
	c := s.redisPool.Get()
	if(c==nil){
		log.Error("Delete: Error trying to acquire redis conn! null connection")
		return errors.New("Delete: Redis conn is null! Check conn errors!")
	}

	defer func() { //assure for not panicking
		if r := recover(); r != nil {
			log.Error("Error trying to delete reg!!  %v", r)

			retErr = errors.New("Error trying to delete reg")
			return
		}

		if(c!=nil){
			c.Close()
		}
	}()

	//apply a prefix to cache area
	keys := s.getKeys(cacheKeys)

	reply, err := c.Do("DEL", keys...)
	if err != nil {
		log.Error("Erro ao tentar invalidar registro no cache!", err, reply)
		return err
	}

	return nil
}

//apply a prefix to cache area
func (s RedisCacheStorage) getKey(key string) string {
	var newKey string

	var serPredix = s.Serializer.GetPrefix()

	if len(s.cacheArea) > 0 {
		newKey = s.cacheArea + serPredix + key
	} else {
		newKey = key
	}

	return newKey
}

//apply a prefix to cachearea
func (s RedisCacheStorage) getKeys(keys []string) []interface{} {

	newKeys := make([]interface{}, len(keys))

	for index, key := range keys {
		newKey := s.getKey(key)
		newKeys[index] = newKey
	}

	return newKeys
}

//instantiate a new cachestorage redis
func NewRedisCacheStorage(hostPort string, password string, maxIdle int, readTimeout int, ttlReadTimeout int, cacheArea string, serializer Serializer, enableTTL bool) RedisCacheStorage {

	redisCacheStorage := RedisCacheStorage{
		*newPoolRedis(hostPort, password, maxIdle, readTimeout),
		ttlReadTimeout,
		cacheArea,
		enableTTL,
		serializer,
	}

	return redisCacheStorage
}

//create a redis connection pool
func newPoolRedis(server, password string, maxIdle int, readTimeout int) *redis.Pool {

	return &redis.Pool{
		MaxIdle:     maxIdle,
		IdleTimeout: 240 * time.Second,
		Dial: func() ( retConn redis.Conn, retErr error) {

			defer func() { //assure for not panicking
				if r := recover(); r != nil {
					log.Error("Error open redis conn!!  %v", r)
					log.Error("Retuning error")

					retConn = nil
					retErr = errors.New("Error trying to open redis conn!!")

					return
				}
			}()

			c, err := redis.Dial("tcp", server, redis.DialReadTimeout(time.Duration(readTimeout) * time.Millisecond))
			if err != nil {
				log.Error("Erro ao tentar se conectar ao redis! ", err)
				return nil, err
			}

			return c, err
		},

		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}
<|endoftext|>


<commit_before>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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 cachehash

import "container/list"

type CacheHash struct {
	h      map[interface{}]*list.Element
	l      *list.List
	len    int
	maxLen int
}

type keyValue struct {
	Key   interface{}
	Value interface{}
}

func (c *CacheHash) Init(maxLen int) {
	c.l = list.New()
	c.l = c.l.Init()
	c.h = make(map[interface{}]*list.Element)
	c.len = 0
	c.maxLen = maxLen
}

func (c *CacheHash) Eject() {

}

func (c *CacheHash) Add(k interface{}, v interface{}) bool {
	e, ok := c.h[k]
	if ok {
		kv := e.Value.(keyValue)
		kv.Key = k
		kv.Value = v
		c.l.MoveToFront(e)
	} else {
		if c.len >= c.maxLen {
			c.Eject()
		}
		var kv keyValue
		kv.Key = k
		kv.Value = v
		e = c.l.PushFront(kv)
		c.len++
		c.h[k] = e
	}
	return ok
}

func (c *CacheHash) First() (interface{}, interface{}) {
	if c.len == 0 {
		return nil, nil
	}
	e := c.l.Front()
	kv := e.Value.(keyValue)
	return kv.Key, kv.Value
}

func (c *CacheHash) Last() (interface{}, interface{}) {
	if c.len == 0 {
		return nil, nil
	}
	e := c.l.Back()
	kv := e.Value.(keyValue)
	return kv.Key, kv.Value

}

func (c *CacheHash) Get(k interface{}) (interface{}, bool) {
	e, ok := c.h[k]
	if ok {
		c.l.MoveToFront(e)
		return e.Value, ok
	}
	return nil, ok
}

func (c *CacheHash) GetNoMove(k interface{}) (interface{}, bool) {
	e, ok := c.h[k]
	if ok {
		return e.Value, ok
	}
	return nil, ok
}

func (c *CacheHash) Has(k interface{}) bool {
	_, ok := c.h[k]
	return ok
}

func (c *CacheHash) Delete(k interface{}) bool {
	return false
}

func (c *CacheHash) Len() int {
	return c.len
}
<commit_msg>basic tests for cachehash<commit_after>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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 cachehash

import "container/list"

type CacheHash struct {
	h      map[interface{}]*list.Element
	l      *list.List
	len    int
	maxLen int
}

type keyValue struct {
	Key   interface{}
	Value interface{}
}

func (c *CacheHash) Init(maxLen int) {
	c.l = list.New()
	c.l = c.l.Init()
	c.h = make(map[interface{}]*list.Element)
	c.len = 0
	c.maxLen = maxLen
}

func (c *CacheHash) Eject() {

}

func (c *CacheHash) Add(k interface{}, v interface{}) bool {
	e, ok := c.h[k]
	if ok {
		kv := e.Value.(keyValue)
		kv.Key = k
		kv.Value = v
		c.l.MoveToFront(e)
	} else {
		if c.len >= c.maxLen {
			c.Eject()
		}
		var kv keyValue
		kv.Key = k
		kv.Value = v
		e = c.l.PushFront(kv)
		c.len++
		c.h[k] = e
	}
	return ok
}

func (c *CacheHash) First() (interface{}, interface{}) {
	if c.len == 0 {
		return nil, nil
	}
	e := c.l.Front()
	kv := e.Value.(keyValue)
	return kv.Key, kv.Value
}

func (c *CacheHash) Last() (interface{}, interface{}) {
	if c.len == 0 {
		return nil, nil
	}
	e := c.l.Back()
	kv := e.Value.(keyValue)
	return kv.Key, kv.Value

}

func (c *CacheHash) Get(k interface{}) (interface{}, bool) {
	e, ok := c.h[k]
	if ok {
		c.l.MoveToFront(e)
		kv := e.Value.(keyValue)
		return kv.Value, ok
	}
	return nil, ok
}

func (c *CacheHash) GetNoMove(k interface{}) (interface{}, bool) {
	e, ok := c.h[k]
	if ok {
		return e.Value, ok
	}
	return nil, ok
}

func (c *CacheHash) Has(k interface{}) bool {
	_, ok := c.h[k]
	return ok
}

func (c *CacheHash) Delete(k interface{}) bool {
	return false
}

func (c *CacheHash) Len() int {
	return c.len
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strconv"

	api "github.com/gophergala2016/be/insightapi"
	"github.com/gophergala2016/be/tui"
	"github.com/nsf/termbox-go"
)

var (
	state        api.BlockList
	selected     int
	screenWidth  int
	screenHeight int
	screenScroll int
)

const (
	boxWidth  = 19
	boxHeight = 7
	xMargin   = 2
	yMargin   = 1
	xSpace    = 4
	ySpace    = 2
)

func tuiLatestBlocks() {
	var err error
	state, err = api.GetLatestBlocks()
	if err != nil {
		log.Fatal(err)
	}

	err = termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termbox.Close()

	selected = 1
	screenWidth, screenHeight = termbox.Size()
	screenScroll = 0

	draw()
	tuiPoll()
	termbox.Close()
	cliBlock(state.Blocks[selected-1].Hash)
	os.Exit(0)
}

func box(lines []string, x, y int, background, foreground termbox.Attribute) tui.Box {
	return tui.Box{
		Lines: lines,
		X:     xMargin + x*(boxWidth+xSpace), Y: yMargin + (y-screenScroll)*(boxHeight+ySpace),
		Width: boxWidth, Height: boxHeight,
		Background: background, Foreground: foreground,
	}
}

func horizontalLine(x, y int) tui.Box {
	line := ""
	if y%2 != 0 {
		line = line + "<"
	}
	for i := 0; i < xSpace-1; i++ {
		line = line + "─"
	}
	if y%2 == 0 {
		line = line + ">"
	}

	return tui.Box{
		Lines: []string{line},
		X:     xMargin + boxWidth + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight/2 + (ySpace+boxHeight)*(y-screenScroll),
		Width: xSpace, Height: 1,
		Foreground: termbox.ColorWhite,
	}
}

func verticalLine(x, y int) tui.Box {
	lines := []string{}
	for i := 0; i < ySpace-1; i++ {
		lines = append(lines, "│")
	}
	lines = append(lines, "V")

	return tui.Box{
		Lines: lines,
		X:     xMargin + boxWidth/2 + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight + (ySpace+boxHeight)*(y-screenScroll),
		Width: 1, Height: ySpace,
		Foreground: termbox.ColorWhite,
	}
}

func calculateFit(pad, space, boxSize, containerSize int) (boxes int) {
	for {
		if pad+boxSize*(boxes+1)+space*boxes+pad > containerSize {
			return
		}

		boxes = boxes + 1
	}
}

func calculateXFit() int {
	x := calculateFit(xMargin, xSpace, boxWidth, screenWidth)
	if x < 1 {
		x = 1
	}
	return x
}

func calculateYFit() int {
	x := calculateFit(yMargin, ySpace, boxHeight, screenHeight)
	if x < 1 {
		x = 1
	}
	return x
}

func toSnake(i int) (x, y int) {
	xBoxes := calculateXFit()

	y = i / xBoxes

	if y%2 == 0 {
		x = i % xBoxes
	} else {
		x = xBoxes - 1 - (i % xBoxes)
	}

	return
}

func blockBox(block api.BlockInfo, i int) tui.Group {
	xBoxes := calculateXFit()

	x, y := toSnake(i)

	color := termbox.ColorBlack
	if i == selected {
		color = termbox.ColorWhite
	}

	box := box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height),
			"",
			"  " + strconv.Itoa(block.Txlength) + " txs",
			"  " + strconv.Itoa(block.Size/1024) + " kb",
			"  " + block.PoolInfo.PoolName,
		},
		x, y, termbox.ColorBlue, color,
	)

	var line tui.Drawable

	if y%2 == 0 {
		if x == 0 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x-1, y)
		}
	} else {
		if x == xBoxes-1 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x, y)
		}
	}

	return tui.Group{box, line}
}

func nextBlockBox(block api.BlockInfo) tui.Box {
	return box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height+1),
			"",
			"  next",
			"  block",
		},
		0, 0, termbox.ColorRed, termbox.ColorBlack,
	)
}

func draw() {
	canvas := tui.Canvas{}

	group := tui.Group{}
	for i, block := range state.Blocks {
		if i == 0 { // draw unconfirmed block
			group = append(group, nextBlockBox(block))
		}

		group = append(group, blockBox(block, i+1))
	}

	canvas.Drawable = group
	canvas.Redraw()
}

func move(x int) {
	selected = selected + x
	if selected < 1 {
		selected = 1
	}
	if selected > len(state.Blocks) {
		selected = len(state.Blocks)
	}
	for _, y := toSnake(selected); y+1 > calculateYFit()+screenScroll; {
		screenScroll = screenScroll + 1
	}
	for _, y := toSnake(selected); y < screenScroll; {
		screenScroll = screenScroll - 1
	}
	draw()
}

func tuiPoll() {
	for {
		e := termbox.PollEvent()

		if e.Type == termbox.EventKey {
			switch e.Key {
			case termbox.KeyArrowLeft:
				move(-1)
			case termbox.KeyArrowUp:
				move(-1)
			case termbox.KeyPgup:
				move(-1)
			case termbox.KeyArrowRight:
				move(1)
			case termbox.KeyArrowDown:
				move(1)
			case termbox.KeyPgdn:
				move(1)
			case termbox.KeyEnter:
				return
			default:
				if e.Ch == 'q' {
					termbox.Close()
					os.Exit(0)
				}
			}
		}

		if e.Type == termbox.EventResize {
			screenWidth = e.Width
			screenHeight = e.Height
			draw()
			move(0)
		}
	}
}
<commit_msg>Simplify switch block<commit_after>package main

import (
	"log"
	"os"
	"strconv"

	api "github.com/gophergala2016/be/insightapi"
	"github.com/gophergala2016/be/tui"
	"github.com/nsf/termbox-go"
)

var (
	state        api.BlockList
	selected     int
	screenWidth  int
	screenHeight int
	screenScroll int
)

const (
	boxWidth  = 19
	boxHeight = 7
	xMargin   = 2
	yMargin   = 1
	xSpace    = 4
	ySpace    = 2
)

func tuiLatestBlocks() {
	var err error
	state, err = api.GetLatestBlocks()
	if err != nil {
		log.Fatal(err)
	}

	err = termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termbox.Close()

	selected = 1
	screenWidth, screenHeight = termbox.Size()
	screenScroll = 0

	draw()
	tuiPoll()
	termbox.Close()
	cliBlock(state.Blocks[selected-1].Hash)
	os.Exit(0)
}

func box(lines []string, x, y int, background, foreground termbox.Attribute) tui.Box {
	return tui.Box{
		Lines: lines,
		X:     xMargin + x*(boxWidth+xSpace), Y: yMargin + (y-screenScroll)*(boxHeight+ySpace),
		Width: boxWidth, Height: boxHeight,
		Background: background, Foreground: foreground,
	}
}

func horizontalLine(x, y int) tui.Box {
	line := ""
	if y%2 != 0 {
		line = line + "<"
	}
	for i := 0; i < xSpace-1; i++ {
		line = line + "─"
	}
	if y%2 == 0 {
		line = line + ">"
	}

	return tui.Box{
		Lines: []string{line},
		X:     xMargin + boxWidth + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight/2 + (ySpace+boxHeight)*(y-screenScroll),
		Width: xSpace, Height: 1,
		Foreground: termbox.ColorWhite,
	}
}

func verticalLine(x, y int) tui.Box {
	lines := []string{}
	for i := 0; i < ySpace-1; i++ {
		lines = append(lines, "│")
	}
	lines = append(lines, "V")

	return tui.Box{
		Lines: lines,
		X:     xMargin + boxWidth/2 + (xSpace+boxWidth)*x,
		Y:     yMargin + boxHeight + (ySpace+boxHeight)*(y-screenScroll),
		Width: 1, Height: ySpace,
		Foreground: termbox.ColorWhite,
	}
}

func calculateFit(pad, space, boxSize, containerSize int) (boxes int) {
	for {
		if pad+boxSize*(boxes+1)+space*boxes+pad > containerSize {
			return
		}

		boxes = boxes + 1
	}
}

func calculateXFit() int {
	x := calculateFit(xMargin, xSpace, boxWidth, screenWidth)
	if x < 1 {
		x = 1
	}
	return x
}

func calculateYFit() int {
	x := calculateFit(yMargin, ySpace, boxHeight, screenHeight)
	if x < 1 {
		x = 1
	}
	return x
}

func toSnake(i int) (x, y int) {
	xBoxes := calculateXFit()

	y = i / xBoxes

	if y%2 == 0 {
		x = i % xBoxes
	} else {
		x = xBoxes - 1 - (i % xBoxes)
	}

	return
}

func blockBox(block api.BlockInfo, i int) tui.Group {
	xBoxes := calculateXFit()

	x, y := toSnake(i)

	color := termbox.ColorBlack
	if i == selected {
		color = termbox.ColorWhite
	}

	box := box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height),
			"",
			"  " + strconv.Itoa(block.Txlength) + " txs",
			"  " + strconv.Itoa(block.Size/1024) + " kb",
			"  " + block.PoolInfo.PoolName,
		},
		x, y, termbox.ColorBlue, color,
	)

	var line tui.Drawable

	if y%2 == 0 {
		if x == 0 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x-1, y)
		}
	} else {
		if x == xBoxes-1 {
			line = verticalLine(x, y-1)
		} else {
			line = horizontalLine(x, y)
		}
	}

	return tui.Group{box, line}
}

func nextBlockBox(block api.BlockInfo) tui.Box {
	return box(
		[]string{
			"",
			"  #" + strconv.Itoa(block.Height+1),
			"",
			"  next",
			"  block",
		},
		0, 0, termbox.ColorRed, termbox.ColorBlack,
	)
}

func draw() {
	canvas := tui.Canvas{}

	group := tui.Group{}
	for i, block := range state.Blocks {
		if i == 0 { // draw unconfirmed block
			group = append(group, nextBlockBox(block))
		}

		group = append(group, blockBox(block, i+1))
	}

	canvas.Drawable = group
	canvas.Redraw()
}

func move(x int) {
	selected = selected + x
	if selected < 1 {
		selected = 1
	}
	if selected > len(state.Blocks) {
		selected = len(state.Blocks)
	}
	for _, y := toSnake(selected); y+1 > calculateYFit()+screenScroll; {
		screenScroll = screenScroll + 1
	}
	for _, y := toSnake(selected); y < screenScroll; {
		screenScroll = screenScroll - 1
	}
	draw()
}

func tuiPoll() {
	for {
		e := termbox.PollEvent()

		if e.Type == termbox.EventKey {
			switch e.Key {
			case termbox.KeyArrowLeft, termbox.KeyArrowUp, termbox.KeyPgup:
				move(-1)
			case termbox.KeyArrowRight, termbox.KeyArrowDown, termbox.KeyPgdn:
				move(1)
			case termbox.KeyEnter:
				return
			default:
				if e.Ch == 'q' {
					termbox.Close()
					os.Exit(0)
				}
			}
		}

		if e.Type == termbox.EventResize {
			screenWidth = e.Width
			screenHeight = e.Height
			draw()
			move(0)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
)

func handleGet(res http.ResponseWriter, req *http.Request) {
	r, _ := regexp.Compile("^data:(.*?)?(;base64)?,(.+)$")
	dataurl := req.URL.Query().Get("url")
	match := r.FindStringSubmatch(dataurl)
	if len(match) == 0 {
		log.Println("match.error.input:", dataurl)
		http.Error(res, "Parameter 'url' must be present and in RFC 2397 form", http.StatusBadRequest)
		return
	}

	contentType := match[1]
	isBase64 := match[2] != ""
	data := match[3]
	log.Println("request.type:", contentType, "request.base64:", isBase64)

	res.Header().Set("Content-Type", contentType)
	if isBase64 {
		decoded, err := base64.StdEncoding.DecodeString(data)
		if err != nil {
			log.Println("base64.decode.error:", err, "dataurl:", dataurl)
			http.Error(res, "Error decoding base64: "+err.Error(), http.StatusBadRequest)
			return
		}
		res.Write(decoded)
	} else {
		fmt.Fprintln(res, data)
	}
}

func handlePost(res http.ResponseWriter, req *http.Request) {
	scheme := "http"
	if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
		scheme = "https"
	}

	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Println("post.read.error:", err)
		http.Error(res, "Error reading request body: "+err.Error(), http.StatusBadRequest)
		return
	}

	contentType := req.Header.Get("Content-Type")
	if contentType == "" || contentType == "application/x-www-form-urlencoded" {
		contentType = http.DetectContentType(data)
	}

	base64 := base64.StdEncoding.EncodeToString(data)
	dataUrl := "data:" + contentType + ";base64," + base64
	fmt.Fprint(res, scheme+"://"+req.Host+"/?url="+url.QueryEscape(dataUrl))
}

func main() {
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		switch req.Method {
		case "GET":
			handleGet(res, req)
		case "POST":
			handlePost(res, req)
		default:
			http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
		}
	})

	log.Println("listening:true port:", os.Getenv("PORT"))
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Move dataUrlPattern outside handleGet for reuse<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
)

var dataUrlPattern *regexp.Regexp

func handleGet(res http.ResponseWriter, req *http.Request) {
	dataUrl := req.URL.Query().Get("url")
	match := dataUrlPattern.FindStringSubmatch(dataUrl)
	if len(match) == 0 {
		log.Println("match.error.input:", dataUrl)
		http.Error(res, "Parameter 'url' must be present and in RFC 2397 form", http.StatusBadRequest)
		return
	}

	contentType := match[1]
	isBase64 := match[2] != ""
	data := match[3]
	log.Println("request.type:", contentType, "request.base64:", isBase64)

	res.Header().Set("Content-Type", contentType)
	if isBase64 {
		decoded, err := base64.StdEncoding.DecodeString(data)
		if err != nil {
			log.Println("base64.decode.error:", err, "dataUrl:", dataUrl)
			http.Error(res, "Error decoding base64: "+err.Error(), http.StatusBadRequest)
			return
		}
		res.Write(decoded)
	} else {
		fmt.Fprintln(res, data)
	}
}

func handlePost(res http.ResponseWriter, req *http.Request) {
	scheme := "http"
	if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
		scheme = "https"
	}

	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Println("post.read.error:", err)
		http.Error(res, "Error reading request body: "+err.Error(), http.StatusBadRequest)
		return
	}

	contentType := req.Header.Get("Content-Type")
	if contentType == "" || contentType == "application/x-www-form-urlencoded" {
		contentType = http.DetectContentType(data)
	}

	base64 := base64.StdEncoding.EncodeToString(data)
	dataUrl := "data:" + contentType + ";base64," + base64
	fmt.Fprint(res, scheme+"://"+req.Host+"/?url="+url.QueryEscape(dataUrl))
}

func main() {
	dataUrlPattern, _ = regexp.Compile("^data:(.*?)?(;base64)?,(.+)$")

	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		switch req.Method {
		case "GET":
			handleGet(res, req)
		case "POST":
			handlePost(res, req)
		default:
			http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
		}
	})

	log.Println("listening:true port:", os.Getenv("PORT"))
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/LogvinovLeon/UberChallenge/definitions"
	"github.com/LogvinovLeon/UberChallenge/email-providers/mailgun"
	"github.com/LogvinovLeon/UberChallenge/email-providers/sendgrid"
	"log"
	"net/http"
	"os"
)

type SenderType func(*definitions.EmailSendPayload) error

func sendEmailWithFallback(payload *definitions.EmailSendPayload, primarySender, secondarySender SenderType) error {
	return primarySender(payload)
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		if r.Body == nil {
			http.Error(w, "Please send a request body", 400)
			return
		}
		var payload definitions.EmailSendPayload
		err := json.NewDecoder(r.Body).Decode(&payload)
		if err != nil {
			http.Error(w, err.Error(), 400)
			return
		}
		fmt.Println(payload)
		var e error
		if payload.PreferredProvider == "mailgun" {
			e = sendEmailWithFallback(&payload, mailgun.Send, sendgrid.Send)
		} else {
			e = sendEmailWithFallback(&payload, sendgrid.Send, mailgun.Send)
		}
		if e != nil {
			log.Println(e)
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		//w.Header().Set("Access-Control-Allow-Origin", "www.uberchallenge.email")
		fmt.Fprintf(w, "OK\n")
	}
}

func main() {
	http.HandleFunc("/email/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}
<commit_msg>Add CORS headers to all types of requests<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/LogvinovLeon/UberChallenge/definitions"
	"github.com/LogvinovLeon/UberChallenge/email-providers/mailgun"
	"github.com/LogvinovLeon/UberChallenge/email-providers/sendgrid"
	"log"
	"net/http"
	"os"
)

type SenderType func(*definitions.EmailSendPayload) error

func sendEmailWithFallback(payload *definitions.EmailSendPayload, primarySender, secondarySender SenderType) error {
	return primarySender(payload)
}

func handler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	//w.Header().Set("Access-Control-Allow-Origin", "www.uberchallenge.email")
	if r.Method == http.MethodPost {
		if r.Body == nil {
			http.Error(w, "Please send a request body", 400)
			return
		}
		var payload definitions.EmailSendPayload
		err := json.NewDecoder(r.Body).Decode(&payload)
		if err != nil {
			http.Error(w, err.Error(), 400)
			return
		}
		fmt.Println(payload)
		var e error
		if payload.PreferredProvider == "mailgun" {
			e = sendEmailWithFallback(&payload, mailgun.Send, sendgrid.Send)
		} else {
			e = sendEmailWithFallback(&payload, sendgrid.Send, mailgun.Send)
		}
		if e != nil {
			log.Println(e)
			return
		}
		fmt.Fprintf(w, "OK\n")
	}
}

func main() {
	http.HandleFunc("/email/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/go-martini/martini"
	"github.com/joshuarubin/goscribe/telapi"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/strict"
)

var (
	m       *martini.ClassicMartini
	baseURL string
)

type transcribeData struct {
	CallbackURL string `form:"callback_url" binding:"required"`
	AudioURL    string `form:"audio_url" binding:"required"`
}

func init() {
	// BASE_URL is not required or else wercker tests would fail
	baseURL = os.Getenv("BASE_URL")

	m = martini.Classic()

	m.Use(gzip.All())
	m.Use(render.Renderer())

	m.Get("/", func() string {
		return "hello, world"
	})

	m.Post(
		"/v1/transcribe",
		strict.Accept("application/json"),
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(transcribeData{}),
		handleTranscribe,
	)

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
}

func main() {
	m.Run()
}

func telapiError(r render.Render, err error) {
	if telapiError, ok := err.(telapi.Error); ok {
		r.JSON(telapiError.JSON())
		return
	}

	r.JSON(500, map[string]interface{}{
		"status": 500,
		"error":  err.Error(),
	})
}

func handleTranscribe(data transcribeData, r render.Render) {
	resp, err := telapi.TranscribeURL(data.AudioURL, data.CallbackURL)
	if err != nil {
		telapiError(r, err)
		return
	}

	r.JSON(200, resp.TranscribeClientResponse.Translate())
}
<commit_msg>add a handler for the processed text string<commit_after>package main

import (
	"encoding/json"
	"os"

	"github.com/go-martini/martini"
	"github.com/joshuarubin/goscribe/telapi"
	"github.com/kr/pretty"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/strict"
)

var (
	m       *martini.ClassicMartini
	baseURL string
)

type transcribeData struct {
	CallbackURL string `form:"callback_url" binding:"required"`
	AudioURL    string `form:"audio_url" binding:"required"`
}

type transcribeClientTelAPIData struct {
	ID                string `form:"TranscriptionSid"    json:"id"`
	Status            string `form:"TranscriptionStatus" json:"status"`
	TranscriptionText string `form:"TranscriptionText"   json:"transcription_text"`
}

type transcribeTelAPIData struct {
	transcribeClientTelAPIData
	AudioURL             string  `form:"AudioUrl"`
	Duration             float32 `form:"Duration"`
	AccountSID           string  `form:"AccountSid"`
	APIVersion           string  `form:"ApiVersion"`
	Price                float32 `form:"Price"`
	TranscriptionQuality string  `form:"TranscriptionQuality"`
}

func init() {
	// BASE_URL is not required or else wercker tests would fail
	baseURL = os.Getenv("BASE_URL")

	m = martini.Classic()

	m.Use(gzip.All())
	m.Use(render.Renderer())

	m.Get("/", func() string {
		return "hello, world"
	})

	m.Post(
		"/v1/transcribe",
		strict.Accept("application/json"),
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(transcribeData{}),
		handleTranscribe,
	)

	m.Post(
		"/v1/transcribe/process",
		strict.ContentType("application/x-www-form-urlencoded"),
		binding.Bind(transcribeTelAPIData{}),
		handleTranscribeProcess,
	)

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
}

func main() {
	m.Run()
}

func telapiError(r render.Render, err error) {
	if telapiError, ok := err.(telapi.Error); ok {
		r.JSON(telapiError.JSON())
		return
	}

	r.JSON(500, map[string]interface{}{
		"status": 500,
		"error":  err.Error(),
	})
}

func handleTranscribe(data transcribeData, r render.Render) {
	resp, err := telapi.TranscribeURL(data.AudioURL, data.CallbackURL)
	if err != nil {
		telapiError(r, err)
		return
	}

	r.JSON(200, resp.TranscribeClientResponse.Translate())
}

func handleTranscribeProcess(data transcribeTelAPIData) (int, string) {
	pretty.Println(data)
	b, _ := json.Marshal(data.transcribeClientTelAPIData)
	pretty.Println(string(b))
	return 200, ""
}
<|endoftext|>