<commit_before>package cert

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

// ParsedCert is a certificate that has been configured as trusted
type ParsedCert struct {
	Entry        *CertEntry
	Certificates []*x509.Certificate
}

func pathLogin(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "login",
		Fields:  map[string]*framework.FieldSchema{},
		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathLogin,
		},
	}
}

func (b *backend) pathLogin(
	req *logical.Request, data *framework.FieldData) (*logical.Response, error) {

	var matched *ParsedCert
	if verifyResp, resp, err := b.verifyCredentials(req); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	} else {
		matched = verifyResp
	}

	if matched == nil {
		return nil, nil
	}

	ttl := matched.Entry.TTL
	if ttl == 0 {
		ttl = b.System().DefaultLeaseTTL()
	}

	clientCerts := req.Connection.ConnState.PeerCertificates
	if len(clientCerts) == 0 {
		return logical.ErrorResponse("no client certificate found"), nil
	}
	skid := base64.StdEncoding.EncodeToString(clientCerts[0].SubjectKeyId)
	akid := base64.StdEncoding.EncodeToString(clientCerts[0].AuthorityKeyId)

	// Generate a response
	resp := &logical.Response{
		Auth: &logical.Auth{
			InternalData: map[string]interface{}{
				"subject_key_id":   skid,
				"authority_key_id": akid,
			},
			Policies:    matched.Entry.Policies,
			DisplayName: matched.Entry.DisplayName,
			Metadata: map[string]string{
				"cert_name":   matched.Entry.Name,
				"common_name": clientCerts[0].Subject.CommonName,
			},
			LeaseOptions: logical.LeaseOptions{
				Renewable: true,
				TTL:       ttl,
			},
		},
	}
	return resp, nil
}

func (b *backend) pathLoginRenew(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	config, err := b.Config(req.Storage)
	if err != nil {
		return nil, err
	}

	if !config.DisableBinding {
		var matched *ParsedCert
		if verifyResp, resp, err := b.verifyCredentials(req); err != nil {
			return nil, err
		} else if resp != nil {
			return resp, nil
		} else {
			matched = verifyResp
		}

		if matched == nil {
			return nil, nil
		}

		clientCerts := req.Connection.ConnState.PeerCertificates
		if len(clientCerts) == 0 {
			return logical.ErrorResponse("no client certificate found"), nil
		}
		skid := base64.StdEncoding.EncodeToString(clientCerts[0].SubjectKeyId)
		akid := base64.StdEncoding.EncodeToString(clientCerts[0].AuthorityKeyId)

		// Certificate should not only match a registered certificate policy.
		// Also, the identity of the certificate presented should match the identity of the certificate used during login
		if req.Auth.InternalData["subject_key_id"] != skid && req.Auth.InternalData["authority_key_id"] != akid {
			return logical.ErrorResponse("client identity during renewal not matching client identity used during login"), nil
		}

	}
	// Get the cert and use its TTL
	cert, err := b.Cert(req.Storage, req.Auth.Metadata["cert_name"])
	if err != nil {
		return nil, err
	}
	if cert == nil {
		// User no longer exists, do not renew
		return nil, nil
	}

	return framework.LeaseExtend(cert.TTL, 0, b.System())(req, d)
}

func (b *backend) verifyCredentials(req *logical.Request) (*ParsedCert, *logical.Response, error) {
	// Get the connection state
	if req.Connection == nil || req.Connection.ConnState == nil {
		return nil, logical.ErrorResponse("tls connection required"), nil
	}
	connState := req.Connection.ConnState

	// Load the trusted certificates
	roots, trusted, trustedNonCAs := b.loadTrustedCerts(req.Storage)

	// If trustedNonCAs is not empty it means that client had registered a non-CA cert
	// with the backend.
	if len(trustedNonCAs) != 0 {
		// Match the trusted chain with the policy
		return b.matchNonCAPolicy(connState.PeerCertificates[0], trustedNonCAs), nil, nil
	}

	// Validate the connection state is trusted
	trustedChains, err := validateConnState(roots, connState)
	if err != nil {
		return nil, nil, err
	}

	// If no trusted chain was found, client is not authenticated
	if len(trustedChains) == 0 {
		return nil, logical.ErrorResponse("invalid certificate or no client certificate supplied"), nil
	}

	validChain := b.checkForValidChain(req.Storage, trustedChains)
	if !validChain {
		return nil, logical.ErrorResponse(
			"no chain containing non-revoked certificates could be found for this login certificate",
		), nil
	}

	// Match the trusted chain with the policy
	return b.matchPolicy(trustedChains, trusted), nil, nil
}

// matchNonCAPolicy is used to match the client cert with the registered non-CA
// policies to establish client identity.
func (b *backend) matchNonCAPolicy(clientCert *x509.Certificate, trustedNonCAs []*ParsedCert) *ParsedCert {
	for _, trustedNonCA := range trustedNonCAs {
		tCert := trustedNonCA.Certificates[0]
		if tCert.SerialNumber.Cmp(clientCert.SerialNumber) == 0 && bytes.Equal(tCert.AuthorityKeyId, clientCert.AuthorityKeyId) {
			return trustedNonCA
		}
	}
	return nil
}

// matchPolicy is used to match the associated policy with the certificate that
// was used to establish the client identity.
func (b *backend) matchPolicy(chains [][]*x509.Certificate, trusted []*ParsedCert) *ParsedCert {
	// There is probably a better way to do this...
	for _, chain := range chains {
		for _, trust := range trusted {
			for _, tCert := range trust.Certificates {
				for _, cCert := range chain {
					if tCert.Equal(cCert) {
						return trust
					}
				}
			}
		}
	}
	return nil
}

// loadTrustedCerts is used to load all the trusted certificates from the backend
func (b *backend) loadTrustedCerts(store logical.Storage) (pool *x509.CertPool, trusted []*ParsedCert, trustedNonCAs []*ParsedCert) {
	pool = x509.NewCertPool()
	names, err := store.List("cert/")
	if err != nil {
		b.Logger().Printf("[ERR] cert: failed to list trusted certs: %v", err)
		return
	}
	for _, name := range names {
		entry, err := b.Cert(store, strings.TrimPrefix(name, "cert/"))
		if err != nil {
			b.Logger().Printf("[ERR] cert: failed to load trusted certs '%s': %v", name, err)
			continue
		}
		parsed := parsePEM([]byte(entry.Certificate))
		if len(parsed) == 0 {
			b.Logger().Printf("[ERR] cert: failed to parse certificate for '%s'", name)
			continue
		}
		if !parsed[0].IsCA {
			trustedNonCAs = append(trustedNonCAs, &ParsedCert{
				Entry:        entry,
				Certificates: parsed,
			})
		} else {
			for _, p := range parsed {
				pool.AddCert(p)
			}

			// Create a ParsedCert entry
			trusted = append(trusted, &ParsedCert{
				Entry:        entry,
				Certificates: parsed,
			})
		}
	}
	return
}

func (b *backend) checkForValidChain(store logical.Storage, chains [][]*x509.Certificate) bool {
	var badChain bool
	for _, chain := range chains {
		badChain = false
		for _, cert := range chain {
			badCRLs := b.findSerialInCRLs(cert.SerialNumber)
			if len(badCRLs) != 0 {
				badChain = true
				break
			}
		}
		if !badChain {
			return true
		}
	}
	return false
}

// parsePEM parses a PEM encoded x509 certificate
func parsePEM(raw []byte) (certs []*x509.Certificate) {
	for len(raw) > 0 {
		var block *pem.Block
		block, raw = pem.Decode(raw)
		if block == nil {
			break
		}
		if (block.Type != "CERTIFICATE" && block.Type != "TRUSTED CERTIFICATE") || len(block.Headers) != 0 {
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			continue
		}
		certs = append(certs, cert)
	}
	return
}

// validateConnState is used to validate that the TLS client is authorized
// by at trusted certificate. Most of this logic is lifted from the client
// verification logic here:  http://golang.org/src/crypto/tls/handshake_server.go
// The trusted chains are returned.
func validateConnState(roots *x509.CertPool, cs *tls.ConnectionState) ([][]*x509.Certificate, error) {
	opts := x509.VerifyOptions{
		Roots:         roots,
		Intermediates: x509.NewCertPool(),
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}

	certs := cs.PeerCertificates
	if len(certs) == 0 {
		return nil, nil
	}

	if len(certs) > 1 {
		for _, cert := range certs[1:] {
			opts.Intermediates.AddCert(cert)
		}
	}

	chains, err := certs[0].Verify(opts)
	if err != nil {
		if _, ok := err.(x509.UnknownAuthorityError); ok {
			return nil, nil
		}
		return nil, errors.New("failed to verify client's certificate: " + err.Error())
	}
	return chains, nil
}
<commit_msg>continue if non-CA policy is not found<commit_after>package cert

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

// ParsedCert is a certificate that has been configured as trusted
type ParsedCert struct {
	Entry        *CertEntry
	Certificates []*x509.Certificate
}

func pathLogin(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "login",
		Fields:  map[string]*framework.FieldSchema{},
		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathLogin,
		},
	}
}

func (b *backend) pathLogin(
	req *logical.Request, data *framework.FieldData) (*logical.Response, error) {

	var matched *ParsedCert
	if verifyResp, resp, err := b.verifyCredentials(req); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	} else {
		matched = verifyResp
	}

	if matched == nil {
		return nil, nil
	}

	ttl := matched.Entry.TTL
	if ttl == 0 {
		ttl = b.System().DefaultLeaseTTL()
	}

	clientCerts := req.Connection.ConnState.PeerCertificates
	if len(clientCerts) == 0 {
		return logical.ErrorResponse("no client certificate found"), nil
	}
	skid := base64.StdEncoding.EncodeToString(clientCerts[0].SubjectKeyId)
	akid := base64.StdEncoding.EncodeToString(clientCerts[0].AuthorityKeyId)

	// Generate a response
	resp := &logical.Response{
		Auth: &logical.Auth{
			InternalData: map[string]interface{}{
				"subject_key_id":   skid,
				"authority_key_id": akid,
			},
			Policies:    matched.Entry.Policies,
			DisplayName: matched.Entry.DisplayName,
			Metadata: map[string]string{
				"cert_name":   matched.Entry.Name,
				"common_name": clientCerts[0].Subject.CommonName,
			},
			LeaseOptions: logical.LeaseOptions{
				Renewable: true,
				TTL:       ttl,
			},
		},
	}
	return resp, nil
}

func (b *backend) pathLoginRenew(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	config, err := b.Config(req.Storage)
	if err != nil {
		return nil, err
	}

	if !config.DisableBinding {
		var matched *ParsedCert
		if verifyResp, resp, err := b.verifyCredentials(req); err != nil {
			return nil, err
		} else if resp != nil {
			return resp, nil
		} else {
			matched = verifyResp
		}

		if matched == nil {
			return nil, nil
		}

		clientCerts := req.Connection.ConnState.PeerCertificates
		if len(clientCerts) == 0 {
			return logical.ErrorResponse("no client certificate found"), nil
		}
		skid := base64.StdEncoding.EncodeToString(clientCerts[0].SubjectKeyId)
		akid := base64.StdEncoding.EncodeToString(clientCerts[0].AuthorityKeyId)

		// Certificate should not only match a registered certificate policy.
		// Also, the identity of the certificate presented should match the identity of the certificate used during login
		if req.Auth.InternalData["subject_key_id"] != skid && req.Auth.InternalData["authority_key_id"] != akid {
			return logical.ErrorResponse("client identity during renewal not matching client identity used during login"), nil
		}

	}
	// Get the cert and use its TTL
	cert, err := b.Cert(req.Storage, req.Auth.Metadata["cert_name"])
	if err != nil {
		return nil, err
	}
	if cert == nil {
		// User no longer exists, do not renew
		return nil, nil
	}

	return framework.LeaseExtend(cert.TTL, 0, b.System())(req, d)
}

func (b *backend) verifyCredentials(req *logical.Request) (*ParsedCert, *logical.Response, error) {
	// Get the connection state
	if req.Connection == nil || req.Connection.ConnState == nil {
		return nil, logical.ErrorResponse("tls connection required"), nil
	}
	connState := req.Connection.ConnState

	// Load the trusted certificates
	roots, trusted, trustedNonCAs := b.loadTrustedCerts(req.Storage)

	// If trustedNonCAs is not empty it means that client had registered a non-CA cert
	// with the backend.
	if len(trustedNonCAs) != 0 {
		policy := b.matchNonCAPolicy(connState.PeerCertificates[0], trustedNonCAs)
		if policy != nil {
			return policy, nil, nil
		}
	}

	// Validate the connection state is trusted
	trustedChains, err := validateConnState(roots, connState)
	if err != nil {
		return nil, nil, err
	}

	// If no trusted chain was found, client is not authenticated
	if len(trustedChains) == 0 {
		return nil, logical.ErrorResponse("invalid certificate or no client certificate supplied"), nil
	}

	validChain := b.checkForValidChain(req.Storage, trustedChains)
	if !validChain {
		return nil, logical.ErrorResponse(
			"no chain containing non-revoked certificates could be found for this login certificate",
		), nil
	}

	// Match the trusted chain with the policy
	return b.matchPolicy(trustedChains, trusted), nil, nil
}

// matchNonCAPolicy is used to match the client cert with the registered non-CA
// policies to establish client identity.
func (b *backend) matchNonCAPolicy(clientCert *x509.Certificate, trustedNonCAs []*ParsedCert) *ParsedCert {
	for _, trustedNonCA := range trustedNonCAs {
		tCert := trustedNonCA.Certificates[0]
		if tCert.SerialNumber.Cmp(clientCert.SerialNumber) == 0 && bytes.Equal(tCert.AuthorityKeyId, clientCert.AuthorityKeyId) {
			return trustedNonCA
		}
	}
	return nil
}

// matchPolicy is used to match the associated policy with the certificate that
// was used to establish the client identity.
func (b *backend) matchPolicy(chains [][]*x509.Certificate, trusted []*ParsedCert) *ParsedCert {
	// There is probably a better way to do this...
	for _, chain := range chains {
		for _, trust := range trusted {
			for _, tCert := range trust.Certificates {
				for _, cCert := range chain {
					if tCert.Equal(cCert) {
						return trust
					}
				}
			}
		}
	}
	return nil
}

// loadTrustedCerts is used to load all the trusted certificates from the backend
func (b *backend) loadTrustedCerts(store logical.Storage) (pool *x509.CertPool, trusted []*ParsedCert, trustedNonCAs []*ParsedCert) {
	pool = x509.NewCertPool()
	names, err := store.List("cert/")
	if err != nil {
		b.Logger().Printf("[ERR] cert: failed to list trusted certs: %v", err)
		return
	}
	for _, name := range names {
		entry, err := b.Cert(store, strings.TrimPrefix(name, "cert/"))
		if err != nil {
			b.Logger().Printf("[ERR] cert: failed to load trusted certs '%s': %v", name, err)
			continue
		}
		parsed := parsePEM([]byte(entry.Certificate))
		if len(parsed) == 0 {
			b.Logger().Printf("[ERR] cert: failed to parse certificate for '%s'", name)
			continue
		}
		if !parsed[0].IsCA {
			trustedNonCAs = append(trustedNonCAs, &ParsedCert{
				Entry:        entry,
				Certificates: parsed,
			})
		} else {
			for _, p := range parsed {
				pool.AddCert(p)
			}

			// Create a ParsedCert entry
			trusted = append(trusted, &ParsedCert{
				Entry:        entry,
				Certificates: parsed,
			})
		}
	}
	return
}

func (b *backend) checkForValidChain(store logical.Storage, chains [][]*x509.Certificate) bool {
	var badChain bool
	for _, chain := range chains {
		badChain = false
		for _, cert := range chain {
			badCRLs := b.findSerialInCRLs(cert.SerialNumber)
			if len(badCRLs) != 0 {
				badChain = true
				break
			}
		}
		if !badChain {
			return true
		}
	}
	return false
}

// parsePEM parses a PEM encoded x509 certificate
func parsePEM(raw []byte) (certs []*x509.Certificate) {
	for len(raw) > 0 {
		var block *pem.Block
		block, raw = pem.Decode(raw)
		if block == nil {
			break
		}
		if (block.Type != "CERTIFICATE" && block.Type != "TRUSTED CERTIFICATE") || len(block.Headers) != 0 {
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			continue
		}
		certs = append(certs, cert)
	}
	return
}

// validateConnState is used to validate that the TLS client is authorized
// by at trusted certificate. Most of this logic is lifted from the client
// verification logic here:  http://golang.org/src/crypto/tls/handshake_server.go
// The trusted chains are returned.
func validateConnState(roots *x509.CertPool, cs *tls.ConnectionState) ([][]*x509.Certificate, error) {
	opts := x509.VerifyOptions{
		Roots:         roots,
		Intermediates: x509.NewCertPool(),
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
	}

	certs := cs.PeerCertificates
	if len(certs) == 0 {
		return nil, nil
	}

	if len(certs) > 1 {
		for _, cert := range certs[1:] {
			opts.Intermediates.AddCert(cert)
		}
	}

	chains, err := certs[0].Verify(opts)
	if err != nil {
		if _, ok := err.(x509.UnknownAuthorityError); ok {
			return nil, nil
		}
		return nil, errors.New("failed to verify client's certificate: " + err.Error())
	}
	return chains, nil
}
<|endoftext|>


<commit_before>package mysql

import (
	"fmt"
	"log"
	"os"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/hashicorp/vault/logical"
	logicaltest "github.com/hashicorp/vault/logical/testing"
	"github.com/mitchellh/mapstructure"
	"github.com/ory-am/dockertest"
)

var (
	testImagePull sync.Once
)

func prepareTestContainer(t *testing.T, s logical.Storage, b logical.Backend) (cid dockertest.ContainerID, retURL string) {
	if os.Getenv("MYSQL_DSN") != "" {
		return "", os.Getenv("MYSQL_DSN")
	}

	// Without this the checks for whether the container has started seem to
	// never actually pass. There's really no reason to expose the test
	// containers, so don't.
	dockertest.BindDockerToLocalhost = "yep"

	testImagePull.Do(func() {
		dockertest.Pull("mysql")
	})

	cid, connErr := dockertest.ConnectToMySQL(60, 500*time.Millisecond, func(connURL string) bool {
		// This will cause a validation to run
		resp, err := b.HandleRequest(&logical.Request{
			Storage:   s,
			Operation: logical.UpdateOperation,
			Path:      "config/connection",
			Data: map[string]interface{}{
				"connection_url": connURL,
			},
		})
		if err != nil || (resp != nil && resp.IsError()) {
			// It's likely not up and running yet, so return false and try again
			return false
		}
		if resp == nil {
			t.Fatal("expected warning")
		}

		retURL = connURL
		return true
	})

	if connErr != nil {
		t.Fatalf("could not connect to database: %v", connErr)
	}

	return
}

func cleanupTestContainer(t *testing.T, cid dockertest.ContainerID) {
	err := cid.KillRemove()
	if err != nil {
		t.Fatal(err)
	}
}

func TestBackend_config_connection(t *testing.T) {
	var resp *logical.Response
	var err error
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	configData := map[string]interface{}{
		"value":                "",
		"connection_url":       "sample_connection_url",
		"max_open_connections": 9,
		"max_idle_connections": 7,
		"verify_connection":    false,
	}

	configReq := &logical.Request{
		Operation: logical.UpdateOperation,
		Path:      "config/connection",
		Storage:   config.StorageView,
		Data:      configData,
	}
	resp, err = b.HandleRequest(configReq)
	if err != nil || (resp != nil && resp.IsError()) {
		t.Fatalf("err:%s resp:%#v\n", err, resp)
	}

	configReq.Operation = logical.ReadOperation
	resp, err = b.HandleRequest(configReq)
	if err != nil || (resp != nil && resp.IsError()) {
		t.Fatalf("err:%s resp:%#v\n", err, resp)
	}

	delete(configData, "verify_connection")
	if !reflect.DeepEqual(configData, resp.Data) {
		t.Fatalf("bad: expected:%#v\nactual:%#v\n", configData, resp.Data)
	}
}

func TestBackend_basic(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	// for wildcard based mysql user
	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepRole(t, true),
			testAccStepReadCreds(t, "web"),
		},
	})
}

func TestBackend_basicHostRevoke(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	// for host based mysql user
	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepRole(t, false),
			testAccStepReadCreds(t, "web"),
		},
	})
}

func TestBackend_roleCrud(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepRole(t, false),
			testAccStepReadRole(t, "web", testRoleWildCard),
			testAccStepDeleteRole(t, "web"),
			testAccStepReadRole(t, "web", ""),
		},
	})
}

func TestBackend_leaseWriteRead(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepWriteLease(t),
			testAccStepReadLease(t),
		},
	})

}

func testAccStepConfig(t *testing.T, d map[string]interface{}, expectError bool) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "config/connection",
		Data:      d,
		ErrorOk:   true,
		Check: func(resp *logical.Response) error {
			if expectError {
				if resp.Data == nil {
					return fmt.Errorf("data is nil")
				}
				var e struct {
					Error string `mapstructure:"error"`
				}
				if err := mapstructure.Decode(resp.Data, &e); err != nil {
					return err
				}
				if len(e.Error) == 0 {
					return fmt.Errorf("expected error, but write succeeded")
				}
				return nil
			} else if resp != nil && resp.IsError() {
				return fmt.Errorf("got an error response: %v", resp.Error())
			}
			return nil
		},
	}
}

func testAccStepRole(t *testing.T, wildCard bool) logicaltest.TestStep {

	if wildCard == true {
		pathData := map[string]interface{}{
			"sql": testRoleHost,
		}
	} else {
		pathData := map[string]interface{}{
			"sql":        testRoleHost,
			"revoke_sql": testRevokeSQL,
		}
	}

	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "roles/web",
		Data:      pathData,
	}

}

func testAccStepDeleteRole(t *testing.T, n string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.DeleteOperation,
		Path:      "roles/" + n,
	}
}

func testAccStepReadCreds(t *testing.T, name string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "creds/" + name,
		Check: func(resp *logical.Response) error {
			var d struct {
				Username string `mapstructure:"username"`
				Password string `mapstructure:"password"`
			}
			if err := mapstructure.Decode(resp.Data, &d); err != nil {
				return err
			}
			log.Printf("[WARN] Generated credentials: %v", d)

			return nil
		},
	}
}

func testAccStepReadRole(t *testing.T, name string, sql string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "roles/" + name,
		Check: func(resp *logical.Response) error {
			if resp == nil {
				if sql == "" {
					return nil
				}

				return fmt.Errorf("bad: %#v", resp)
			}

			var d struct {
				SQL string `mapstructure:"sql"`
			}
			if err := mapstructure.Decode(resp.Data, &d); err != nil {
				return err
			}

			if d.SQL != sql {
				return fmt.Errorf("bad: %#v", resp)
			}

			return nil
		},
	}
}

func testAccStepWriteLease(t *testing.T) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "config/lease",
		Data: map[string]interface{}{
			"lease":     "1h5m",
			"lease_max": "24h",
		},
	}
}

func testAccStepReadLease(t *testing.T) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "config/lease",
		Check: func(resp *logical.Response) error {
			if resp.Data["lease"] != "1h5m0s" || resp.Data["lease_max"] != "24h0m0s" {
				return fmt.Errorf("bad: %#v", resp)
			}

			return nil
		},
	}
}

const testRoleWildCard = `
CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';
GRANT SELECT ON *.* TO '{{name}}'@'%';
`
const testRoleHost = `
CREATE USER '{{name}}'@'10.1.1.2' IDENTIFIED BY '{{password}}';
GRANT SELECT ON *.* TO '{{name}}'@'10.1.1.2';
`
const testRevokeSQL = `
REVOKE ALL PRIVILEGES, GRANT OPTION FROM '{{name}}'@'10.1.1.2';
DROP USER '{{name}}'@'10.1.1.2';
`
<commit_msg>fixed some more issues I had with the tests.<commit_after>package mysql

import (
	"fmt"
	"log"
	"os"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/hashicorp/vault/logical"
	logicaltest "github.com/hashicorp/vault/logical/testing"
	"github.com/mitchellh/mapstructure"
	"github.com/ory-am/dockertest"
)

var (
	testImagePull sync.Once
)

func prepareTestContainer(t *testing.T, s logical.Storage, b logical.Backend) (cid dockertest.ContainerID, retURL string) {
	if os.Getenv("MYSQL_DSN") != "" {
		return "", os.Getenv("MYSQL_DSN")
	}

	// Without this the checks for whether the container has started seem to
	// never actually pass. There's really no reason to expose the test
	// containers, so don't.
	dockertest.BindDockerToLocalhost = "yep"

	testImagePull.Do(func() {
		dockertest.Pull("mysql")
	})

	cid, connErr := dockertest.ConnectToMySQL(60, 500*time.Millisecond, func(connURL string) bool {
		// This will cause a validation to run
		resp, err := b.HandleRequest(&logical.Request{
			Storage:   s,
			Operation: logical.UpdateOperation,
			Path:      "config/connection",
			Data: map[string]interface{}{
				"connection_url": connURL,
			},
		})
		if err != nil || (resp != nil && resp.IsError()) {
			// It's likely not up and running yet, so return false and try again
			return false
		}
		if resp == nil {
			t.Fatal("expected warning")
		}

		retURL = connURL
		return true
	})

	if connErr != nil {
		t.Fatalf("could not connect to database: %v", connErr)
	}

	return
}

func cleanupTestContainer(t *testing.T, cid dockertest.ContainerID) {
	err := cid.KillRemove()
	if err != nil {
		t.Fatal(err)
	}
}

func TestBackend_config_connection(t *testing.T) {
	var resp *logical.Response
	var err error
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	configData := map[string]interface{}{
		"value":                "",
		"connection_url":       "sample_connection_url",
		"max_open_connections": 9,
		"max_idle_connections": 7,
		"verify_connection":    false,
	}

	configReq := &logical.Request{
		Operation: logical.UpdateOperation,
		Path:      "config/connection",
		Storage:   config.StorageView,
		Data:      configData,
	}
	resp, err = b.HandleRequest(configReq)
	if err != nil || (resp != nil && resp.IsError()) {
		t.Fatalf("err:%s resp:%#v\n", err, resp)
	}

	configReq.Operation = logical.ReadOperation
	resp, err = b.HandleRequest(configReq)
	if err != nil || (resp != nil && resp.IsError()) {
		t.Fatalf("err:%s resp:%#v\n", err, resp)
	}

	delete(configData, "verify_connection")
	if !reflect.DeepEqual(configData, resp.Data) {
		t.Fatalf("bad: expected:%#v\nactual:%#v\n", configData, resp.Data)
	}
}

func TestBackend_basic(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	// for wildcard based mysql user
	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepRole(t, true),
			testAccStepReadCreds(t, "web"),
		},
	})
}

func TestBackend_basicHostRevoke(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	// for host based mysql user
	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepRole(t, false),
			testAccStepReadCreds(t, "web"),
		},
	})
}

func TestBackend_roleCrud(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			// test SQL with wildcard based user
			testAccStepRole(t, true),
			testAccStepReadRole(t, "web", testRoleWildCard),
			testAccStepDeleteRole(t, "web"),
			// test SQL with host  based user
			testAccStepRole(t, false),
			testAccStepReadRole(t, "web", testRoleHost),
			testAccStepDeleteRole(t, "web"),
		},
	})
}

func TestBackend_leaseWriteRead(t *testing.T) {
	config := logical.TestBackendConfig()
	config.StorageView = &logical.InmemStorage{}
	b, err := Factory(config)
	if err != nil {
		t.Fatal(err)
	}

	cid, connURL := prepareTestContainer(t, config.StorageView, b)
	if cid != "" {
		defer cleanupTestContainer(t, cid)
	}
	connData := map[string]interface{}{
		"connection_url": connURL,
	}

	logicaltest.Test(t, logicaltest.TestCase{
		Backend: b,
		Steps: []logicaltest.TestStep{
			testAccStepConfig(t, connData, false),
			testAccStepWriteLease(t),
			testAccStepReadLease(t),
		},
	})

}

func testAccStepConfig(t *testing.T, d map[string]interface{}, expectError bool) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "config/connection",
		Data:      d,
		ErrorOk:   true,
		Check: func(resp *logical.Response) error {
			if expectError {
				if resp.Data == nil {
					return fmt.Errorf("data is nil")
				}
				var e struct {
					Error string `mapstructure:"error"`
				}
				if err := mapstructure.Decode(resp.Data, &e); err != nil {
					return err
				}
				if len(e.Error) == 0 {
					return fmt.Errorf("expected error, but write succeeded")
				}
				return nil
			} else if resp != nil && resp.IsError() {
				return fmt.Errorf("got an error response: %v", resp.Error())
			}
			return nil
		},
	}
}

func testAccStepRole(t *testing.T, wildCard bool) logicaltest.TestStep {

	pathData := make(map[string]interface{})
	if wildCard == true {
		pathData = map[string]interface{}{
			"sql": testRoleWildCard,
		}
	} else {
		pathData = map[string]interface{}{
			"sql":        testRoleHost,
			"revoke_sql": testRevokeSQL,
		}
	}

	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "roles/web",
		Data:      pathData,
	}

}

func testAccStepDeleteRole(t *testing.T, n string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.DeleteOperation,
		Path:      "roles/" + n,
	}
}

func testAccStepReadCreds(t *testing.T, name string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "creds/" + name,
		Check: func(resp *logical.Response) error {
			var d struct {
				Username string `mapstructure:"username"`
				Password string `mapstructure:"password"`
			}
			if err := mapstructure.Decode(resp.Data, &d); err != nil {
				return err
			}
			log.Printf("[WARN] Generated credentials: %v", d)

			return nil
		},
	}
}

func testAccStepReadRole(t *testing.T, name string, sql string) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "roles/" + name,
		Check: func(resp *logical.Response) error {
			if resp == nil {
				if sql == "" {
					return nil
				}

				return fmt.Errorf("bad: %#v", resp)
			}

			var d struct {
				SQL string `mapstructure:"sql"`
			}
			if err := mapstructure.Decode(resp.Data, &d); err != nil {
				return err
			}

			if d.SQL != sql {
				return fmt.Errorf("bad: %#v", resp)
			}

			return nil
		},
	}
}

func testAccStepWriteLease(t *testing.T) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.UpdateOperation,
		Path:      "config/lease",
		Data: map[string]interface{}{
			"lease":     "1h5m",
			"lease_max": "24h",
		},
	}
}

func testAccStepReadLease(t *testing.T) logicaltest.TestStep {
	return logicaltest.TestStep{
		Operation: logical.ReadOperation,
		Path:      "config/lease",
		Check: func(resp *logical.Response) error {
			if resp.Data["lease"] != "1h5m0s" || resp.Data["lease_max"] != "24h0m0s" {
				return fmt.Errorf("bad: %#v", resp)
			}

			return nil
		},
	}
}

const testRoleWildCard = `
CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';
GRANT SELECT ON *.* TO '{{name}}'@'%';
`
const testRoleHost = `
CREATE USER '{{name}}'@'10.1.1.2' IDENTIFIED BY '{{password}}';
GRANT SELECT ON *.* TO '{{name}}'@'10.1.1.2';
`
const testRevokeSQL = `
REVOKE ALL PRIVILEGES, GRANT OPTION FROM '{{name}}'@'10.1.1.2';
DROP USER '{{name}}'@'10.1.1.2';
`
<|endoftext|>


<commit_before>package edit

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"

	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/util"
)

// completer takes the current Node (always a leaf in the AST) and an Editor,
// and should returns an interval and a list of candidates, meaning that the
// text within the interval may be replaced by any of the candidates. If the
// completer is not applicable, it should return an invalid interval [-1, end).
type completer func(parse.Node, *Editor) (int, int, []*candidate)

var completers = []struct {
	name string
	completer
}{
	{"variable", complVariable},
	{"command name", complFormHead},
	{"argument", complArg},
}

func complVariable(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end := n.Begin(), n.End()

	primary, ok := n.(*parse.Primary)
	if !ok || primary.Type != parse.Variable {
		return -1, -1, nil
	}

	// XXX Repeats eval.ParseVariable.
	explode, qname := eval.ParseVariableSplice(primary.Value)
	nsPart, nameHead := eval.ParseVariableQName(qname)
	ns := nsPart
	if len(ns) > 0 {
		ns = ns[:len(ns)-1]
	}

	// Collect matching variables.
	var varnames []string
	iterateVariables(ed.evaler, ns, func(varname string) {
		if strings.HasPrefix(varname, nameHead) {
			varnames = append(varnames, nsPart+varname)
		}
	})
	// Collect namespace prefixes.
	// TODO Support non-module namespaces.
	for ns := range ed.evaler.Modules {
		if hasProperPrefix(ns+":", qname) {
			varnames = append(varnames, ns+":")
		}
	}
	sort.Strings(varnames)

	cands := make([]*candidate, len(varnames))
	// Build candidates.
	for i, varname := range varnames {
		cands[i] = &candidate{text: "$" + explode + varname}
	}
	return begin, end, cands
}

func hasProperPrefix(s, p string) bool {
	return len(s) > len(p) && strings.HasPrefix(s, p)
}

func iterateVariables(ev *eval.Evaler, ns string, f func(string)) {
	switch ns {
	case "":
		for varname := range eval.Builtin() {
			f(varname)
		}
		for varname := range ev.Global {
			f(varname)
		}
		// TODO Include local names as well.
	case "E":
		for _, s := range os.Environ() {
			f(s[:strings.IndexByte(s, '=')])
		}
	default:
		// TODO Support non-module namespaces.
		for varname := range ev.Modules[ns] {
			f(varname)
		}
	}
}

func complFormHead(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end, head, q := findFormHeadContext(n)
	if begin == -1 {
		return -1, -1, nil
	}
	cands, err := complFormHeadInner(head, ed)
	if err != nil {
		ed.Notify("%v", err)
	}
	fixCandidates(cands, q)
	return begin, end, cands
}

func findFormHeadContext(n parse.Node) (int, int, string, parse.PrimaryType) {
	_, isChunk := n.(*parse.Chunk)
	_, isPipeline := n.(*parse.Pipeline)
	if isChunk || isPipeline {
		return n.Begin(), n.End(), "", parse.Bareword
	}

	if primary, ok := n.(*parse.Primary); ok {
		if compound, head := primaryInSimpleCompound(primary); compound != nil {
			if form, ok := compound.Parent().(*parse.Form); ok {
				if form.Head == compound {
					return compound.Begin(), compound.End(), head, primary.Type
				}
			}
		}
	}
	return -1, -1, "", 0
}

func complFormHeadInner(head string, ed *Editor) ([]*candidate, error) {
	if util.DontSearch(head) {
		return complFilenameInner(head, true)
	}

	var commands []string
	got := func(s string) {
		if strings.HasPrefix(s, head) {
			commands = append(commands, s)
		}
	}
	for special := range isBuiltinSpecial {
		got(special)
	}
	explode, ns, _ := eval.ParseVariable(head)
	if !explode {
		iterateVariables(ed.evaler, ns, func(varname string) {
			if strings.HasPrefix(varname, eval.FnPrefix) {
				got(eval.MakeVariableName(false, ns, varname[len(eval.FnPrefix):]))
			} else {
				got(eval.MakeVariableName(false, ns, varname) + "=")
			}
		})
	}
	for command := range ed.isExternal {
		got(command)
		if strings.HasPrefix(head, "e:") {
			got("e:" + command)
		}
	}
	// TODO Support non-module namespaces.
	for ns := range ed.evaler.Modules {
		if head != ns+":" {
			got(ns + ":")
		}
	}
	sort.Strings(commands)

	cands := []*candidate{}
	for _, cmd := range commands {
		cands = append(cands, &candidate{text: cmd})
	}
	return cands, nil
}

func complArg(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end, current, q, form := findArgContext(n)
	if begin == -1 {
		return -1, -1, nil
	}

	// Find out head of the form and preceding arguments.
	// If Form.Head is not a simple compound, head will be "", just what we want.
	_, head, _ := simpleCompound(form.Head, nil)
	var args []string
	for _, compound := range form.Args {
		if compound.Begin() >= begin {
			break
		}
		ok, arg, _ := simpleCompound(compound, nil)
		if ok {
			// XXX Arguments that are not simple compounds are simply ignored.
			args = append(args, arg)
		}
	}

	words := make([]string, len(args)+2)
	words[0] = head
	words[len(words)-1] = current
	copy(words[1:len(words)-1], args[:])

	cands, err := completeArg(words, ed)
	if err != nil {
		ed.Notify("%v", err)
	}
	fixCandidates(cands, q)
	return begin, end, cands
}

func findArgContext(n parse.Node) (int, int, string, parse.PrimaryType, *parse.Form) {
	if sep, ok := n.(*parse.Sep); ok {
		if form, ok := sep.Parent().(*parse.Form); ok {
			return n.End(), n.End(), "", parse.Bareword, form
		}
	}
	if primary, ok := n.(*parse.Primary); ok {
		if compound, head := primaryInSimpleCompound(primary); compound != nil {
			if form, ok := compound.Parent().(*parse.Form); ok {
				if form.Head != compound {
					return compound.Begin(), compound.End(), head, primary.Type, form
				}
			}
		}
	}
	return -1, -1, "", 0, nil
}

// TODO: getStyle does redundant stats.
func complFilenameInner(head string, executableOnly bool) ([]*candidate, error) {
	dir, fileprefix := path.Split(head)
	if dir == "" {
		dir = "."
	}

	infos, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, fmt.Errorf("cannot list directory %s: %v", dir, err)
	}

	cands := []*candidate{}
	lsColor := getLsColor()
	// Make candidates out of elements that match the file component.
	for _, info := range infos {
		name := info.Name()
		// Irrevelant file.
		if !strings.HasPrefix(name, fileprefix) {
			continue
		}
		// Hide dot files unless file starts with a dot.
		if !dotfile(fileprefix) && dotfile(name) {
			continue
		}
		// Only accept searchable directories and executable files if
		// executableOnly is true.
		if executableOnly && !(info.IsDir() || (info.Mode()&0111) != 0) {
			continue
		}

		// Full filename for source and getStyle.
		full := head + name[len(fileprefix):]

		suffix := " "
		if info.IsDir() {
			suffix = "/"
		} else if info.Mode()&os.ModeSymlink != 0 {
			stat, err := os.Stat(full)
			if err == nil && stat.IsDir() {
				// Symlink to directory.
				suffix = "/"
			}
		}

		cands = append(cands, &candidate{
			text: full, suffix: suffix,
			display: styled{name, stylesFromString(lsColor.getStyle(full))},
		})
	}

	return cands, nil
}

func fixCandidates(cands []*candidate, q parse.PrimaryType) []*candidate {
	for _, cand := range cands {
		quoted, _ := parse.QuoteAs(cand.text, q)
		cand.text = quoted + cand.suffix
	}
	return cands
}

func dotfile(fname string) bool {
	return strings.HasPrefix(fname, ".")
}
<commit_msg>Don't use Editor.isExternal when completing.<commit_after>package edit

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"

	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/util"
)

// completer takes the current Node (always a leaf in the AST) and an Editor,
// and should returns an interval and a list of candidates, meaning that the
// text within the interval may be replaced by any of the candidates. If the
// completer is not applicable, it should return an invalid interval [-1, end).
type completer func(parse.Node, *Editor) (int, int, []*candidate)

var completers = []struct {
	name string
	completer
}{
	{"variable", complVariable},
	{"command name", complFormHead},
	{"argument", complArg},
}

func complVariable(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end := n.Begin(), n.End()

	primary, ok := n.(*parse.Primary)
	if !ok || primary.Type != parse.Variable {
		return -1, -1, nil
	}

	// XXX Repeats eval.ParseVariable.
	explode, qname := eval.ParseVariableSplice(primary.Value)
	nsPart, nameHead := eval.ParseVariableQName(qname)
	ns := nsPart
	if len(ns) > 0 {
		ns = ns[:len(ns)-1]
	}

	// Collect matching variables.
	var varnames []string
	iterateVariables(ed.evaler, ns, func(varname string) {
		if strings.HasPrefix(varname, nameHead) {
			varnames = append(varnames, nsPart+varname)
		}
	})
	// Collect namespace prefixes.
	// TODO Support non-module namespaces.
	for ns := range ed.evaler.Modules {
		if hasProperPrefix(ns+":", qname) {
			varnames = append(varnames, ns+":")
		}
	}
	sort.Strings(varnames)

	cands := make([]*candidate, len(varnames))
	// Build candidates.
	for i, varname := range varnames {
		cands[i] = &candidate{text: "$" + explode + varname}
	}
	return begin, end, cands
}

func hasProperPrefix(s, p string) bool {
	return len(s) > len(p) && strings.HasPrefix(s, p)
}

func iterateVariables(ev *eval.Evaler, ns string, f func(string)) {
	switch ns {
	case "":
		for varname := range eval.Builtin() {
			f(varname)
		}
		for varname := range ev.Global {
			f(varname)
		}
		// TODO Include local names as well.
	case "E":
		for _, s := range os.Environ() {
			f(s[:strings.IndexByte(s, '=')])
		}
	default:
		// TODO Support non-module namespaces.
		for varname := range ev.Modules[ns] {
			f(varname)
		}
	}
}

func complFormHead(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end, head, q := findFormHeadContext(n)
	if begin == -1 {
		return -1, -1, nil
	}
	cands, err := complFormHeadInner(head, ed)
	if err != nil {
		ed.Notify("%v", err)
	}
	fixCandidates(cands, q)
	return begin, end, cands
}

func findFormHeadContext(n parse.Node) (int, int, string, parse.PrimaryType) {
	_, isChunk := n.(*parse.Chunk)
	_, isPipeline := n.(*parse.Pipeline)
	if isChunk || isPipeline {
		return n.Begin(), n.End(), "", parse.Bareword
	}

	if primary, ok := n.(*parse.Primary); ok {
		if compound, head := primaryInSimpleCompound(primary); compound != nil {
			if form, ok := compound.Parent().(*parse.Form); ok {
				if form.Head == compound {
					return compound.Begin(), compound.End(), head, primary.Type
				}
			}
		}
	}
	return -1, -1, "", 0
}

func complFormHeadInner(head string, ed *Editor) ([]*candidate, error) {
	if util.DontSearch(head) {
		return complFilenameInner(head, true)
	}

	var commands []string
	got := func(s string) {
		if strings.HasPrefix(s, head) {
			commands = append(commands, s)
		}
	}
	for special := range isBuiltinSpecial {
		got(special)
	}
	explode, ns, _ := eval.ParseVariable(head)
	if !explode {
		iterateVariables(ed.evaler, ns, func(varname string) {
			if strings.HasPrefix(varname, eval.FnPrefix) {
				got(eval.MakeVariableName(false, ns, varname[len(eval.FnPrefix):]))
			} else {
				got(eval.MakeVariableName(false, ns, varname) + "=")
			}
		})
	}
	ed.evaler.EachExternal(func(command string) {
		got(command)
		if strings.HasPrefix(head, "e:") {
			got("e:" + command)
		}
	})
	// TODO Support non-module namespaces.
	for ns := range ed.evaler.Modules {
		if head != ns+":" {
			got(ns + ":")
		}
	}
	sort.Strings(commands)

	cands := []*candidate{}
	for _, cmd := range commands {
		cands = append(cands, &candidate{text: cmd})
	}
	return cands, nil
}

func complArg(n parse.Node, ed *Editor) (int, int, []*candidate) {
	begin, end, current, q, form := findArgContext(n)
	if begin == -1 {
		return -1, -1, nil
	}

	// Find out head of the form and preceding arguments.
	// If Form.Head is not a simple compound, head will be "", just what we want.
	_, head, _ := simpleCompound(form.Head, nil)
	var args []string
	for _, compound := range form.Args {
		if compound.Begin() >= begin {
			break
		}
		ok, arg, _ := simpleCompound(compound, nil)
		if ok {
			// XXX Arguments that are not simple compounds are simply ignored.
			args = append(args, arg)
		}
	}

	words := make([]string, len(args)+2)
	words[0] = head
	words[len(words)-1] = current
	copy(words[1:len(words)-1], args[:])

	cands, err := completeArg(words, ed)
	if err != nil {
		ed.Notify("%v", err)
	}
	fixCandidates(cands, q)
	return begin, end, cands
}

func findArgContext(n parse.Node) (int, int, string, parse.PrimaryType, *parse.Form) {
	if sep, ok := n.(*parse.Sep); ok {
		if form, ok := sep.Parent().(*parse.Form); ok {
			return n.End(), n.End(), "", parse.Bareword, form
		}
	}
	if primary, ok := n.(*parse.Primary); ok {
		if compound, head := primaryInSimpleCompound(primary); compound != nil {
			if form, ok := compound.Parent().(*parse.Form); ok {
				if form.Head != compound {
					return compound.Begin(), compound.End(), head, primary.Type, form
				}
			}
		}
	}
	return -1, -1, "", 0, nil
}

// TODO: getStyle does redundant stats.
func complFilenameInner(head string, executableOnly bool) ([]*candidate, error) {
	dir, fileprefix := path.Split(head)
	if dir == "" {
		dir = "."
	}

	infos, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, fmt.Errorf("cannot list directory %s: %v", dir, err)
	}

	cands := []*candidate{}
	lsColor := getLsColor()
	// Make candidates out of elements that match the file component.
	for _, info := range infos {
		name := info.Name()
		// Irrevelant file.
		if !strings.HasPrefix(name, fileprefix) {
			continue
		}
		// Hide dot files unless file starts with a dot.
		if !dotfile(fileprefix) && dotfile(name) {
			continue
		}
		// Only accept searchable directories and executable files if
		// executableOnly is true.
		if executableOnly && !(info.IsDir() || (info.Mode()&0111) != 0) {
			continue
		}

		// Full filename for source and getStyle.
		full := head + name[len(fileprefix):]

		suffix := " "
		if info.IsDir() {
			suffix = "/"
		} else if info.Mode()&os.ModeSymlink != 0 {
			stat, err := os.Stat(full)
			if err == nil && stat.IsDir() {
				// Symlink to directory.
				suffix = "/"
			}
		}

		cands = append(cands, &candidate{
			text: full, suffix: suffix,
			display: styled{name, stylesFromString(lsColor.getStyle(full))},
		})
	}

	return cands, nil
}

func fixCandidates(cands []*candidate, q parse.PrimaryType) []*candidate {
	for _, cand := range cands {
		quoted, _ := parse.QuoteAs(cand.text, q)
		cand.text = quoted + cand.suffix
	}
	return cands
}

func dotfile(fname string) bool {
	return strings.HasPrefix(fname, ".")
}
<|endoftext|>


<commit_before>package utils

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

// UploadFile used to upload file by S3 pre-signed URL
func UploadFile(path, url string) int {
	log.Println("Uploading app ...")
	file, err := os.Open(path)
	if err != nil {
		log.Fatal("Failed to get file for upload because of: ", err.Error())
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatal("Failed to get info about file because of: ", err.Error())
	}
	client := &http.Client{}
	request, err := http.NewRequest("PUT", url, file)
	if err != nil {
		log.Fatal("Failed to create HTTP request because of: ", err.Error())
	}
	request.Header.Add("Content-Type", "application/octet-stream")
	request.ContentLength = info.Size()
	resp, err := client.Do(request)
	if err != nil {
		log.Fatal("Failed to upload file by S3 link because of: ", err.Error())
	}
	defer resp.Body.Close()
	var result int
	result = resp.StatusCode
	log.Println("Response code:", result)
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal("Failed to get body of response because of: ", err.Error())
	}
	log.Println("Response body:", string(body))
	return result
}

// StringEndsWith check that string ends with specified substring
func StringEndsWith(original, substring string) bool {
	if len(substring) > len(original) {
		return false
	}
	str := string(original[len(original)-len(substring):])
	return str == substring
}

// GetFilename returns file name from path string
func GetFilename(path string) string {
	if !strings.Contains(path, "/") {
		return path
	}
	pos := strings.LastIndex(path, "/")
	return string(path[pos+1:])
}
<commit_msg>Optimize UploadFile method<commit_after>package utils

import (
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

// UploadFile used to upload file by S3 pre-signed URL
func UploadFile(path, url string) int {
	log.Println("Uploading app ...")
	file, info := prepareFile(path)
	client := &http.Client{}
	request, err := http.NewRequest("PUT", url, file)
	if err != nil {
		log.Fatal("Failed to create HTTP request because of: ", err.Error())
	}
	request.Header.Add("Content-Type", "application/octet-stream")
	request.ContentLength = info.Size()
	resp, err := client.Do(request)
	if err != nil {
		log.Fatal("Failed to upload file by S3 link because of: ", err.Error())
	}
	defer resp.Body.Close()
	status := saveFile(resp)
	return status
}

func prepareFile(path string) (*os.File, os.FileInfo) {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal("Failed to get file for upload because of: ", err.Error())
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatal("Failed to get info about file because of: ", err.Error())
	}
	return file, info
}

func saveFile(response http.Response) int {
	result := response.StatusCode
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatal("Failed to get body of response because of: ", err.Error())
	}
	log.Println("Response code:", result)
	log.Println("Response body:", string(body))
	return result
}

// StringEndsWith check that string ends with specified substring
func StringEndsWith(original, substring string) bool {
	if len(substring) > len(original) {
		return false
	}
	str := string(original[len(original)-len(substring):])
	return str == substring
}

// GetFilename returns file name from path string
func GetFilename(path string) string {
	if !strings.Contains(path, "/") {
		return path
	}
	pos := strings.LastIndex(path, "/")
	return string(path[pos+1:])
}
<|endoftext|>


<commit_before>package export

import "github.com/robertkrimen/otto"

func New() Export {
	return make(Export)
}

type Export map[string]func(otto.FunctionCall) otto.Value

func (e Export) Set(key string, value func(otto.FunctionCall) otto.Value) {
	e[key] = value
}
<commit_msg>Add Export.Reegister<commit_after>package export

import "github.com/robertkrimen/otto"

func New() Export {
	return make(Export)
}

type Export map[string]interface{}

func (e Export) Set(key string, value interface{}) {
	e[key] = value
}

func (e Export) Register(vm *otto.Otto) error {
	o, err := vm.Object(`({})`)
	if err != nil {
		return err
	}
	for key, value := range e {
		o.Set(key, value)
	}
	return nil
}
<|endoftext|>


<commit_before>// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or 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 utils

var capitalizedToCapitalizedWordsMap = map[string]string{
	"Dns":     "DNS",
	"Dyn":     "DYN",
	"Eip":     "EIP",
	"Keypair": "KeyPair",
	"Vxnet":   "VxNet",
}

var lowerCaseToLowercaseWordsMap = map[string]string{
	"lastest": "latest", // Fix typo
}

var lowerCaseToCapitalizedWordsMap = map[string]string{
	"acl":           "ACL",
	"cors":          "CORS",
	"cpu":           "CPU",
	"datadir":       "DataDir",
	"dhcp":          "DHCP",
	"dns":           "DNS",
	"dyn":           "DYN",
	"eip":           "EIP",
	"eips":          "EIPs",
	"http":          "HTTP",
	"icp":           "ICP",
	"id":            "ID",
	"ids":           "IDs",
	"innodb":        "InnoDB",
	"io":            "IO",
	"ip":            "IP",
	"ips":           "IPs",
	"ipset":         "IPSet",
	"ipsets":        "IPSets",
	"keypair":       "KeyPair",
	"keypairs":      "KeyPairs",
	"lastest":       "Latest", // Fix typo
	"loadbalancer":  "LoadBalancer",
	"loadbalancers": "LoadBalancers",
	"newsid":        "NewSID",
	"nic":           "NIC",
	"os":            "OS",
	"opt":           "OPT",
	"qingstor":      "QingStor",
	"qingcloud":     "QingCloud",
	"qs":            "QS",
	"rdb":           "RDB",
	"rdbs":          "RDBs",
	"sql":           "SQL",
	"tmp":           "TMP",
	"tmpdir":        "TMPDir",
	"topslave":      "TopSlave",
	"trx":           "TRX",
	"ui":            "UI",
	"uri":           "URI",
	"url":           "URL",
	"usb":           "USB",
	"vcpus":         "VCPUs",
	"vxnet":         "VxNet",
	"vxnets":        "VxNets",
}

var abbreviateWordsMap = []string{
	"ACL",
	"CORS",
	"CPU",
	"DHCP",
	"DNS",
	"DYN",
	"EIP",
	"ETag",
	"IaaS",
	"ICP",
	"ID",
	"IO",
	"IP",
	"IPSets",
	"MD5",
	"NIC",
	"OS",
	"OPT",
	"QingStor",
	"QingCloud",
	"QS",
	"RDB",
	"SQL",
	"TMP",
	"TMPDir",
	"TRX",
	"UI",
	"URL",
	"VCPUs",
	"VxNet",
}
<commit_msg>Add SSO to abbreviate words map<commit_after>// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or 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 utils

var capitalizedToCapitalizedWordsMap = map[string]string{
	"Dns":     "DNS",
	"Dyn":     "DYN",
	"Eip":     "EIP",
	"Keypair": "KeyPair",
	"Vxnet":   "VxNet",
}

var lowerCaseToLowercaseWordsMap = map[string]string{
	"lastest": "latest", // Fix typo
}

var lowerCaseToCapitalizedWordsMap = map[string]string{
	"acl":           "ACL",
	"cors":          "CORS",
	"cpu":           "CPU",
	"datadir":       "DataDir",
	"dhcp":          "DHCP",
	"dns":           "DNS",
	"dyn":           "DYN",
	"eip":           "EIP",
	"eips":          "EIPs",
	"http":          "HTTP",
	"icp":           "ICP",
	"id":            "ID",
	"ids":           "IDs",
	"innodb":        "InnoDB",
	"io":            "IO",
	"ip":            "IP",
	"ips":           "IPs",
	"ipset":         "IPSet",
	"ipsets":        "IPSets",
	"keypair":       "KeyPair",
	"keypairs":      "KeyPairs",
	"lastest":       "Latest", // Fix typo
	"loadbalancer":  "LoadBalancer",
	"loadbalancers": "LoadBalancers",
	"newsid":        "NewSID",
	"nic":           "NIC",
	"os":            "OS",
	"opt":           "OPT",
	"qingstor":      "QingStor",
	"qingcloud":     "QingCloud",
	"qs":            "QS",
	"rdb":           "RDB",
	"rdbs":          "RDBs",
	"sql":           "SQL",
	"tmp":           "TMP",
	"tmpdir":        "TMPDir",
	"topslave":      "TopSlave",
	"trx":           "TRX",
	"ui":            "UI",
	"uri":           "URI",
	"url":           "URL",
	"usb":           "USB",
	"vcpus":         "VCPUs",
	"vxnet":         "VxNet",
	"vxnets":        "VxNets",
}

var abbreviateWordsMap = []string{
	"ACL",
	"CORS",
	"CPU",
	"DHCP",
	"DNS",
	"DYN",
	"EIP",
	"ETag",
	"IaaS",
	"ICP",
	"ID",
	"IO",
	"IP",
	"IPSets",
	"MD5",
	"NIC",
	"OS",
	"OPT",
	"QingStor",
	"QingCloud",
	"QS",
	"RDB",
	"SQL",
	"SSO",
	"TMP",
	"TMPDir",
	"TRX",
	"UI",
	"URL",
	"VCPUs",
	"VxNet",
}
<|endoftext|>


<commit_before>package message

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"

	"github.com/jinzhu/gorm"
)

func Create(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	channelId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// override message type
	// all of the messages coming from client-side
	// should be marked as POST
	req.TypeConstant = models.ChannelMessage_TYPE_POST

	// set initial channel id
	req.InitialChannelId = channelId

	if err := req.Create(); err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	cml := models.NewChannelMessageList()

	// override channel id
	cml.ChannelId = channelId
	cml.MessageId = req.Id
	if err := cml.Create(); err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Delete(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	req.Id = id
	if err := req.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	err = deleteSingleMessage(req, true)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// yes it is deleted but not removed completely from our system
	return helpers.NewDeletedResponse()
}

func deleteSingleMessage(cm *models.ChannelMessage, deleteReplies bool) error {
	// first delete from all channels
	selector := map[string]interface{}{
		"message_id": cm.Id,
	}

	cml := models.NewChannelMessageList()
	if err := cml.DeleteMessagesBySelector(selector); err != nil {
		return err
	}

	// fetch interactions
	i := models.NewInteraction()
	i.MessageId = cm.Id
	interactions, err := i.FetchAll("like")
	if err != nil {
		return err
	}

	// delete interactions
	for _, interaction := range interactions {
		err := interaction.Delete()
		if err != nil {
			return err
		}
	}

	if deleteReplies {
		mr := models.NewMessageReply()
		mr.MessageId = cm.Id

		// list returns ChannelMessage
		messageReplies, err := mr.List()
		if err != nil {
			return err
		}

		// delete message replies
		for _, replyMessage := range messageReplies {
			err := deleteSingleMessage(&replyMessage, false)
			if err != nil {
				return err
			}
		}
	}

	err = models.NewMessageReply().DeleteByOrQuery(cm.Id)
	if err != nil {
		return err
	}

	// delete replyMessage itself
	err = cm.Delete()
	if err != nil {
		return err
	}
	return nil
}

func Update(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}
	req.Id = id

	body := req.Body
	if err := req.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	if req.Id == 0 {
		return helpers.NewBadRequestResponse(err)
	}

	req.Body = body
	if err := req.Update(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Get(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}
	cm := models.NewChannelMessage()
	cm.Id = id
	if err := cm.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(cm)
}

func GetWithRelated(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	cm := models.NewChannelMessage()
	cm.Id = id
	if err := cm.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	cmc, err := cm.BuildMessage(helpers.GetQuery(u))
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(cmc)
}
<commit_msg>Social: change list function to listall<commit_after>package message

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"

	"github.com/jinzhu/gorm"
)

func Create(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	channelId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// override message type
	// all of the messages coming from client-side
	// should be marked as POST
	req.TypeConstant = models.ChannelMessage_TYPE_POST

	// set initial channel id
	req.InitialChannelId = channelId

	if err := req.Create(); err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	cml := models.NewChannelMessageList()

	// override channel id
	cml.ChannelId = channelId
	cml.MessageId = req.Id
	if err := cml.Create(); err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Delete(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	req.Id = id
	if err := req.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	err = deleteSingleMessage(req, true)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// yes it is deleted but not removed completely from our system
	return helpers.NewDeletedResponse()
}

func deleteSingleMessage(cm *models.ChannelMessage, deleteReplies bool) error {
	// first delete from all channels
	selector := map[string]interface{}{
		"message_id": cm.Id,
	}

	cml := models.NewChannelMessageList()
	if err := cml.DeleteMessagesBySelector(selector); err != nil {
		return err
	}

	// fetch interactions
	i := models.NewInteraction()
	i.MessageId = cm.Id
	interactions, err := i.FetchAll("like")
	if err != nil {
		return err
	}

	// delete interactions
	for _, interaction := range interactions {
		err := interaction.Delete()
		if err != nil {
			return err
		}
	}

	if deleteReplies {
		mr := models.NewMessageReply()
		mr.MessageId = cm.Id

		// list returns ChannelMessage
		messageReplies, err := mr.ListAll()
		if err != nil {
			return err
		}

		// delete message replies
		for _, replyMessage := range messageReplies {
			err := deleteSingleMessage(&replyMessage, false)
			if err != nil {
				return err
			}
		}
	}

	err = models.NewMessageReply().DeleteByOrQuery(cm.Id)
	if err != nil {
		return err
	}

	// delete replyMessage itself
	err = cm.Delete()
	if err != nil {
		return err
	}
	return nil
}

func Update(u *url.URL, h http.Header, req *models.ChannelMessage) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}
	req.Id = id

	body := req.Body
	if err := req.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	if req.Id == 0 {
		return helpers.NewBadRequestResponse(err)
	}

	req.Body = body
	if err := req.Update(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Get(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}
	cm := models.NewChannelMessage()
	cm.Id = id
	if err := cm.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(cm)
}

func GetWithRelated(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	id, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	cm := models.NewChannelMessage()
	cm.Id = id
	if err := cm.Fetch(); err != nil {
		if err == gorm.RecordNotFound {
			return helpers.NewNotFoundResponse()
		}
		return helpers.NewBadRequestResponse(err)
	}

	cmc, err := cm.BuildMessage(helpers.GetQuery(u))
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(cmc)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type actDownloadTemplateVM struct {
	SourceURL  string `cli:"type=opt short=s long=source default='http://192.168.1.10/vbox' desc='location of the template to download'"`
	Template   string `cli:"type=arg required=true desc='The name of the template to load (try ubuntu_precise_template.ova)'"`
	Identifier string `cli:"type=arg required=true desc='Identifier of the template VM'"`
}

func (action *actDownloadTemplateVM) Run() error {
	return downloadTemplateVM(action.SourceURL, action.Template, action.Identifier)
}

type actCloneVM struct {
	Snapshot string `cli:"type=opt short=s long=snapshot default='base' desc='The template VM\'s snapshot to use for cloning.'"`
	Template string `cli:"type=arg required=true desc='The VM to use for cloning.'"`
	Name     string `cli:"type=arg required=true desc='Name of the new VM'"`
}

func (action *actCloneVM) Run() error {
	return cloneVM(action.Name, action.Template, action.Snapshot)
}

type actListVMs struct {
	Running bool `cli:"type=opt short=r long=running desc='Show running VMs only.'"`
}

func (action *actListVMs) Run() (e error) {
	var vms []*vbox
	if action.Running {
		vms, e = listRunningVMs()
	} else {
		vms, e = listAllVMs()
	}
	if e != nil {
		return e
	}

	for _, vm := range vms {
		r := ""
		if vm.status == "running" {
			r = "*"
		}
		log.Printf("%s%s", vm.name, r)
	}
	return nil
}

type vmBase struct {
	Name   string `cli:"type=arg required=true desc='Name of the VM'"`
	Action string
}

func (action *vmBase) Run() (e error) {
	switch action.Action {
	case "props":
		return listVMProps(action.Name)
	case "stop":
		return stopVM(action.Name)
	case "shutdown":
		return shutdownVM(action.Name)
	case "save":
		return saveVM(action.Name)
	case "delete":
		return deleteVM(action.Name)
	case "info":
		return showVMInfo(action.Name)
	}
	return nil
}

func listVMProps(vm string) (e error) {
	var props map[string]string
	if props, e = getVMProperties(vm); e != nil {
		return e
	}

	for k, v := range props {
		if !strings.HasPrefix(k, "/VirtualBox/GuestInfo") {
			continue
		}
		log.Printf("%s%-*s%q", k, 50-len(k), "", v)
	}
	return nil
}

func showVMInfo(name string) (e error) {
	vm := &vbox{name: name}
	if e = vmInfos(vm); e != nil {
		return e
	}
	log.Printf("VM %q", name)
	log.Printf("cpus:          %d", vm.cpus)
	log.Printf("memory:        %d MB", vm.memory)
	log.Printf("boot order:    %s", strings.Join(vm.bootOrder[:], ","))
	for _, nic := range vm.nics {
		networkName := ""
		if nic.ntype == "hostonly" {
			networkName = " [->" + nic.name + "]"
		}
		log.Printf("nic [%d]:       %s %s%s", nic.id, nic.ntype, nic.mac, networkName)
	}
	for k, v := range vm.sfolders {
		log.Printf("shared folder: %s [->%s]", v, k)
	}
	return nil
}

type actStartVM struct {
	vmBase
	WithGUI bool `cli:"type=opt short=g long=gui desc='Show the GUI of the virtual machine?'"`
}

func (action *actStartVM) Run() (e error) {
	return startVM(action.Name, action.WithGUI)
}

type sshInto struct {
	vmBase

	User    string `cli:"type=opt short=l long=login default=ubuntu desc='User used to log in to the VM.'"`
	IFace   int    `cli:"type=opt short=i long=interface default=0 desc='Number of the nic to connect to.'"`
	Timeout int    `cli:"type=opt short=t long=timeout default=15 desc='Time to wait for machine to boot.'"`
}

func (action *sshInto) Run() error {
	ip, e := getIP(action.Name, action.IFace, action.Timeout)
	if e != nil {
		return e
	}

	log.Printf("connecting to machine %q using ip %q", action.Name, ip)

	cmd := exec.Command("ssh", "-l", action.User, ip)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

type actShareFolder struct {
	vmBase

	LocalPath  string `cli:"arg required desc='Absolute path of the folder shared with the guest.'"`
	RemoteName string `cli:"arg required desc='Remote name of the path (mounted in /media).'"`
}

func (action *actShareFolder) Run() (e error) {
	path := action.LocalPath
	if !filepath.IsAbs(path) {
		if path, e = filepath.Abs(path); e != nil {
			return e
		}
	}

	return shareFolder(action.Name, action.RemoteName, path)
}

type actUnshareFolder struct {
	vmBase

	RemoteName string `cli:"arg required desc='Remote name of the path (mounted in /media).'"`
}

func (action *actUnshareFolder) Run() error {
	return unshareFolder(action.Name, action.RemoteName)
}

type actConfigMemVM struct {
	vmBase

	Memory int `cli:"arg required desc='The amount of memory the VM has in MB.'"`
}

func (action *actConfigMemVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	vm.memory = action.Memory

	return configureVM(vm)
}

type actConfigCPUsVM struct {
	vmBase

	CPUs int `cli:"arg required desc='The amount of CPUs the VM has.'"`
}

func (action *actConfigCPUsVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	vm.cpus = action.CPUs

	return configureVM(vm)
}

type actConfigBootOrderVM struct {
	vmBase

	Devices []string `cli:"arg required desc='Ordered list of boot devices (at most 4 of floppy, disk, dvd, and net)'"`
}

func (action *actConfigBootOrderVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	for i := 0; i < 4; i++ {
		if i < len(action.Devices) {
			vm.bootOrder[i] = action.Devices[i]
		} else {
			vm.bootOrder[i] = "none"
		}
	}

	return configureVM(vm)
}

type actConfigNetworkIFacesVM struct {
	vmBase

	Id      int    `cli:"arg required desc='Network interface to configure.'"`
	NType   string `cli:"arg required desc='Type of NIC (one of none, bridged, nat, and hostonly).'"`
	Network string `cli:"arg desc='Network name (required for hostonly).'"`
}

func (action *actConfigNetworkIFacesVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	if action.Id >= 8 {
		return fmt.Errorf("Only 8 nics supported!")
	}

	var nic *vnet
	for i := range vm.nics {
		if vm.nics[i].id == action.Id {
			nic = vm.nics[i]
		}
	}

	if nic == nil {
		nic = &vnet{}
		vm.nics = append(vm.nics, nic)
	}

	nic.ntype = action.NType
	if action.NType == "hostonly" {
		if action.Network == "" {
			return fmt.Errorf("No name for the hostonly network specified!")
		}
		nic.name = action.Network
	}

	return configureVM(vm)
}
<commit_msg>fixed bug with configuration of nics<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type actDownloadTemplateVM struct {
	SourceURL  string `cli:"type=opt short=s long=source default='http://192.168.1.10/vbox' desc='location of the template to download'"`
	Template   string `cli:"type=arg required=true desc='The name of the template to load (try ubuntu_precise_template.ova)'"`
	Identifier string `cli:"type=arg required=true desc='Identifier of the template VM'"`
}

func (action *actDownloadTemplateVM) Run() error {
	return downloadTemplateVM(action.SourceURL, action.Template, action.Identifier)
}

type actCloneVM struct {
	Snapshot string `cli:"type=opt short=s long=snapshot default='base' desc='The template VM\'s snapshot to use for cloning.'"`
	Template string `cli:"type=arg required=true desc='The VM to use for cloning.'"`
	Name     string `cli:"type=arg required=true desc='Name of the new VM'"`
}

func (action *actCloneVM) Run() error {
	return cloneVM(action.Name, action.Template, action.Snapshot)
}

type actListVMs struct {
	Running bool `cli:"type=opt short=r long=running desc='Show running VMs only.'"`
}

func (action *actListVMs) Run() (e error) {
	var vms []*vbox
	if action.Running {
		vms, e = listRunningVMs()
	} else {
		vms, e = listAllVMs()
	}
	if e != nil {
		return e
	}

	for _, vm := range vms {
		r := ""
		if vm.status == "running" {
			r = "*"
		}
		log.Printf("%s%s", vm.name, r)
	}
	return nil
}

type vmBase struct {
	Name   string `cli:"type=arg required=true desc='Name of the VM'"`
	Action string
}

func (action *vmBase) Run() (e error) {
	switch action.Action {
	case "props":
		return listVMProps(action.Name)
	case "stop":
		return stopVM(action.Name)
	case "shutdown":
		return shutdownVM(action.Name)
	case "save":
		return saveVM(action.Name)
	case "delete":
		return deleteVM(action.Name)
	case "info":
		return showVMInfo(action.Name)
	}
	return nil
}

func listVMProps(vm string) (e error) {
	var props map[string]string
	if props, e = getVMProperties(vm); e != nil {
		return e
	}

	for k, v := range props {
		if !strings.HasPrefix(k, "/VirtualBox/GuestInfo") {
			continue
		}
		log.Printf("%s%-*s%q", k, 50-len(k), "", v)
	}
	return nil
}

func showVMInfo(name string) (e error) {
	vm := &vbox{name: name}
	if e = vmInfos(vm); e != nil {
		return e
	}
	log.Printf("VM %q", name)
	log.Printf("cpus:          %d", vm.cpus)
	log.Printf("memory:        %d MB", vm.memory)
	log.Printf("boot order:    %s", strings.Join(vm.bootOrder[:], ","))
	for _, nic := range vm.nics {
		networkName := ""
		if nic.ntype == "hostonly" {
			networkName = " [->" + nic.name + "]"
		}
		log.Printf("nic [%d]:       %s %s%s", nic.id, nic.ntype, nic.mac, networkName)
	}
	for k, v := range vm.sfolders {
		log.Printf("shared folder: %s [->%s]", v, k)
	}
	return nil
}

type actStartVM struct {
	vmBase
	WithGUI bool `cli:"type=opt short=g long=gui desc='Show the GUI of the virtual machine?'"`
}

func (action *actStartVM) Run() (e error) {
	return startVM(action.Name, action.WithGUI)
}

type sshInto struct {
	vmBase

	User    string `cli:"type=opt short=l long=login default=ubuntu desc='User used to log in to the VM.'"`
	IFace   int    `cli:"type=opt short=i long=interface default=0 desc='Number of the nic to connect to.'"`
	Timeout int    `cli:"type=opt short=t long=timeout default=15 desc='Time to wait for machine to boot.'"`
}

func (action *sshInto) Run() error {
	ip, e := getIP(action.Name, action.IFace, action.Timeout)
	if e != nil {
		return e
	}

	log.Printf("connecting to machine %q using ip %q", action.Name, ip)

	cmd := exec.Command("ssh", "-l", action.User, ip)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

type actShareFolder struct {
	vmBase

	LocalPath  string `cli:"arg required desc='Absolute path of the folder shared with the guest.'"`
	RemoteName string `cli:"arg required desc='Remote name of the path (mounted in /media).'"`
}

func (action *actShareFolder) Run() (e error) {
	path := action.LocalPath
	if !filepath.IsAbs(path) {
		if path, e = filepath.Abs(path); e != nil {
			return e
		}
	}

	return shareFolder(action.Name, action.RemoteName, path)
}

type actUnshareFolder struct {
	vmBase

	RemoteName string `cli:"arg required desc='Remote name of the path (mounted in /media).'"`
}

func (action *actUnshareFolder) Run() error {
	return unshareFolder(action.Name, action.RemoteName)
}

type actConfigMemVM struct {
	vmBase

	Memory int `cli:"arg required desc='The amount of memory the VM has in MB.'"`
}

func (action *actConfigMemVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	vm.memory = action.Memory

	return configureVM(vm)
}

type actConfigCPUsVM struct {
	vmBase

	CPUs int `cli:"arg required desc='The amount of CPUs the VM has.'"`
}

func (action *actConfigCPUsVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	vm.cpus = action.CPUs

	return configureVM(vm)
}

type actConfigBootOrderVM struct {
	vmBase

	Devices []string `cli:"arg required desc='Ordered list of boot devices (at most 4 of floppy, disk, dvd, and net)'"`
}

func (action *actConfigBootOrderVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	for i := 0; i < 4; i++ {
		if i < len(action.Devices) {
			vm.bootOrder[i] = action.Devices[i]
		} else {
			vm.bootOrder[i] = "none"
		}
	}

	return configureVM(vm)
}

type actConfigNetworkIFacesVM struct {
	vmBase

	Id      int    `cli:"arg required desc='Network interface to configure.'"`
	NType   string `cli:"arg required desc='Type of NIC (one of none, bridged, nat, and hostonly).'"`
	Network string `cli:"arg desc='Network name (required for hostonly).'"`
}

func (action *actConfigNetworkIFacesVM) Run() (e error) {
	vm := &vbox{name: action.Name}
	if e = vmInfos(vm); e != nil {
		return e
	}

	if action.Id >= 8 {
		return fmt.Errorf("Only 8 nics supported!")
	}

	var nic *vnet
	for i := range vm.nics {
		if vm.nics[i].id == action.Id {
			nic = vm.nics[i]
		}
	}

	if nic == nil {
		nic = &vnet{id: action.Id}
		vm.nics = append(vm.nics, nic)
	}

	nic.ntype = action.NType
	if action.NType == "hostonly" {
		if action.Network == "" {
			return fmt.Errorf("No name for the hostonly network specified!")
		}
		nic.name = action.Network
	}

	return configureVM(vm)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"io"

	"github.com/unixpickle/essentials"
	"github.com/unixpickle/muniverse"

	"gopkg.in/mgo.v2/bson"
)

// Response is a message sent from the API back-end to an
// API front-end in response to a Call.
type Response struct {
	ID string `bson:"ID"`

	Error *string `bson:"Error,omitempty"`

	Spec        *muniverse.EnvSpec `bson:"Spec,omitempty"`
	UID         *string            `bson:"UID,omitempty"`
	StepResult  *StepResult        `bson:"StepResult,omitempty"`
	Observation *Observation       `bson:"Observation,omitempty"`
}

// ErrorResponse creates a *Response with an error.
func ErrorResponse(e error) *Response {
	errMsg := e.Error()
	return &Response{Error: &errMsg}
}

// WriteResponse encodes a response to an output stream.
func WriteResponse(w io.Writer, r *Response) error {
	return essentials.AddCtx("write response", writeObject(w, r))
}

func writeObject(w io.Writer, obj interface{}) error {
	data, err := bson.Marshal(obj)
	if err != nil {
		return err
	}
	size := uint32(len(data))
	if err := binary.Write(w, binary.LittleEndian, size); err != nil {
		return err
	}
	_, err = w.Write(data)
	return err
}

type StepResult struct {
	Reward float64
	Done   bool
}

type Observation struct {
	Width  int
	Height int
	RGB    []byte
}
<commit_msg>added more missing BSON annotations<commit_after>package main

import (
	"encoding/binary"
	"io"

	"github.com/unixpickle/essentials"
	"github.com/unixpickle/muniverse"

	"gopkg.in/mgo.v2/bson"
)

// Response is a message sent from the API back-end to an
// API front-end in response to a Call.
type Response struct {
	ID string `bson:"ID"`

	Error *string `bson:"Error,omitempty"`

	Spec        *muniverse.EnvSpec `bson:"Spec,omitempty"`
	UID         *string            `bson:"UID,omitempty"`
	StepResult  *StepResult        `bson:"StepResult,omitempty"`
	Observation *Observation       `bson:"Observation,omitempty"`
}

// ErrorResponse creates a *Response with an error.
func ErrorResponse(e error) *Response {
	errMsg := e.Error()
	return &Response{Error: &errMsg}
}

// WriteResponse encodes a response to an output stream.
func WriteResponse(w io.Writer, r *Response) error {
	return essentials.AddCtx("write response", writeObject(w, r))
}

func writeObject(w io.Writer, obj interface{}) error {
	data, err := bson.Marshal(obj)
	if err != nil {
		return err
	}
	size := uint32(len(data))
	if err := binary.Write(w, binary.LittleEndian, size); err != nil {
		return err
	}
	_, err = w.Write(data)
	return err
}

type StepResult struct {
	Reward float64 `bson:"Reward"`
	Done   bool    `bson:"Done"`
}

type Observation struct {
	Width  int    `bson:"Width"`
	Height int    `bson:"Height"`
	RGB    []byte `bson:"RGB"`
}
<|endoftext|>


<commit_before>package forecast

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

// URL example:  "https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.forecast.io/forecast"
)

type Flags struct {
	DarkSkyUnavailable string
	DarkSkyStations    []string
	DataPointStations  []string
	ISDStations        []string
	LAMPStations       []string
	METARStations      []string
	METNOLicense       string
	Sources            []string
	Units              string
}

type DataPoint struct {
	Time                   float64
	Summary                string
	Icon                   string
	SunriseTime            float64
	SunsetTime             float64
	PrecipIntensity        float64
	PrecipIntensityMax     float64
	PrecipIntensityMaxTime float64
	PrecipProbability      float64
	PrecipType             string
	PrecipAccumulation     float64
	Temperature            float64
	TemperatureMin         float64
	TemperatureMinTime     float64
	TemperatureMax         float64
	TemperatureMaxTime     float64
	DewPoint               float64
	WindSpeed              float64
	WindBearing            float64
	CloudCover             float64
	Humidity               float64
	Pressure               float64
	Visibility             float64
	Ozone                  float64
}

type DataBlock struct {
	Summary string
	Icon    string
	Data    []DataPoint
}

type alert struct {
	Title   string
	Expires float64
	URI     string
}

type Forecast struct {
	Latitude  float64
	Longitude float64
	Timezone  string
	Offset    float64
	Currently DataPoint
	Minutely  DataBlock
	Hourly    DataBlock
	Daily     DataBlock
	Alerts    []alert
	Flags     Flags
}

func Get(key string, lat string, long string, time string) *Forecast {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=ca"
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=ca"
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // susceptible to man-in-the-middle
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get(url)

	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var f Forecast
	err = json.Unmarshal(body, &f)
	if err != nil {
		log.Fatal(err)
	}

	return &f
}<commit_msg>fmt not used<commit_after>package forecast

import (
	"crypto/tls"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
)

// URL example:  "https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.forecast.io/forecast"
)

type Flags struct {
	DarkSkyUnavailable string
	DarkSkyStations    []string
	DataPointStations  []string
	ISDStations        []string
	LAMPStations       []string
	METARStations      []string
	METNOLicense       string
	Sources            []string
	Units              string
}

type DataPoint struct {
	Time                   float64
	Summary                string
	Icon                   string
	SunriseTime            float64
	SunsetTime             float64
	PrecipIntensity        float64
	PrecipIntensityMax     float64
	PrecipIntensityMaxTime float64
	PrecipProbability      float64
	PrecipType             string
	PrecipAccumulation     float64
	Temperature            float64
	TemperatureMin         float64
	TemperatureMinTime     float64
	TemperatureMax         float64
	TemperatureMaxTime     float64
	DewPoint               float64
	WindSpeed              float64
	WindBearing            float64
	CloudCover             float64
	Humidity               float64
	Pressure               float64
	Visibility             float64
	Ozone                  float64
}

type DataBlock struct {
	Summary string
	Icon    string
	Data    []DataPoint
}

type alert struct {
	Title   string
	Expires float64
	URI     string
}

type Forecast struct {
	Latitude  float64
	Longitude float64
	Timezone  string
	Offset    float64
	Currently DataPoint
	Minutely  DataBlock
	Hourly    DataBlock
	Daily     DataBlock
	Alerts    []alert
	Flags     Flags
}

func Get(key string, lat string, long string, time string) *Forecast {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=ca"
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=ca"
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // susceptible to man-in-the-middle
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get(url)

	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	var f Forecast
	err = json.Unmarshal(body, &f)
	if err != nil {
		log.Fatal(err)
	}

	return &f
}<|endoftext|>


<commit_before>package leveldb

import (
	"fmt"
	//"log"

	"github.com/syndtr/goleveldb/leveldb"
)

func HandleError(err error, place string){
	if err != nil {
        //log.Fatal(place)
        //log.Fatal(err)
        fmt.Println(place, err)
    }
}

func OpenDB(db_path string) (db *leveldb.DB, err error) {
	fmt.Println("Creating leveldb db...")
	db, err = leveldb.OpenFile(db_path, nil)
	return db, err

}

func CloseDB(db *leveldb.DB) {
	db.Close()	//Use defer
}

func InsertBFTX(key string, value string, db *leveldb.DB) (error){
	//return err
	return db.Put([]byte(key), []byte(value), nil)
}

func Iterate(db *leveldb.DB) (n int, err error){
	iter := db.NewIterator(nil, nil)
	n = 0
	for iter.Next() {
	    /*key := iter.Key()
	    value := iter.Value()
		fmt.Println("\nKey: "+string(key)+"\nValue: "+string(value)+"\n")*/
		n+=1
	}
	iter.Release()
	return n, iter.Error()
}<commit_msg>Modify a message and add message for testing<commit_after>package leveldb

import (
	"fmt"
	//"log"

	"github.com/syndtr/goleveldb/leveldb"
)

func HandleError(err error, place string){
	if err != nil {
        //log.Fatal(place)
        //log.Fatal(err)
        fmt.Println(place, err)
    }
}

func OpenDB(db_path string) (db *leveldb.DB, err error) {
	fmt.Println("Creating / Opening leveldb db...")
	db, err = leveldb.OpenFile(db_path, nil)
	return db, err

}

func CloseDB(db *leveldb.DB) {
	db.Close()	//Use defer
}

func InsertBFTX(key string, value string, db *leveldb.DB) (error){
	//return err
	//fmt.Println("key", key)
	return db.Put([]byte(key), []byte(value), nil)
}

func Iterate(db *leveldb.DB) (n int, err error){
	iter := db.NewIterator(nil, nil)
	n = 0
	for iter.Next() {
	    /*key := iter.Key()
	    value := iter.Value()
		fmt.Println("\nKey: "+string(key)+"\nValue: "+string(value)+"\n")*/
		n+=1
	}
	iter.Release()
	return n, iter.Error()
}<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package remind

import (
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"strings"
	"time"
)

type Module struct {
	TimeLimit int `json:"time_limit"`
	UserLimit int `json:"user_limit"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "remind"
}

func (m *Module) Help() string {
	return "USAGE: !remind DURATION MSG"
}

func (m *Module) Defaults() {
	m.TimeLimit = 10
	m.UserLimit = 3
}

func (m *Module) Load(client *irc.Client) error {
	users := make(map[string]int)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		splited := strings.Fields(msg.Data)
		if len(splited) < 3 || splited[0] != "!remind" {
			return nil
		}

		duration, err := time.ParseDuration(splited[1])
		if err != nil {
			return err
		}

		limit := time.Duration(m.TimeLimit) * time.Hour
		if duration > limit {
			return c.Write("NOTICE %s :%v hours exceeds the limit of %v hours",
				msg.Receiver, duration.Hours(), limit.Hours())
		}

		if users[msg.Sender.Host] >= m.UserLimit {
			return c.Write("NOTICE %s :You can only run %d reminders at a time",
				msg.Receiver, m.UserLimit)
		}

		users[msg.Sender.Host]++
		reminder := strings.Join(splited[2:], " ")
		time.AfterFunc(duration, func() {
			users[msg.Sender.Host]--
			c.Write("PRIVMSG %s :Reminder: %s",
				msg.Sender.Name, reminder)
		})

		return c.Write("NOTICE %s :Reminder setup for %s",
			msg.Receiver, duration.String())
	})

	return nil
}
<commit_msg>remind: write parse error to channel<commit_after>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package remind

import (
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"strings"
	"time"
)

type Module struct {
	TimeLimit int `json:"time_limit"`
	UserLimit int `json:"user_limit"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "remind"
}

func (m *Module) Help() string {
	return "USAGE: !remind DURATION MSG"
}

func (m *Module) Defaults() {
	m.TimeLimit = 10
	m.UserLimit = 3
}

func (m *Module) Load(client *irc.Client) error {
	users := make(map[string]int)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		splited := strings.Fields(msg.Data)
		if len(splited) < 3 || splited[0] != "!remind" {
			return nil
		}

		duration, err := time.ParseDuration(splited[1])
		if err != nil {
			return c.Write("NOTICE %s :ERROR: %s", msg.Receiver, err.Error())
		}

		limit := time.Duration(m.TimeLimit) * time.Hour
		if duration > limit {
			return c.Write("NOTICE %s :%v hours exceeds the limit of %v hours",
				msg.Receiver, duration.Hours(), limit.Hours())
		}

		if users[msg.Sender.Host] >= m.UserLimit {
			return c.Write("NOTICE %s :You can only run %d reminders at a time",
				msg.Receiver, m.UserLimit)
		}

		users[msg.Sender.Host]++
		reminder := strings.Join(splited[2:], " ")
		time.AfterFunc(duration, func() {
			users[msg.Sender.Host]--
			c.Write("PRIVMSG %s :Reminder: %s",
				msg.Sender.Name, reminder)
		})

		return c.Write("NOTICE %s :Reminder setup for %s",
			msg.Receiver, duration.String())
	})

	return nil
}
<|endoftext|>