<commit_before>// +build go1.8

package pq

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"io"
	"io/ioutil"
)

// Implement the "QueryerContext" interface
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}
	finish := cn.watchCancel(ctx)
	r, err := cn.query(query, list)
	if err != nil {
		if finish != nil {
			finish()
		}
		return nil, err
	}
	r.finish = finish
	return r, nil
}

// Implement the "ExecerContext" interface
func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}

	if finish := cn.watchCancel(ctx); finish != nil {
		defer finish()
	}

	return cn.Exec(query, list)
}

// Implement the "ConnPrepareContext" interface
func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
	if finish := cn.watchCancel(ctx); finish != nil {
		defer finish()
	}
	return cn.Prepare(query)
}

// Implement the "ConnBeginTx" interface
func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
	var mode string

	switch sql.IsolationLevel(opts.Isolation) {
	case sql.LevelDefault:
		// Don't touch mode: use the server's default
	case sql.LevelReadUncommitted:
		mode = " ISOLATION LEVEL READ UNCOMMITTED"
	case sql.LevelReadCommitted:
		mode = " ISOLATION LEVEL READ COMMITTED"
	case sql.LevelRepeatableRead:
		mode = " ISOLATION LEVEL REPEATABLE READ"
	case sql.LevelSerializable:
		mode = " ISOLATION LEVEL SERIALIZABLE"
	default:
		return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
	}

	if opts.ReadOnly {
		mode += " READ ONLY"
	} else {
		mode += " READ WRITE"
	}

	tx, err := cn.begin(mode)
	if err != nil {
		return nil, err
	}
	cn.txnFinish = cn.watchCancel(ctx)
	return tx, nil
}

func (cn *conn) watchCancel(ctx context.Context) func() {
	if done := ctx.Done(); done != nil {
		finished := make(chan struct{})
		go func() {
			select {
			case <-done:
				_ = cn.cancel()
				finished <- struct{}{}
			case <-finished:
			}
		}()
		return func() {
			select {
			case <-finished:
			case finished <- struct{}{}:
			}
		}
	}
	return nil
}

func (cn *conn) cancel() error {
	c, err := dial(cn.dialer, cn.opts)
	if err != nil {
		return err
	}
	defer c.Close()

	{
		can := conn{
			c: c,
		}
		err = can.ssl(cn.opts)
		if err != nil {
			return err
		}

		w := can.writeBuf(0)
		w.int32(80877102) // cancel request code
		w.int32(cn.processID)
		w.int32(cn.secretKey)

		if err := can.sendStartupPacket(w); err != nil {
			return err
		}
	}

	// Read until EOF to ensure that the server received the cancel.
	{
		_, err := io.Copy(ioutil.Discard, c)
		return err
	}
}

// Implement the "StmtQueryContext" interface
func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}
	finish := st.watchCancel(ctx)
	r, err := st.query(list)
	if err != nil {
		if finish != nil {
			finish()
		}
		return nil, err
	}
	r.finish = finish
	return r, nil
}

// Implement the "StmtExecContext" interface
func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}

	if finish := st.watchCancel(ctx); finish != nil {
		defer finish()
	}

	return st.Exec(list)
}

func (st *stmt) watchCancel(ctx context.Context) func() {
	if done := ctx.Done(); done != nil {
		finished := make(chan struct{})
		go func() {
			select {
			case <-done:
				_ = st.cancel()
				finished <- struct{}{}
			case <-finished:
			}
		}()
		return func() {
			select {
			case <-finished:
			case finished <- struct{}{}:
			}
		}
	}
	return nil
}

func (st *stmt) cancel() error {
	return st.cn.cancel()
}<commit_msg>fix formatting<commit_after>// +build go1.8

package pq

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"io"
	"io/ioutil"
)

// Implement the "QueryerContext" interface
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}
	finish := cn.watchCancel(ctx)
	r, err := cn.query(query, list)
	if err != nil {
		if finish != nil {
			finish()
		}
		return nil, err
	}
	r.finish = finish
	return r, nil
}

// Implement the "ExecerContext" interface
func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}

	if finish := cn.watchCancel(ctx); finish != nil {
		defer finish()
	}

	return cn.Exec(query, list)
}

// Implement the "ConnPrepareContext" interface
func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
	if finish := cn.watchCancel(ctx); finish != nil {
		defer finish()
	}
	return cn.Prepare(query)
}

// Implement the "ConnBeginTx" interface
func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
	var mode string

	switch sql.IsolationLevel(opts.Isolation) {
	case sql.LevelDefault:
		// Don't touch mode: use the server's default
	case sql.LevelReadUncommitted:
		mode = " ISOLATION LEVEL READ UNCOMMITTED"
	case sql.LevelReadCommitted:
		mode = " ISOLATION LEVEL READ COMMITTED"
	case sql.LevelRepeatableRead:
		mode = " ISOLATION LEVEL REPEATABLE READ"
	case sql.LevelSerializable:
		mode = " ISOLATION LEVEL SERIALIZABLE"
	default:
		return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
	}

	if opts.ReadOnly {
		mode += " READ ONLY"
	} else {
		mode += " READ WRITE"
	}

	tx, err := cn.begin(mode)
	if err != nil {
		return nil, err
	}
	cn.txnFinish = cn.watchCancel(ctx)
	return tx, nil
}

func (cn *conn) watchCancel(ctx context.Context) func() {
	if done := ctx.Done(); done != nil {
		finished := make(chan struct{})
		go func() {
			select {
			case <-done:
				_ = cn.cancel()
				finished <- struct{}{}
			case <-finished:
			}
		}()
		return func() {
			select {
			case <-finished:
			case finished <- struct{}{}:
			}
		}
	}
	return nil
}

func (cn *conn) cancel() error {
	c, err := dial(cn.dialer, cn.opts)
	if err != nil {
		return err
	}
	defer c.Close()

	{
		can := conn{
			c: c,
		}
		err = can.ssl(cn.opts)
		if err != nil {
			return err
		}

		w := can.writeBuf(0)
		w.int32(80877102) // cancel request code
		w.int32(cn.processID)
		w.int32(cn.secretKey)

		if err := can.sendStartupPacket(w); err != nil {
			return err
		}
	}

	// Read until EOF to ensure that the server received the cancel.
	{
		_, err := io.Copy(ioutil.Discard, c)
		return err
	}
}

// Implement the "StmtQueryContext" interface
func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}
	finish := st.watchCancel(ctx)
	r, err := st.query(list)
	if err != nil {
		if finish != nil {
			finish()
		}
		return nil, err
	}
	r.finish = finish
	return r, nil
}

// Implement the "StmtExecContext" interface
func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
	list := make([]driver.Value, len(args))
	for i, nv := range args {
		list[i] = nv.Value
	}

	if finish := st.watchCancel(ctx); finish != nil {
		defer finish()
	}

	return st.Exec(list)
}

func (st *stmt) watchCancel(ctx context.Context) func() {
	if done := ctx.Done(); done != nil {
		finished := make(chan struct{})
		go func() {
			select {
			case <-done:
				_ = st.cancel()
				finished <- struct{}{}
			case <-finished:
			}
		}()
		return func() {
			select {
			case <-finished:
			case finished <- struct{}{}:
			}
		}
	}
	return nil
}

func (st *stmt) cancel() error {
	return st.cn.cancel()
}
<|endoftext|>


<commit_before>package ergo

const (
	IN_PATH = iota
	IN_QUERY
	IN_HEADER
	IN_BODY

	METHOD_ANY    = ""
	METHOD_GET    = "GET"
	METHOD_POST   = "POST"
	METHOD_PUT    = "PUT"
	METHOD_DELETE = "DELETE"

	SCHEME_HTTP  = "http"
	SCHEME_HTTPS = "https"

	MIME_XML  = "application/xml"
	MIME_JSON = "application/json"

)
<commit_msg>Param types constants<commit_after>package ergo

const (
	PARAM_STRING = iota
	PARAM_INT
	PARAM_INT64
	PARAM_FLOAT
	PARAM_FLOAT64
	PARAM_BOOL

	IN_PATH = iota
	IN_QUERY
	IN_HEADER
	IN_BODY

	METHOD_ANY    = ""
	METHOD_GET    = "GET"
	METHOD_POST   = "POST"
	METHOD_PUT    = "PUT"
	METHOD_DELETE = "DELETE"

	SCHEME_HTTP  = "http"
	SCHEME_HTTPS = "https"

	MIME_XML  = "application/xml"
	MIME_JSON = "application/json"

)
<|endoftext|>


<commit_before>/*
Package contextio provides a simple way to sign API requests for http://Context.IO.

The simplest usage is to use DoJSON() to return a json byte array that you can use elsewhere in your code.
For more advanced usage, you can use Do() and parse through the http.Response struct yourself. It is not
specific to an API version, so you can use it to make any request you would make through http://console.Context.IO.
*/
package contextio

import (
	"bytes"
	"flag"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/garyburd/go-oauth/oauth"
)

const (
	defaultMaxMemory = 32 << 21 // 64 MB
)

// ContextIO is a struct containing the authentication information and a pointer to the oauth client
type ContextIO struct {
	key    string
	secret string
	client *oauth.Client
}

// NewContextIO returns a ContextIO struct based on your CIO User and Secret
func NewContextIO(key, secret string) *ContextIO {
	c := &oauth.Client{
		Credentials: oauth.Credentials{
			Token:  key,
			Secret: secret,
		},
	}

	return &ContextIO{
		key:    key,
		secret: secret,
		client: c,
	}
}

var apiHost = flag.String("apiHost", "api.context.io", "Use a specific host for the API")

// NewRequest generates a request and signs it
func (c *ContextIO) NewRequest(method, q string, queryParams url.Values, body io.Reader) (req *http.Request, err error) {
	// make sure q has a slash in front of it
	if q[0:1] != "/" {
		q = "/" + q
	}

	query := *apiHost + q
	if len(queryParams) > 0 {
		query = query + "?" + queryParams.Encode()
	}
	req, err = http.NewRequest(method, "https://"+query, body)
	if err != nil {
		return nil, err
	}
	req.URL.Opaque = q
	req.Header.Set("User-Agent", "GoContextIO Simple Library v. 0.1")

	v := url.Values{}
	switch method {
	case "PUT", "POST", "DELETE":
		// need form data here if uploading
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		var b []byte
		b, err = ioutil.ReadAll(body)
		if err != nil {
			return nil, err
		}
		v, err = url.ParseQuery(string(b))
		if err != nil {
			return
		}
	}

	err = c.client.SetAuthorizationHeader(req.Header, nil, req.Method, req.URL, v)
	if err != nil {
		return
	}
	return req, nil
}

// AttachFile will create a file upload in the request, assumes NewRequest has already been called
func (c *ContextIO) AttachFile(req *http.Request, fieldName, fileName string) error {
	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(fieldName, filepath.Base(fileName))
	if err != nil {
		return err
	}
	_, err = io.Copy(part, f)

	// transfer the existing post vals into the new body
	for key, valSlice := range req.PostForm {
		for _, val := range valSlice {
			err = writer.WriteField(key, val)
			if err != nil {
				return err
			}
		}
	}
	err = writer.Close()
	if err != nil {
		return err
	}
	rc := ioutil.NopCloser(body)
	req.Body = rc
	// update the form
	req.ParseMultipartForm(defaultMaxMemory)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return nil
}

// Do signs the request and returns an *http.Response. The body is a standard response.Body
// and must have defer response.Body.close().  Does not support uploads, use NewRequest and AttachFile for that.
// This is 2 legged authentication, and will not currently work with 3 legged authentication.
func (c *ContextIO) Do(method, q string, params url.Values, body *string) (response *http.Response, err error) {
	req, err := c.NewRequest(method, q, params, bytes.NewBufferString(*body))
	if err != nil {
		return nil, err
	}
	return http.DefaultClient.Do(req)
}

// DoJSON passes the request to Do and then returns the json in a []byte array
func (c *ContextIO) DoJSON(method, q string, params url.Values, body *string) (json []byte, err error) {
	response, err := c.Do(method, q, params, body)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	json, err = ioutil.ReadAll(response.Body)
	return json, err
}
<commit_msg>allow for nil body<commit_after>/*
Package contextio provides a simple way to sign API requests for http://Context.IO.

The simplest usage is to use DoJSON() to return a json byte array that you can use elsewhere in your code.
For more advanced usage, you can use Do() and parse through the http.Response struct yourself. It is not
specific to an API version, so you can use it to make any request you would make through http://console.Context.IO.
*/
package contextio

import (
	"bytes"
	"flag"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/garyburd/go-oauth/oauth"
)

const (
	defaultMaxMemory = 32 << 21 // 64 MB
)

// ContextIO is a struct containing the authentication information and a pointer to the oauth client
type ContextIO struct {
	key    string
	secret string
	client *oauth.Client
}

// NewContextIO returns a ContextIO struct based on your CIO User and Secret
func NewContextIO(key, secret string) *ContextIO {
	c := &oauth.Client{
		Credentials: oauth.Credentials{
			Token:  key,
			Secret: secret,
		},
	}

	return &ContextIO{
		key:    key,
		secret: secret,
		client: c,
	}
}

var apiHost = flag.String("apiHost", "api.context.io", "Use a specific host for the API")

// NewRequest generates a request and signs it
func (c *ContextIO) NewRequest(method, q string, queryParams url.Values, body io.Reader) (req *http.Request, err error) {
	// make sure q has a slash in front of it
	if q[0:1] != "/" {
		q = "/" + q
	}

	query := *apiHost + q
	if len(queryParams) > 0 {
		query = query + "?" + queryParams.Encode()
	}
	req, err = http.NewRequest(method, "https://"+query, body)
	if err != nil {
		return nil, err
	}
	req.URL.Opaque = q
	req.Header.Set("User-Agent", "GoContextIO Simple Library v. 0.1")

	v := url.Values{}
	switch method {
	case "PUT", "POST", "DELETE":
		// need form data here if uploading
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		var b []byte
		if body != nil {
			b, err = ioutil.ReadAll(body)
		} else {
			b = []byte{}
		}
		if err != nil {
			return nil, err
		}
		v, err = url.ParseQuery(string(b))
		if err != nil {
			return
		}
	}

	err = c.client.SetAuthorizationHeader(req.Header, nil, req.Method, req.URL, v)
	if err != nil {
		return
	}
	return req, nil
}

// AttachFile will create a file upload in the request, assumes NewRequest has already been called
func (c *ContextIO) AttachFile(req *http.Request, fieldName, fileName string) error {
	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(fieldName, filepath.Base(fileName))
	if err != nil {
		return err
	}
	_, err = io.Copy(part, f)

	// transfer the existing post vals into the new body
	for key, valSlice := range req.PostForm {
		for _, val := range valSlice {
			err = writer.WriteField(key, val)
			if err != nil {
				return err
			}
		}
	}
	err = writer.Close()
	if err != nil {
		return err
	}
	rc := ioutil.NopCloser(body)
	req.Body = rc
	// update the form
	req.ParseMultipartForm(defaultMaxMemory)
	req.Header.Set("Content-Type", writer.FormDataContentType())
	return nil
}

// Do signs the request and returns an *http.Response. The body is a standard response.Body
// and must have defer response.Body.close().  Does not support uploads, use NewRequest and AttachFile for that.
// This is 2 legged authentication, and will not currently work with 3 legged authentication.
func (c *ContextIO) Do(method, q string, params url.Values, body *string) (response *http.Response, err error) {
	req, err := c.NewRequest(method, q, params, bytes.NewBufferString(*body))
	if err != nil {
		return nil, err
	}
	return http.DefaultClient.Do(req)
}

// DoJSON passes the request to Do and then returns the json in a []byte array
func (c *ContextIO) DoJSON(method, q string, params url.Values, body *string) (json []byte, err error) {
	response, err := c.Do(method, q, params, body)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	json, err = ioutil.ReadAll(response.Body)
	return json, err
}
<|endoftext|>


<commit_before>// +build coprocess

package main

import (
	"encoding/json"
	"strings"
	"unicode/utf8"

	"github.com/Sirupsen/logrus"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/coprocess"

	"errors"
	"io/ioutil"
	"net/http"
)

var (
	// EnableCoProcess will be overridden by config.Global().EnableCoProcess.
	EnableCoProcess = false

	// GlobalDispatcher will be implemented by the current CoProcess driver.
	GlobalDispatcher coprocess.Dispatcher
)

// CoProcessMiddleware is the basic CP middleware struct.
type CoProcessMiddleware struct {
	BaseMiddleware
	HookType         coprocess.HookType
	HookName         string
	MiddlewareDriver apidef.MiddlewareDriver
}

func (mw *CoProcessMiddleware) Name() string {
	return "CoProcessMiddleware"
}

// CreateCoProcessMiddleware initializes a new CP middleware, takes hook type (pre, post, etc.), hook name ("my_hook") and driver ("python").
func CreateCoProcessMiddleware(hookName string, hookType coprocess.HookType, mwDriver apidef.MiddlewareDriver, baseMid BaseMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		BaseMiddleware:   baseMid,
		HookType:         hookType,
		HookName:         hookName,
		MiddlewareDriver: mwDriver,
	}

	return createMiddleware(dMiddleware)
}

func doCoprocessReload() {
	if GlobalDispatcher != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Reloading middlewares")
		GlobalDispatcher.Reload()
	}

}

// CoProcessor represents a CoProcess during the request.
type CoProcessor struct {
	HookType   coprocess.HookType
	Middleware *CoProcessMiddleware
}

// ObjectFromRequest constructs a CoProcessObject from a given http.Request.
func (c *CoProcessor) ObjectFromRequest(r *http.Request) *coprocess.Object {
	headers := ProtoMap(r.Header)

	host := r.Host
	if host == "" && r.URL != nil {
		host = r.URL.Host
	}
	if host != "" {
		headers["Host"] = host
	}

	miniRequestObject := &coprocess.MiniRequestObject{
		Headers:        headers,
		SetHeaders:     map[string]string{},
		DeleteHeaders:  []string{},
		Url:            r.URL.Path,
		Params:         ProtoMap(r.URL.Query()),
		AddParams:      map[string]string{},
		ExtendedParams: ProtoMap(nil),
		DeleteParams:   []string{},
		ReturnOverrides: &coprocess.ReturnOverrides{
			ResponseCode: -1,
		},
		Method:     r.Method,
		RequestUri: r.RequestURI,
		Scheme:     r.URL.Scheme,
	}

	if r.Body != nil {
		defer r.Body.Close()
		miniRequestObject.RawBody, _ = ioutil.ReadAll(r.Body)
		if utf8.Valid(miniRequestObject.RawBody) {
			miniRequestObject.Body = string(miniRequestObject.RawBody)
		}
	}

	object := &coprocess.Object{
		Request:  miniRequestObject,
		HookName: c.Middleware.HookName,
	}

	// If a middleware is set, take its HookType, otherwise override it with CoProcessor.HookType
	if c.Middleware != nil && c.HookType == 0 {
		c.HookType = c.Middleware.HookType
	}

	object.HookType = c.HookType

	object.Spec = make(map[string]string)

	// Append spec data:
	if c.Middleware != nil {
		configDataAsJson := []byte("{}")
		if len(c.Middleware.Spec.ConfigData) > 0 {
			configDataAsJson, _ = json.Marshal(c.Middleware.Spec.ConfigData)
		}

		object.Spec = map[string]string{
			"OrgID":       c.Middleware.Spec.OrgID,
			"APIID":       c.Middleware.Spec.APIID,
			"config_data": string(configDataAsJson),
		}
	}

	// Encode the session object (if not a pre-process & not a custom key check):
	if c.HookType != coprocess.HookType_Pre && c.HookType != coprocess.HookType_CustomKeyCheck {
		if session := ctxGetSession(r); session != nil {
			object.Session = ProtoSessionState(session)
			// For compatibility purposes:
			object.Metadata = object.Session.Metadata
		}
	}

	return object
}

// ObjectPostProcess does CoProcessObject post-processing (adding/removing headers or params, etc.).
func (c *CoProcessor) ObjectPostProcess(object *coprocess.Object, r *http.Request) {
	r.ContentLength = int64(len(object.Request.Body))
	r.Body = ioutil.NopCloser(strings.NewReader(object.Request.Body))

	for _, dh := range object.Request.DeleteHeaders {
		r.Header.Del(dh)
	}

	for h, v := range object.Request.SetHeaders {
		r.Header.Set(h, v)
	}

	values := r.URL.Query()
	for _, k := range object.Request.DeleteParams {
		values.Del(k)
	}

	for p, v := range object.Request.AddParams {
		values.Set(p, v)
	}

	r.URL.Path = object.Request.Url
	r.URL.RawQuery = values.Encode()
}

// CoProcessInit creates a new CoProcessDispatcher, it will be called when Tyk starts.
func CoProcessInit() error {
	if runningTests && GlobalDispatcher != nil {
		return nil
	}
	var err error
	if config.Global().CoProcessOptions.EnableCoProcess {
		GlobalDispatcher, err = NewCoProcessDispatcher()
		EnableCoProcess = true
	}
	return err
}

// EnabledForSpec checks if this middleware should be enabled for a given API.
func (m *CoProcessMiddleware) EnabledForSpec() bool {
	// This flag is true when Tyk has been compiled with CP support and when the configuration enables it.
	enableCoProcess := config.Global().CoProcessOptions.EnableCoProcess && EnableCoProcess
	// This flag indicates if the current spec specifies any CP custom middleware.
	var usesCoProcessMiddleware bool

	supportedDrivers := []apidef.MiddlewareDriver{apidef.PythonDriver, apidef.LuaDriver, apidef.GrpcDriver}

	for _, driver := range supportedDrivers {
		if m.Spec.CustomMiddleware.Driver == driver && CoProcessName == driver {
			usesCoProcessMiddleware = true
			break
		}
	}

	if usesCoProcessMiddleware && enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Debug("Enabling CP middleware.")
		return true
	}

	if usesCoProcessMiddleware && !enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("Your API specifies a CP custom middleware, either Tyk wasn't build with CP support or CP is not enabled in your Tyk configuration file!")
	}

	if !usesCoProcessMiddleware && m.Spec.CustomMiddleware.Driver != "" {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("CP Driver not supported: ", m.Spec.CustomMiddleware.Driver)
	}

	return false
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	logger := m.Logger()

	logger.Debug("CoProcess Request, HookType: ", m.HookType)

	if !EnableCoProcess {
		return nil, 200
	}

	var extractor IdExtractor
	if m.Spec.EnableCoProcessAuth && m.Spec.CustomMiddleware.IdExtractor.Extractor != nil {
		extractor = m.Spec.CustomMiddleware.IdExtractor.Extractor.(IdExtractor)
	}

	var returnOverrides ReturnOverrides
	var sessionID string

	if m.HookType == coprocess.HookType_CustomKeyCheck && extractor != nil {
		sessionID, returnOverrides = extractor.ExtractAndCheck(r)

		if returnOverrides.ResponseCode != 0 {
			if returnOverrides.ResponseError == "" {
				return nil, returnOverrides.ResponseCode
			}
			err := errors.New(returnOverrides.ResponseError)
			return err, returnOverrides.ResponseCode
		}
	}

	// It's also possible to override the HookType:
	coProcessor := CoProcessor{
		Middleware: m,
		// HookType: coprocess.PreHook,
	}

	object := coProcessor.ObjectFromRequest(r)

	returnObject, err := coProcessor.Dispatch(object)
	if err != nil {
		logger.WithError(err).Error("Dispatch error")
		if m.HookType == coprocess.HookType_CustomKeyCheck {
			return errors.New("Key not authorised"), 403
		} else {
			return errors.New("Middleware error"), 500
		}
	}

	coProcessor.ObjectPostProcess(returnObject, r)

	var token string
	if returnObject.Session != nil {
		// For compatibility purposes, inject coprocess.Object.Metadata fields:
		if returnObject.Metadata != nil {
			if returnObject.Session.Metadata == nil {
				returnObject.Session.Metadata = make(map[string]string)
			}
			for k, v := range returnObject.Metadata {
				returnObject.Session.Metadata[k] = v
			}
		}

		token = returnObject.Session.Metadata["token"]
	}

	// The CP middleware indicates this is a bad auth:
	if returnObject.Request.ReturnOverrides.ResponseCode > 400 {
		logger.WithField("key", obfuscateKey(token)).Info("Attempted access with invalid key")

		// Fire Authfailed Event
		AuthFailed(m, r, token)

		// Report in health check
		reportHealthValue(m.Spec, KeyFailure, "1")

		errorMsg := "Key not authorised"
		if returnObject.Request.ReturnOverrides.ResponseError != "" {
			errorMsg = returnObject.Request.ReturnOverrides.ResponseError
		}

		return errors.New(errorMsg), int(returnObject.Request.ReturnOverrides.ResponseCode)
	}

	if returnObject.Request.ReturnOverrides.ResponseCode > 0 {
		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}
		w.WriteHeader(int(returnObject.Request.ReturnOverrides.ResponseCode))
		w.Write([]byte(returnObject.Request.ReturnOverrides.ResponseError))
		return nil, mwStatusRespond
	}

	// Is this a CP authentication middleware?
	if m.Spec.EnableCoProcessAuth && m.HookType == coprocess.HookType_CustomKeyCheck {
		// The CP middleware didn't setup a session:
		if returnObject.Session == nil || token == "" {
			authHeaderValue := r.Header.Get(m.Spec.Auth.AuthHeaderName)
			AuthFailed(m, r, authHeaderValue)
			return errors.New("Key not authorised"), 403
		}

		returnedSession := TykSessionState(returnObject.Session)

		// If the returned object contains metadata, add them to the session:
		for k, v := range returnObject.Metadata {
			returnedSession.MetaData[k] = string(v)
		}

		if extractor == nil {
			ctxSetSession(r, returnedSession, token, true)
		} else {
			ctxSetSession(r, returnedSession, sessionID, true)
		}
	}

	return nil, 200
}
<commit_msg>coprocess: use raw_body when re-building the request object (#1911)<commit_after>// +build coprocess

package main

import (
	"bytes"
	"encoding/json"
	"unicode/utf8"

	"github.com/Sirupsen/logrus"

	"github.com/TykTechnologies/tyk/apidef"
	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/coprocess"

	"errors"
	"io/ioutil"
	"net/http"
)

var (
	// EnableCoProcess will be overridden by config.Global().EnableCoProcess.
	EnableCoProcess = false

	// GlobalDispatcher will be implemented by the current CoProcess driver.
	GlobalDispatcher coprocess.Dispatcher
)

// CoProcessMiddleware is the basic CP middleware struct.
type CoProcessMiddleware struct {
	BaseMiddleware
	HookType         coprocess.HookType
	HookName         string
	MiddlewareDriver apidef.MiddlewareDriver
}

func (mw *CoProcessMiddleware) Name() string {
	return "CoProcessMiddleware"
}

// CreateCoProcessMiddleware initializes a new CP middleware, takes hook type (pre, post, etc.), hook name ("my_hook") and driver ("python").
func CreateCoProcessMiddleware(hookName string, hookType coprocess.HookType, mwDriver apidef.MiddlewareDriver, baseMid BaseMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		BaseMiddleware:   baseMid,
		HookType:         hookType,
		HookName:         hookName,
		MiddlewareDriver: mwDriver,
	}

	return createMiddleware(dMiddleware)
}

func doCoprocessReload() {
	if GlobalDispatcher != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Reloading middlewares")
		GlobalDispatcher.Reload()
	}

}

// CoProcessor represents a CoProcess during the request.
type CoProcessor struct {
	HookType   coprocess.HookType
	Middleware *CoProcessMiddleware
}

// ObjectFromRequest constructs a CoProcessObject from a given http.Request.
func (c *CoProcessor) ObjectFromRequest(r *http.Request) *coprocess.Object {
	headers := ProtoMap(r.Header)

	host := r.Host
	if host == "" && r.URL != nil {
		host = r.URL.Host
	}
	if host != "" {
		headers["Host"] = host
	}

	miniRequestObject := &coprocess.MiniRequestObject{
		Headers:        headers,
		SetHeaders:     map[string]string{},
		DeleteHeaders:  []string{},
		Url:            r.URL.Path,
		Params:         ProtoMap(r.URL.Query()),
		AddParams:      map[string]string{},
		ExtendedParams: ProtoMap(nil),
		DeleteParams:   []string{},
		ReturnOverrides: &coprocess.ReturnOverrides{
			ResponseCode: -1,
		},
		Method:     r.Method,
		RequestUri: r.RequestURI,
		Scheme:     r.URL.Scheme,
	}

	if r.Body != nil {
		defer r.Body.Close()
		miniRequestObject.RawBody, _ = ioutil.ReadAll(r.Body)
		if utf8.Valid(miniRequestObject.RawBody) {
			miniRequestObject.Body = string(miniRequestObject.RawBody)
		}
	}

	object := &coprocess.Object{
		Request:  miniRequestObject,
		HookName: c.Middleware.HookName,
	}

	// If a middleware is set, take its HookType, otherwise override it with CoProcessor.HookType
	if c.Middleware != nil && c.HookType == 0 {
		c.HookType = c.Middleware.HookType
	}

	object.HookType = c.HookType

	object.Spec = make(map[string]string)

	// Append spec data:
	if c.Middleware != nil {
		configDataAsJson := []byte("{}")
		if len(c.Middleware.Spec.ConfigData) > 0 {
			configDataAsJson, _ = json.Marshal(c.Middleware.Spec.ConfigData)
		}

		object.Spec = map[string]string{
			"OrgID":       c.Middleware.Spec.OrgID,
			"APIID":       c.Middleware.Spec.APIID,
			"config_data": string(configDataAsJson),
		}
	}

	// Encode the session object (if not a pre-process & not a custom key check):
	if c.HookType != coprocess.HookType_Pre && c.HookType != coprocess.HookType_CustomKeyCheck {
		if session := ctxGetSession(r); session != nil {
			object.Session = ProtoSessionState(session)
			// For compatibility purposes:
			object.Metadata = object.Session.Metadata
		}
	}

	return object
}

// ObjectPostProcess does CoProcessObject post-processing (adding/removing headers or params, etc.).
func (c *CoProcessor) ObjectPostProcess(object *coprocess.Object, r *http.Request) {
	r.ContentLength = int64(len(object.Request.RawBody))
	r.Body = ioutil.NopCloser(bytes.NewReader(object.Request.RawBody))

	for _, dh := range object.Request.DeleteHeaders {
		r.Header.Del(dh)
	}

	for h, v := range object.Request.SetHeaders {
		r.Header.Set(h, v)
	}

	values := r.URL.Query()
	for _, k := range object.Request.DeleteParams {
		values.Del(k)
	}

	for p, v := range object.Request.AddParams {
		values.Set(p, v)
	}

	r.URL.Path = object.Request.Url
	r.URL.RawQuery = values.Encode()
}

// CoProcessInit creates a new CoProcessDispatcher, it will be called when Tyk starts.
func CoProcessInit() error {
	if runningTests && GlobalDispatcher != nil {
		return nil
	}
	var err error
	if config.Global().CoProcessOptions.EnableCoProcess {
		GlobalDispatcher, err = NewCoProcessDispatcher()
		EnableCoProcess = true
	}
	return err
}

// EnabledForSpec checks if this middleware should be enabled for a given API.
func (m *CoProcessMiddleware) EnabledForSpec() bool {
	// This flag is true when Tyk has been compiled with CP support and when the configuration enables it.
	enableCoProcess := config.Global().CoProcessOptions.EnableCoProcess && EnableCoProcess
	// This flag indicates if the current spec specifies any CP custom middleware.
	var usesCoProcessMiddleware bool

	supportedDrivers := []apidef.MiddlewareDriver{apidef.PythonDriver, apidef.LuaDriver, apidef.GrpcDriver}

	for _, driver := range supportedDrivers {
		if m.Spec.CustomMiddleware.Driver == driver && CoProcessName == driver {
			usesCoProcessMiddleware = true
			break
		}
	}

	if usesCoProcessMiddleware && enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Debug("Enabling CP middleware.")
		return true
	}

	if usesCoProcessMiddleware && !enableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("Your API specifies a CP custom middleware, either Tyk wasn't build with CP support or CP is not enabled in your Tyk configuration file!")
	}

	if !usesCoProcessMiddleware && m.Spec.CustomMiddleware.Driver != "" {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("CP Driver not supported: ", m.Spec.CustomMiddleware.Driver)
	}

	return false
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	logger := m.Logger()

	logger.Debug("CoProcess Request, HookType: ", m.HookType)

	if !EnableCoProcess {
		return nil, 200
	}

	var extractor IdExtractor
	if m.Spec.EnableCoProcessAuth && m.Spec.CustomMiddleware.IdExtractor.Extractor != nil {
		extractor = m.Spec.CustomMiddleware.IdExtractor.Extractor.(IdExtractor)
	}

	var returnOverrides ReturnOverrides
	var sessionID string

	if m.HookType == coprocess.HookType_CustomKeyCheck && extractor != nil {
		sessionID, returnOverrides = extractor.ExtractAndCheck(r)

		if returnOverrides.ResponseCode != 0 {
			if returnOverrides.ResponseError == "" {
				return nil, returnOverrides.ResponseCode
			}
			err := errors.New(returnOverrides.ResponseError)
			return err, returnOverrides.ResponseCode
		}
	}

	// It's also possible to override the HookType:
	coProcessor := CoProcessor{
		Middleware: m,
		// HookType: coprocess.PreHook,
	}

	object := coProcessor.ObjectFromRequest(r)

	returnObject, err := coProcessor.Dispatch(object)
	if err != nil {
		logger.WithError(err).Error("Dispatch error")
		if m.HookType == coprocess.HookType_CustomKeyCheck {
			return errors.New("Key not authorised"), 403
		} else {
			return errors.New("Middleware error"), 500
		}
	}

	coProcessor.ObjectPostProcess(returnObject, r)

	var token string
	if returnObject.Session != nil {
		// For compatibility purposes, inject coprocess.Object.Metadata fields:
		if returnObject.Metadata != nil {
			if returnObject.Session.Metadata == nil {
				returnObject.Session.Metadata = make(map[string]string)
			}
			for k, v := range returnObject.Metadata {
				returnObject.Session.Metadata[k] = v
			}
		}

		token = returnObject.Session.Metadata["token"]
	}

	// The CP middleware indicates this is a bad auth:
	if returnObject.Request.ReturnOverrides.ResponseCode > 400 {
		logger.WithField("key", obfuscateKey(token)).Info("Attempted access with invalid key")

		// Fire Authfailed Event
		AuthFailed(m, r, token)

		// Report in health check
		reportHealthValue(m.Spec, KeyFailure, "1")

		errorMsg := "Key not authorised"
		if returnObject.Request.ReturnOverrides.ResponseError != "" {
			errorMsg = returnObject.Request.ReturnOverrides.ResponseError
		}

		return errors.New(errorMsg), int(returnObject.Request.ReturnOverrides.ResponseCode)
	}

	if returnObject.Request.ReturnOverrides.ResponseCode > 0 {
		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}
		w.WriteHeader(int(returnObject.Request.ReturnOverrides.ResponseCode))
		w.Write([]byte(returnObject.Request.ReturnOverrides.ResponseError))
		return nil, mwStatusRespond
	}

	// Is this a CP authentication middleware?
	if m.Spec.EnableCoProcessAuth && m.HookType == coprocess.HookType_CustomKeyCheck {
		// The CP middleware didn't setup a session:
		if returnObject.Session == nil || token == "" {
			authHeaderValue := r.Header.Get(m.Spec.Auth.AuthHeaderName)
			AuthFailed(m, r, authHeaderValue)
			return errors.New("Key not authorised"), 403
		}

		returnedSession := TykSessionState(returnObject.Session)

		// If the returned object contains metadata, add them to the session:
		for k, v := range returnObject.Metadata {
			returnedSession.MetaData[k] = string(v)
		}

		if extractor == nil {
			ctxSetSession(r, returnedSession, token, true)
		} else {
			ctxSetSession(r, returnedSession, sessionID, true)
		}
	}

	return nil, 200
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package core

import (
	"github.com/brocaar/lorawan"
)

// Component materializes a core component of the network: Router, Broker or Handler.
//
// With two adapters, it can communicates with others components and thus create a distributed
// network of components.
type Component interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, upAdapter Adapter) error
	HandleDown(p []byte, an AckNacker) error
}

type Handler interface {
	Register(reg Registration, an AckNacker, s Subscriber) error
	HandleUp(p []byte, an AckNacker, upAdapter Adapter) error
	HandleDown(p []byte, an AckNacker, down Adapter) error
}

type Router interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, up Adapter) error
}

type Broker interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, up Adapter) error
}

// NetworkController is directly used by the broker to manage nodes lifecycle.
type NetworkController interface {
	HandleCommands(packet BPacket) error
	UpdateFCntUp(appEUI lorawan.EUI64, devEUI lorawan.EUI64, fcnt uint32)
	UpdateFCntDown(appEUI lorawan.EUI64, devEUI lorawan.EUI64, fcnt uint32)
	MergeCommands(appEUI lorawan.EUI64, devEUI lorawan.EUI64, pkt BPacket) RPacket
}

// AckNacker represents an interface that allow adapters to decouple their protocol from the
// behaviour expected by the caller.
type AckNacker interface {
	Ack(p Packet) error
	Nack() error
}

// Adapter handles communications between components. They implement a specific communication
// protocol which is completely hidden from the outside.
type Adapter interface {
	Send(p Packet, r ...Recipient) ([]byte, error)
	//Join(r JoinRequest, r ...Recipient) (JoinResponse, error)
	GetRecipient(raw []byte) (Recipient, error)
	Next() ([]byte, AckNacker, error)
	NextRegistration() (Registration, AckNacker, error)
}

type Subscriber interface {
	Subscribe(reg Registration, recipient Recipient) error
}
<commit_msg>[handler-broker] Fix typo in core interfaces<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package core

import (
	"github.com/brocaar/lorawan"
)

// Component materializes a core component of the network: Router, Broker or Handler.
//
// With two adapters, it can communicates with others components and thus create a distributed
// network of components.
type Component interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, upAdapter Adapter) error
	HandleDown(p []byte, an AckNacker) error
}

type Handler interface {
	Register(reg Registration, an AckNacker, s Subscriber) error
	HandleUp(p []byte, an AckNacker, upAdapter Adapter) error
	HandleDown(p []byte, an AckNacker, down Adapter) error
}

type Router interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, up Adapter) error
}

type Broker interface {
	Register(reg Registration, an AckNacker) error
	HandleUp(p []byte, an AckNacker, up Adapter) error
}

// NetworkController is directly used by the broker to manage nodes lifecycle.
type NetworkController interface {
	HandleCommands(packet BPacket) error
	UpdateFCntUp(appEUI lorawan.EUI64, devEUI lorawan.EUI64, fcnt uint32)
	UpdateFCntDown(appEUI lorawan.EUI64, devEUI lorawan.EUI64, fcnt uint32)
	MergeCommands(appEUI lorawan.EUI64, devEUI lorawan.EUI64, pkt BPacket) RPacket
}

// AckNacker represents an interface that allow adapters to decouple their protocol from the
// behaviour expected by the caller.
type AckNacker interface {
	Ack(p Packet) error
	Nack() error
}

// Adapter handles communications between components. They implement a specific communication
// protocol which is completely hidden from the outside.
type Adapter interface {
	Send(p Packet, r ...Recipient) ([]byte, error)
	//Join(r JoinRequest, r ...Recipient) (JoinResponse, error)
	GetRecipient(raw []byte) (Recipient, error)
	Next() ([]byte, AckNacker, error)
	NextRegistration() (Registration, AckNacker, error)
}

type Subscriber interface {
	Subscribe(reg Registration) error
}
<|endoftext|>


<commit_before>package core

import (
	"encoding/base64"
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	bserv "github.com/jbenet/go-ipfs/blockservice"
	config "github.com/jbenet/go-ipfs/config"
	diag "github.com/jbenet/go-ipfs/diagnostics"
	exchange "github.com/jbenet/go-ipfs/exchange"
	bitswap "github.com/jbenet/go-ipfs/exchange/bitswap"
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
	mount "github.com/jbenet/go-ipfs/fuse/mount"
	merkledag "github.com/jbenet/go-ipfs/merkledag"
	namesys "github.com/jbenet/go-ipfs/namesys"
	inet "github.com/jbenet/go-ipfs/net"
	handshake "github.com/jbenet/go-ipfs/net/handshake"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	path "github.com/jbenet/go-ipfs/path"
	peer "github.com/jbenet/go-ipfs/peer"
	pin "github.com/jbenet/go-ipfs/pin"
	routing "github.com/jbenet/go-ipfs/routing"
	dht "github.com/jbenet/go-ipfs/routing/dht"
	u "github.com/jbenet/go-ipfs/util"
	ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
	"github.com/jbenet/go-ipfs/util/debugerror"
)

const IpnsValidatorTag = "ipns"

var log = u.Logger("core")

// IpfsNode is IPFS Core module. It represents an IPFS instance.
type IpfsNode struct {

	// the node's configuration
	Config *config.Config

	// the local node's identity
	Identity peer.Peer

	// storage for other Peer instances
	Peerstore peer.Peerstore

	// the local datastore
	Datastore u.ThreadSafeDatastoreCloser

	// the network message stream
	Network inet.Network

	// the routing system. recommend ipfs-dht
	Routing routing.IpfsRouting

	// the block exchange + strategy (bitswap)
	Exchange exchange.Interface

	// the block service, get/add blocks.
	Blocks *bserv.BlockService

	// the merkle dag service, get/add objects.
	DAG merkledag.DAGService

	// the path resolution system
	Resolver *path.Resolver

	// the name system, resolves paths to hashes
	Namesys namesys.NameSystem

	// the diagnostics service
	Diagnostics *diag.Diagnostics

	// the pinning manager
	Pinning pin.Pinner

	// current mount state, if any.
	Mounts Mounts

	ctxc.ContextCloser

	onlineMode bool // alternatively, offline
}

// Mounts defines what the node's mount state is. This should
// perhaps be moved to the daemon or mount. It's here because
// it needs to be accessible across daemon requests.
type Mounts struct {
	Ipfs mount.Mount
	Ipns mount.Mount
}

// NewIpfsNode constructs a new IpfsNode based on the given config.
func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
	success := false // flip to true after all sub-system inits succeed
	defer func() {
		if !success && n != nil {
			n.Close()
		}
	}()

	if cfg == nil {
		return nil, debugerror.Errorf("configuration required")
	}

	// derive this from a higher context.
	ctx := context.TODO()
	n = &IpfsNode{
		onlineMode: online,
		Config:     cfg,
	}
	n.ContextCloser = ctxc.NewContextCloser(ctx, n.teardown)

	// setup datastore.
	if n.Datastore, err = makeDatastore(cfg.Datastore); err != nil {
		return nil, debugerror.Wrap(err)
	}

	// setup peerstore + local peer identity
	n.Peerstore = peer.NewPeerstore()
	n.Identity, err = initIdentity(&n.Config.Identity, n.Peerstore, online)
	if err != nil {
		return nil, debugerror.Wrap(err)
	}

	// setup online services
	if online {

		dhtService := netservice.NewService(ctx, nil)      // nil handler for now, need to patch it
		exchangeService := netservice.NewService(ctx, nil) // nil handler for now, need to patch it
		diagService := netservice.NewService(ctx, nil)     // nil handler for now, need to patch it

		muxMap := &mux.ProtocolMap{
			mux.ProtocolID_Routing:    dhtService,
			mux.ProtocolID_Exchange:   exchangeService,
			mux.ProtocolID_Diagnostic: diagService,
			// add protocol services here.
		}

		// setup the network
		listenAddrs, err := listenAddresses(cfg)
		if err != nil {
			return nil, debugerror.Wrap(err)
		}

		n.Network, err = inet.NewIpfsNetwork(ctx, listenAddrs, n.Identity, n.Peerstore, muxMap)
		if err != nil {
			return nil, debugerror.Wrap(err)
		}
		n.AddCloserChild(n.Network)

		// setup diagnostics service
		n.Diagnostics = diag.NewDiagnostics(n.Identity, n.Network, diagService)
		diagService.SetHandler(n.Diagnostics)

		// setup routing service
		dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
		dhtRouting.Validators[IpnsValidatorTag] = namesys.ValidateIpnsRecord

		// TODO(brian): perform this inside NewDHT factory method
		dhtService.SetHandler(dhtRouting) // wire the handler to the service.
		n.Routing = dhtRouting
		n.AddCloserChild(dhtRouting)

		// setup exchange service
		const alwaysSendToPeer = true // use YesManStrategy
		bitswapNetwork := bsnet.NewFromIpfsNetwork(exchangeService, n.Network)
		n.Exchange = bitswap.New(ctx, n.Identity, bitswapNetwork, n.Routing, n.Datastore, alwaysSendToPeer)

		go initConnections(ctx, n.Config, n.Peerstore, dhtRouting)
	}

	// TODO(brian): when offline instantiate the BlockService with a bitswap
	// session that simply doesn't return blocks
	n.Blocks, err = bserv.NewBlockService(n.Datastore, n.Exchange)
	if err != nil {
		return nil, debugerror.Wrap(err)
	}

	n.DAG = merkledag.NewDAGService(n.Blocks)
	n.Namesys = namesys.NewNameSystem(n.Routing)
	n.Pinning, err = pin.LoadPinner(n.Datastore, n.DAG)
	if err != nil {
		n.Pinning = pin.NewPinner(n.Datastore, n.DAG)
	}
	n.Resolver = &path.Resolver{DAG: n.DAG}

	success = true
	return n, nil
}

func (n *IpfsNode) teardown() error {
	if err := n.Datastore.Close(); err != nil {
		return err
	}
	return nil
}

func (n *IpfsNode) OnlineMode() bool {
	return n.onlineMode
}

func initIdentity(cfg *config.Identity, peers peer.Peerstore, online bool) (peer.Peer, error) {
	if cfg.PeerID == "" {
		return nil, debugerror.New("Identity was not set in config (was ipfs init run?)")
	}

	if len(cfg.PeerID) == 0 {
		return nil, debugerror.New("No peer ID in config! (was ipfs init run?)")
	}

	// get peer from peerstore (so it is constructed there)
	id := peer.ID(b58.Decode(cfg.PeerID))
	self, err := peers.Get(id)
	if err != nil {
		return nil, err
	}
	self.SetType(peer.Local)
	self, err = peers.Add(self)
	if err != nil {
		return nil, err
	}

	self.SetVersions(handshake.ClientVersion, handshake.IpfsVersion.String())

	// when not online, don't need to parse private keys (yet)
	if online {
		skb, err := base64.StdEncoding.DecodeString(cfg.PrivKey)
		if err != nil {
			return nil, err
		}

		if err := self.LoadAndVerifyKeyPair(skb); err != nil {
			return nil, err
		}
	}

	return self, nil
}

func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerstore, route *dht.IpfsDHT) {
	for _, p := range cfg.Bootstrap {
		if p.PeerID == "" {
			log.Criticalf("error: peer does not include PeerID. %v", p)
		}

		maddr, err := ma.NewMultiaddr(p.Address)
		if err != nil {
			log.Error(err)
			continue
		}

		// setup peer
		npeer, err := pstore.Get(peer.DecodePrettyID(p.PeerID))
		if err != nil {
			log.Criticalf("Bootstrapping error: %v", err)
			continue
		}
		npeer.AddAddress(maddr)

		if _, err = route.Connect(ctx, npeer); err != nil {
			log.Criticalf("Bootstrapping error: %v", err)
		}
	}
}

func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {

	var err error
	listen := make([]ma.Multiaddr, len(cfg.Addresses.Swarm))
	for i, addr := range cfg.Addresses.Swarm {

		listen[i], err = ma.NewMultiaddr(addr)
		if err != nil {
			return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm[%d]: %s", i, cfg.Addresses.Swarm)
		}
	}

	return listen, nil
}
<commit_msg>log(core) Event: bootstrap<commit_after>package core

import (
	"encoding/base64"
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	bserv "github.com/jbenet/go-ipfs/blockservice"
	config "github.com/jbenet/go-ipfs/config"
	diag "github.com/jbenet/go-ipfs/diagnostics"
	exchange "github.com/jbenet/go-ipfs/exchange"
	bitswap "github.com/jbenet/go-ipfs/exchange/bitswap"
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
	mount "github.com/jbenet/go-ipfs/fuse/mount"
	merkledag "github.com/jbenet/go-ipfs/merkledag"
	namesys "github.com/jbenet/go-ipfs/namesys"
	inet "github.com/jbenet/go-ipfs/net"
	handshake "github.com/jbenet/go-ipfs/net/handshake"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	path "github.com/jbenet/go-ipfs/path"
	peer "github.com/jbenet/go-ipfs/peer"
	pin "github.com/jbenet/go-ipfs/pin"
	routing "github.com/jbenet/go-ipfs/routing"
	dht "github.com/jbenet/go-ipfs/routing/dht"
	u "github.com/jbenet/go-ipfs/util"
	ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
	"github.com/jbenet/go-ipfs/util/debugerror"
	"github.com/jbenet/go-ipfs/util/eventlog"
)

const IpnsValidatorTag = "ipns"

var log = eventlog.Logger("core")

// IpfsNode is IPFS Core module. It represents an IPFS instance.
type IpfsNode struct {

	// the node's configuration
	Config *config.Config

	// the local node's identity
	Identity peer.Peer

	// storage for other Peer instances
	Peerstore peer.Peerstore

	// the local datastore
	Datastore u.ThreadSafeDatastoreCloser

	// the network message stream
	Network inet.Network

	// the routing system. recommend ipfs-dht
	Routing routing.IpfsRouting

	// the block exchange + strategy (bitswap)
	Exchange exchange.Interface

	// the block service, get/add blocks.
	Blocks *bserv.BlockService

	// the merkle dag service, get/add objects.
	DAG merkledag.DAGService

	// the path resolution system
	Resolver *path.Resolver

	// the name system, resolves paths to hashes
	Namesys namesys.NameSystem

	// the diagnostics service
	Diagnostics *diag.Diagnostics

	// the pinning manager
	Pinning pin.Pinner

	// current mount state, if any.
	Mounts Mounts

	ctxc.ContextCloser

	onlineMode bool // alternatively, offline
}

// Mounts defines what the node's mount state is. This should
// perhaps be moved to the daemon or mount. It's here because
// it needs to be accessible across daemon requests.
type Mounts struct {
	Ipfs mount.Mount
	Ipns mount.Mount
}

// NewIpfsNode constructs a new IpfsNode based on the given config.
func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
	success := false // flip to true after all sub-system inits succeed
	defer func() {
		if !success && n != nil {
			n.Close()
		}
	}()

	if cfg == nil {
		return nil, debugerror.Errorf("configuration required")
	}

	// derive this from a higher context.
	ctx := context.TODO()
	n = &IpfsNode{
		onlineMode: online,
		Config:     cfg,
	}
	n.ContextCloser = ctxc.NewContextCloser(ctx, n.teardown)

	// setup datastore.
	if n.Datastore, err = makeDatastore(cfg.Datastore); err != nil {
		return nil, debugerror.Wrap(err)
	}

	// setup peerstore + local peer identity
	n.Peerstore = peer.NewPeerstore()
	n.Identity, err = initIdentity(&n.Config.Identity, n.Peerstore, online)
	if err != nil {
		return nil, debugerror.Wrap(err)
	}

	// setup online services
	if online {

		dhtService := netservice.NewService(ctx, nil)      // nil handler for now, need to patch it
		exchangeService := netservice.NewService(ctx, nil) // nil handler for now, need to patch it
		diagService := netservice.NewService(ctx, nil)     // nil handler for now, need to patch it

		muxMap := &mux.ProtocolMap{
			mux.ProtocolID_Routing:    dhtService,
			mux.ProtocolID_Exchange:   exchangeService,
			mux.ProtocolID_Diagnostic: diagService,
			// add protocol services here.
		}

		// setup the network
		listenAddrs, err := listenAddresses(cfg)
		if err != nil {
			return nil, debugerror.Wrap(err)
		}

		n.Network, err = inet.NewIpfsNetwork(ctx, listenAddrs, n.Identity, n.Peerstore, muxMap)
		if err != nil {
			return nil, debugerror.Wrap(err)
		}
		n.AddCloserChild(n.Network)

		// setup diagnostics service
		n.Diagnostics = diag.NewDiagnostics(n.Identity, n.Network, diagService)
		diagService.SetHandler(n.Diagnostics)

		// setup routing service
		dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
		dhtRouting.Validators[IpnsValidatorTag] = namesys.ValidateIpnsRecord

		// TODO(brian): perform this inside NewDHT factory method
		dhtService.SetHandler(dhtRouting) // wire the handler to the service.
		n.Routing = dhtRouting
		n.AddCloserChild(dhtRouting)

		// setup exchange service
		const alwaysSendToPeer = true // use YesManStrategy
		bitswapNetwork := bsnet.NewFromIpfsNetwork(exchangeService, n.Network)
		n.Exchange = bitswap.New(ctx, n.Identity, bitswapNetwork, n.Routing, n.Datastore, alwaysSendToPeer)

		go initConnections(ctx, n.Config, n.Peerstore, dhtRouting)
	}

	// TODO(brian): when offline instantiate the BlockService with a bitswap
	// session that simply doesn't return blocks
	n.Blocks, err = bserv.NewBlockService(n.Datastore, n.Exchange)
	if err != nil {
		return nil, debugerror.Wrap(err)
	}

	n.DAG = merkledag.NewDAGService(n.Blocks)
	n.Namesys = namesys.NewNameSystem(n.Routing)
	n.Pinning, err = pin.LoadPinner(n.Datastore, n.DAG)
	if err != nil {
		n.Pinning = pin.NewPinner(n.Datastore, n.DAG)
	}
	n.Resolver = &path.Resolver{DAG: n.DAG}

	success = true
	return n, nil
}

func (n *IpfsNode) teardown() error {
	if err := n.Datastore.Close(); err != nil {
		return err
	}
	return nil
}

func (n *IpfsNode) OnlineMode() bool {
	return n.onlineMode
}

func initIdentity(cfg *config.Identity, peers peer.Peerstore, online bool) (peer.Peer, error) {
	if cfg.PeerID == "" {
		return nil, debugerror.New("Identity was not set in config (was ipfs init run?)")
	}

	if len(cfg.PeerID) == 0 {
		return nil, debugerror.New("No peer ID in config! (was ipfs init run?)")
	}

	// get peer from peerstore (so it is constructed there)
	id := peer.ID(b58.Decode(cfg.PeerID))
	self, err := peers.Get(id)
	if err != nil {
		return nil, err
	}
	self.SetType(peer.Local)
	self, err = peers.Add(self)
	if err != nil {
		return nil, err
	}

	self.SetVersions(handshake.ClientVersion, handshake.IpfsVersion.String())

	// when not online, don't need to parse private keys (yet)
	if online {
		skb, err := base64.StdEncoding.DecodeString(cfg.PrivKey)
		if err != nil {
			return nil, err
		}

		if err := self.LoadAndVerifyKeyPair(skb); err != nil {
			return nil, err
		}
	}

	return self, nil
}

func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerstore, route *dht.IpfsDHT) {
	// TODO consider stricter error handling
	// TODO consider Criticalf error logging
	for _, p := range cfg.Bootstrap {
		if p.PeerID == "" {
			log.Criticalf("error: peer does not include PeerID. %v", p)
		}

		maddr, err := ma.NewMultiaddr(p.Address)
		if err != nil {
			log.Error(err)
			continue
		}

		// setup peer
		npeer, err := pstore.Get(peer.DecodePrettyID(p.PeerID))
		if err != nil {
			log.Criticalf("Bootstrapping error: %v", err)
			continue
		}
		npeer.AddAddress(maddr)

		if _, err = route.Connect(ctx, npeer); err != nil {
			log.Criticalf("Bootstrapping error: %v", err)
			continue
		}
		log.Event(ctx, "bootstrap", npeer)
	}
}

func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {

	var err error
	listen := make([]ma.Multiaddr, len(cfg.Addresses.Swarm))
	for i, addr := range cfg.Addresses.Swarm {

		listen[i], err = ma.NewMultiaddr(addr)
		if err != nil {
			return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm[%d]: %s", i, cfg.Addresses.Swarm)
		}
	}

	return listen, nil
}
<|endoftext|>


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

// +build java android

package v23_go_runner

import (
	"fmt"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/rpc"
	"v.io/v23/security"
)

const (
	tcpServerName = "tmp/tcpServerName"
	btServerName  = "tmp/btServerName"
)

// v23GoRunnerFuncs is a map containing go functions keys by unique strings
// intended to be run by java/android applications using V23GoRunner.run(key).
// Users must add function entries to this map and rebuild lib/android-lib in
// the vanadium java repository.
var v23GoRunnerFuncs = map[string]func(*context.T) error{
	"tcp-server": tcpServerFunc,
	"tcp-client": tcpClientFunc,
	"bt-client":  btClientFunc,
	"bt-server":  btServerFunc,
}

func tcpServerFunc(ctx *context.T) error {
	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Proxy: "proxy"})
	return runServer(ctx, tcpServerName)
}

func tcpClientFunc(ctx *context.T) error {
	return runClient(ctx, tcpServerName)
}

func btServerFunc(ctx *context.T) error {
	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Addrs: rpc.ListenAddrs{{Protocol: "bt", Address: "/0"}}})
	return runServer(ctx, btServerName)
}

func btClientFunc(ctx *context.T) error {
	return runClient(ctx, btServerName)
}

func runServer(ctx *context.T, name string) error {
	_, server, err := v23.WithNewServer(ctx, name, &echoServer{}, security.AllowEveryone())
	if err != nil {
		return err
	}
	ctx.Infof("Server listening on %v", server.Status().Endpoints)
	ctx.Infof("Server listen errors: %v", server.Status().ListenErrors)
	return nil
}

func runClient(ctx *context.T, name string) error {
	elapsed, err := runTimedCall(ctx, name)
	if err != nil {
		return err
	}
	ctx.Infof("Client successfully executed rpc on new connection in %s.", elapsed.String())

	elapsed, err = runTimedCall(ctx, name)
	if err != nil {
		return err
	}
	ctx.Infof("Client successfully executed rpc on cached connection in %s.", elapsed.String())
	return nil
}

func runTimedCall(ctx *context.T, name string) (time.Duration, error) {
	message := "hi there"
	var got string
	start := time.Now()
	if err := v23.GetClient(ctx).Call(ctx, name, "Echo", []interface{}{message}, []interface{}{&got}); err != nil {
		return 0, err
	}
	elapsed := time.Now().Sub(start)
	if want := message; got != want {
		return 0, fmt.Errorf("got %s, want %s", got, want)
	}
	return elapsed, nil
}
<commit_msg>V23GoRunner: Add funcs for ble-client and ble-server.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build java android

package v23_go_runner

import (
	"fmt"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/rpc"
	"v.io/v23/security"
)

const (
	tcpServerName = "tmp/tcpServerName"
	btServerName  = "tmp/btServerName"
)

var bleServerName = naming.Endpoint{
	Protocol: "ble",
}.Name()

// v23GoRunnerFuncs is a map containing go functions keys by unique strings
// intended to be run by java/android applications using V23GoRunner.run(key).
// Users must add function entries to this map and rebuild lib/android-lib in
// the vanadium java repository.
var v23GoRunnerFuncs = map[string]func(*context.T) error{
	"tcp-server": tcpServerFunc,
	"tcp-client": tcpClientFunc,
	"bt-client":  btClientFunc,
	"bt-server":  btServerFunc,
	"ble-client": bleClientFunc,
	"ble-server": bleServerFunc,
}

func tcpServerFunc(ctx *context.T) error {
	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Proxy: "proxy"})
	return runServer(ctx, tcpServerName)
}

func tcpClientFunc(ctx *context.T) error {
	return runClient(ctx, tcpServerName)
}

func btServerFunc(ctx *context.T) error {
	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Addrs: rpc.ListenAddrs{{Protocol: "bt", Address: "/0"}}})
	return runServer(ctx, btServerName)
}

func btClientFunc(ctx *context.T) error {
	return runClient(ctx, btServerName)
}

func runServer(ctx *context.T, name string) error {
	_, server, err := v23.WithNewServer(ctx, name, &echoServer{}, security.AllowEveryone())
	if err != nil {
		return err
	}
	ctx.Infof("Server listening on %v", server.Status().Endpoints)
	ctx.Infof("Server listen errors: %v", server.Status().ListenErrors)
	return nil
}

func runClient(ctx *context.T, name string) error {
	elapsed, err := runTimedCall(ctx, name)
	if err != nil {
		return err
	}
	ctx.Infof("Client successfully executed rpc on new connection in %s.", elapsed.String())

	elapsed, err = runTimedCall(ctx, name)
	if err != nil {
		return err
	}
	ctx.Infof("Client successfully executed rpc on cached connection in %s.", elapsed.String())
	return nil
}

func runTimedCall(ctx *context.T, name string) (time.Duration, error) {
	message := "hi there"
	var got string
	start := time.Now()
	if err := v23.GetClient(ctx).Call(ctx, name, "Echo", []interface{}{message}, []interface{}{&got}); err != nil {
		return 0, err
	}
	elapsed := time.Now().Sub(start)
	if want := message; got != want {
		return 0, fmt.Errorf("got %s, want %s", got, want)
	}
	return elapsed, nil
}

func bleServerFunc(ctx *context.T) error {
	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{Addrs: rpc.ListenAddrs{{Protocol: "ble"}}})
	return runServer(ctx, "")
}

func bleClientFunc(ctx *context.T) error {
	return runClient(ctx, bleServerName)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsKinesisFirehoseDeliveryStream() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsKinesisFirehoseDeliveryStreamCreate,
		Read:   resourceAwsKinesisFirehoseDeliveryStreamRead,
		Update: resourceAwsKinesisFirehoseDeliveryStreamUpdate,
		Delete: resourceAwsKinesisFirehoseDeliveryStreamDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"destination": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				StateFunc: func(v interface{}) string {
					value := v.(string)
					return strings.ToLower(value)
				},
			},

			"role_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"s3_bucket_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"s3_prefix": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"s3_buffer_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  5,
			},

			"s3_buffer_interval": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  300,
			},

			"s3_data_compression": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "UNCOMPRESSED",
			},

			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"version_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"destination_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func resourceAwsKinesisFirehoseDeliveryStreamCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	if d.Get("destination").(string) != "s3" {
		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
	}

	sn := d.Get("name").(string)
	input := &firehose.CreateDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	}

	s3_config := &firehose.S3DestinationConfiguration{
		BucketARN: aws.String(d.Get("s3_bucket_arn").(string)),
		RoleARN:   aws.String(d.Get("role_arn").(string)),
		BufferingHints: &firehose.BufferingHints{
			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
		},
		CompressionFormat: aws.String(d.Get("s3_data_compression").(string)),
	}
	if v, ok := d.GetOk("s3_prefix"); ok {
		s3_config.Prefix = aws.String(v.(string))
	}

	input.S3DestinationConfiguration = s3_config

	_, err := conn.CreateDeliveryStream(input)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("[WARN] Error creating Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
		}
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"CREATING"},
		Target:     "ACTIVE",
		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	firehoseStream, err := stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for Kinesis Stream (%s) to become active: %s",
			sn, err)
	}

	s := firehoseStream.(*firehose.DeliveryStreamDescription)
	d.SetId(*s.DeliveryStreamARN)
	d.Set("arn", s.DeliveryStreamARN)

	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
}

func resourceAwsKinesisFirehoseDeliveryStreamUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	if d.Get("destination").(string) != "s3" {
		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
	}

	sn := d.Get("name").(string)
	s3_config := &firehose.S3DestinationUpdate{}

	if d.HasChange("role_arn") {
		s3_config.RoleARN = aws.String(d.Get("role_arn").(string))
	}

	if d.HasChange("s3_bucket_arn") {
		s3_config.BucketARN = aws.String(d.Get("s3_bucket_arn").(string))
	}

	if d.HasChange("s3_prefix") {
		s3_config.Prefix = aws.String(d.Get("s3_prefix").(string))
	}

	if d.HasChange("s3_data_compression") {
		s3_config.CompressionFormat = aws.String(d.Get("s3_data_compression").(string))
	}

	if d.HasChange("s3_buffer_interval") || d.HasChange("s3_buffer_size") {
		bufferingHints := &firehose.BufferingHints{
			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
		}
		s3_config.BufferingHints = bufferingHints
	}

	destOpts := &firehose.UpdateDestinationInput{
		DeliveryStreamName:             aws.String(sn),
		CurrentDeliveryStreamVersionId: aws.String(d.Get("version_id").(string)),
		DestinationId:                  aws.String(d.Get("destination_id").(string)),
		S3DestinationUpdate:            s3_config,
	}

	_, err := conn.UpdateDestination(destOpts)
	if err != nil {
		return fmt.Errorf(
			"Error Updating Kinesis Firehose Delivery Stream: %s",
			sn, err)
	}

	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
}

func resourceAwsKinesisFirehoseDeliveryStreamRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn
	sn := d.Get("name").(string)
	describeOpts := &firehose.DescribeDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	}
	resp, err := conn.DescribeDeliveryStream(describeOpts)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				d.SetId("")
				return nil
			}
			return fmt.Errorf("[WARN] Error reading Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
		}
		return err
	}

	s := resp.DeliveryStreamDescription
	d.Set("version_id", s.VersionId)
	d.Set("arn", *s.DeliveryStreamARN)
	if len(s.Destinations) > 0 {
		destination := s.Destinations[0]
		d.Set("destination_id", *destination.DestinationId)
	}

	return nil
}

func resourceAwsKinesisFirehoseDeliveryStreamDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	sn := d.Get("name").(string)
	_, err := conn.DeleteDeliveryStream(&firehose.DeleteDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	})

	if err != nil {
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"DELETING"},
		Target:     "DESTROYED",
		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for Delivery Stream (%s) to be destroyed: %s",
			sn, err)
	}

	d.SetId("")
	return nil
}

func firehoseStreamStateRefreshFunc(conn *firehose.Firehose, sn string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		describeOpts := &firehose.DescribeDeliveryStreamInput{
			DeliveryStreamName: aws.String(sn),
		}
		resp, err := conn.DescribeDeliveryStream(describeOpts)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ResourceNotFoundException" {
					return 42, "DESTROYED", nil
				}
				return nil, awsErr.Code(), err
			}
			return nil, "failed", err
		}

		return resp.DeliveryStreamDescription, *resp.DeliveryStreamDescription.DeliveryStreamStatus, nil
	}
}
<commit_msg>provider/aws: Fix error format in Kinesis Firehose<commit_after>package aws

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsKinesisFirehoseDeliveryStream() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsKinesisFirehoseDeliveryStreamCreate,
		Read:   resourceAwsKinesisFirehoseDeliveryStreamRead,
		Update: resourceAwsKinesisFirehoseDeliveryStreamUpdate,
		Delete: resourceAwsKinesisFirehoseDeliveryStreamDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"destination": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				StateFunc: func(v interface{}) string {
					value := v.(string)
					return strings.ToLower(value)
				},
			},

			"role_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"s3_bucket_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"s3_prefix": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"s3_buffer_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  5,
			},

			"s3_buffer_interval": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  300,
			},

			"s3_data_compression": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "UNCOMPRESSED",
			},

			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"version_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"destination_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func resourceAwsKinesisFirehoseDeliveryStreamCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	if d.Get("destination").(string) != "s3" {
		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
	}

	sn := d.Get("name").(string)
	input := &firehose.CreateDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	}

	s3_config := &firehose.S3DestinationConfiguration{
		BucketARN: aws.String(d.Get("s3_bucket_arn").(string)),
		RoleARN:   aws.String(d.Get("role_arn").(string)),
		BufferingHints: &firehose.BufferingHints{
			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
		},
		CompressionFormat: aws.String(d.Get("s3_data_compression").(string)),
	}
	if v, ok := d.GetOk("s3_prefix"); ok {
		s3_config.Prefix = aws.String(v.(string))
	}

	input.S3DestinationConfiguration = s3_config

	_, err := conn.CreateDeliveryStream(input)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("[WARN] Error creating Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
		}
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"CREATING"},
		Target:     "ACTIVE",
		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	firehoseStream, err := stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for Kinesis Stream (%s) to become active: %s",
			sn, err)
	}

	s := firehoseStream.(*firehose.DeliveryStreamDescription)
	d.SetId(*s.DeliveryStreamARN)
	d.Set("arn", s.DeliveryStreamARN)

	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
}

func resourceAwsKinesisFirehoseDeliveryStreamUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	if d.Get("destination").(string) != "s3" {
		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
	}

	sn := d.Get("name").(string)
	s3_config := &firehose.S3DestinationUpdate{}

	if d.HasChange("role_arn") {
		s3_config.RoleARN = aws.String(d.Get("role_arn").(string))
	}

	if d.HasChange("s3_bucket_arn") {
		s3_config.BucketARN = aws.String(d.Get("s3_bucket_arn").(string))
	}

	if d.HasChange("s3_prefix") {
		s3_config.Prefix = aws.String(d.Get("s3_prefix").(string))
	}

	if d.HasChange("s3_data_compression") {
		s3_config.CompressionFormat = aws.String(d.Get("s3_data_compression").(string))
	}

	if d.HasChange("s3_buffer_interval") || d.HasChange("s3_buffer_size") {
		bufferingHints := &firehose.BufferingHints{
			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
		}
		s3_config.BufferingHints = bufferingHints
	}

	destOpts := &firehose.UpdateDestinationInput{
		DeliveryStreamName:             aws.String(sn),
		CurrentDeliveryStreamVersionId: aws.String(d.Get("version_id").(string)),
		DestinationId:                  aws.String(d.Get("destination_id").(string)),
		S3DestinationUpdate:            s3_config,
	}

	_, err := conn.UpdateDestination(destOpts)
	if err != nil {
		return fmt.Errorf(
			"Error Updating Kinesis Firehose Delivery Stream: \"%s\"\n%s",
			sn, err)
	}

	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
}

func resourceAwsKinesisFirehoseDeliveryStreamRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn
	sn := d.Get("name").(string)
	describeOpts := &firehose.DescribeDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	}
	resp, err := conn.DescribeDeliveryStream(describeOpts)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				d.SetId("")
				return nil
			}
			return fmt.Errorf("[WARN] Error reading Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
		}
		return err
	}

	s := resp.DeliveryStreamDescription
	d.Set("version_id", s.VersionId)
	d.Set("arn", *s.DeliveryStreamARN)
	if len(s.Destinations) > 0 {
		destination := s.Destinations[0]
		d.Set("destination_id", *destination.DestinationId)
	}

	return nil
}

func resourceAwsKinesisFirehoseDeliveryStreamDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).firehoseconn

	sn := d.Get("name").(string)
	_, err := conn.DeleteDeliveryStream(&firehose.DeleteDeliveryStreamInput{
		DeliveryStreamName: aws.String(sn),
	})

	if err != nil {
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"DELETING"},
		Target:     "DESTROYED",
		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for Delivery Stream (%s) to be destroyed: %s",
			sn, err)
	}

	d.SetId("")
	return nil
}

func firehoseStreamStateRefreshFunc(conn *firehose.Firehose, sn string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		describeOpts := &firehose.DescribeDeliveryStreamInput{
			DeliveryStreamName: aws.String(sn),
		}
		resp, err := conn.DescribeDeliveryStream(describeOpts)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ResourceNotFoundException" {
					return 42, "DESTROYED", nil
				}
				return nil, awsErr.Code(), err
			}
			return nil, "failed", err
		}

		return resp.DeliveryStreamDescription, *resp.DeliveryStreamDescription.DeliveryStreamStatus, nil
	}
}
<|endoftext|>


<commit_before>package jstmpl

import (
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/ghodss/yaml"
	jstypes "github.com/go-jstmpl/go-jstmpl/types"
	"github.com/lestrrat/go-jshschema"
)

func ParseHschema(file string) (*hschema.HyperSchema, error) {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, fmt.Errorf("fail to read the source JSON Schema file: %s", err)
	}

	var m map[string]interface{}
	if err := yaml.Unmarshal(b, &m); err != nil {
		return nil, fmt.Errorf("fail to unmarshal YAML: %s", err)
	}

	hs := hschema.New()
	if err := hs.Extract(m); err != nil {
		return nil, fmt.Errorf("fail to extract JSON Schema: %s", err)
	}

	return hs, nil
}

func TestBuillderNotHaveHref(t *testing.T) {
	hs, err := ParseHschema("./test/has_not_href.yml")
	if err != nil {
		t.Fatal(err)
	}
	b := NewBuilder()
	ts, err := b.Build(hs)
	if err != nil {
		t.Fatalf("fail to build: %s", err)
	}

	if ts.Title != "has not href" {
		t.Error("fail to get title")
	}
}

func TestBuilderPassBuild(t *testing.T) {
	hs, err := ParseHschema("./test/pass.yml")
	if err != nil {
		t.Fatal(err)
	}
	b := NewBuilder()
	ts, err := b.Build(hs)
	if err != nil {
		t.Fatalf("fail to build: %s", err)
	}

	if len(ts.Objects) != 1 {
		t.Fatal("fail to parse Object type schema")
	}

	if ts.Objects[0] == nil || ts.Objects[0].Title() != "test object" {
		t.Errorf("fail to get Object type schema: %+v", ts.Objects[0])
	}

	if len(ts.Arrays) != 1 {
		t.Fatal("fail to parse Array type schema")
	}

	if ts.Arrays[0] == nil || ts.Arrays[0].Title() != "test array" {
		t.Errorf("fail to get Arrays type schema: %+v", ts.Arrays[0])
	}

	if len(ts.Booleans) != 1 {
		t.Fatal("fail to parse Boolean type schema")
	}

	if ts.Booleans[0] == nil || ts.Booleans[0].Title() != "test boolean" {
		t.Errorf("fail to get Boolean type schema: %+v", ts.Booleans[0])
	}

	if len(ts.Numbers) != 1 {
		t.Fatal("fail to parse Number type schema")
	}

	if ts.Numbers[0] == nil || ts.Numbers[0].Title() != "test number" {
		t.Errorf("fail to get Numbers type schema: %+v", ts.Numbers[0])
	}

	if len(ts.Integers) != 1 {
		t.Fatal("fail to parse Integer type schema")
	}
	if ts.Integers[0] == nil || ts.Integers[0].Title() != "test integer" {
		t.Errorf("fail to get Integer type schema: %+v", ts.Integers[0])
	}

	if len(ts.Strings) != 1 {
		t.Fatal("fail to parse String type schema")
	}

	if ts.Strings[0] == nil || ts.Strings[0].Title() != "test string" {
		t.Errorf("fail to get Strings type schema: %+v", ts.Strings[0])
	}

	if len(ts.Properties) != 2 {
		t.Fatal("fail to parse Properties type schema")
	}

	for _, v := range ts.Properties {
		switch v.Key() {
		case "test_properties":
			if v.Title() != "test properties" {
				t.Errorf("fail to get Properties type not link schema: %+v", v)
			}
		case "test_link_properties":
			if v.Title() != "test object" {
				t.Errorf("fail to get Properties type link schema: %+v", v)
			}
		default:
			t.Errorf("fail to get Properties type schema, specify one of key")
		}
	}

	if len(ts.Links) != 1 {
		t.Fatal("fail to parse Links type schema")
	}

	for _, v := range ts.Links {
		switch obj := v.Schema.(type) {
		case *jstypes.Object:
			for _, p := range obj.Properties {
				switch p.Key() {
				case "links_test":
					if p.Title() != "test_column" {
						t.Errorf("failt to get Links type not link schema: %+v", p)
					}
				case "links_link_test":
					if p.Title() != "test object" {
						t.Errorf("fail to get Links type link schema: %+v", p)
					}
				default:
					t.Error("failt to get Links type schema, specify one of keys")
				}
			}
		default:
			t.Errorf("fail to get Links type, should be object schema: %+v", v)
		}
	}
	if len(ts.Definitions) != 6 {
		t.Fatal("fail to parse Definitions")
	}
}

func TestResolvePass(t *testing.T) {
	hs, err := ParseHschema("./test/resolve_pass.yml")
	if err != nil {
		t.Fatalf("fail to parse resolve: %v", err)
	}

	if hs.Schema.Definitions["test_link"] == nil {
		t.Fatalf("fail to get schema: %+v", hs)
	}

	sc := hs.Schema.Definitions["test_link"]
	ctx := &jstypes.Context{
		Validations: map[string]bool{},
	}

	for k := range hs.Definitions {
		ctx.Key = k
	}

	scm, err := resolve(sc, hs.Schema, ctx)
	if err != nil {
		t.Fatalf("fail to resolve: %s", err)
	}

	if scm.Title() != "test" {
		t.Errorf("fail to resolve link schema: title should be test: %+v", scm)
	}
}
<commit_msg>add test want to parse<commit_after>package jstmpl

import (
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/ghodss/yaml"
	jstypes "github.com/go-jstmpl/go-jstmpl/types"
	"github.com/lestrrat/go-jshschema"
)

func ParseHschema(file string) (*hschema.HyperSchema, error) {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, fmt.Errorf("fail to read the source JSON Schema file: %s", err)
	}

	var m map[string]interface{}
	if err := yaml.Unmarshal(b, &m); err != nil {
		return nil, fmt.Errorf("fail to unmarshal YAML: %s", err)
	}

	hs := hschema.New()
	if err := hs.Extract(m); err != nil {
		return nil, fmt.Errorf("fail to extract JSON Schema: %s", err)
	}

	return hs, nil
}

func TestBuillderNotHaveHref(t *testing.T) {
	hs, err := ParseHschema("./test/has_not_href.yml")
	if err != nil {
		t.Fatal(err)
	}
	b := NewBuilder()
	ts, err := b.Build(hs)
	if err != nil {
		t.Fatalf("fail to build: %s", err)
	}

	if ts.Title != "has not href" {
		t.Error("fail to get title")
	}
}

func TestBuilderPassBuild(t *testing.T) {
	hs, err := ParseHschema("./test/pass.yml")
	if err != nil {
		t.Fatal(err)
	}
	b := NewBuilder()
	ts, err := b.Build(hs)
	if err != nil {
		t.Fatalf("fail to build: %s", err)
	}

	if len(ts.Objects) != 1 {
		t.Fatal("fail to parse Object type schema")
	}

	if ts.Objects[0] == nil || ts.Objects[0].Title() != "test object" {
		t.Errorf("fail to get Object type schema: %+v", ts.Objects[0])
	}

	if len(ts.Arrays) != 1 {
		t.Fatal("fail to parse Array type schema")
	}

	if ts.Arrays[0] == nil || ts.Arrays[0].Title() != "test array" {
		t.Errorf("fail to get Arrays type schema: %+v", ts.Arrays[0])
	}

	if len(ts.Booleans) != 1 {
		t.Fatal("fail to parse Boolean type schema")
	}

	if ts.Booleans[0] == nil || ts.Booleans[0].Title() != "test boolean" {
		t.Errorf("fail to get Boolean type schema: %+v", ts.Booleans[0])
	}

	if len(ts.Numbers) != 1 {
		t.Fatal("fail to parse Number type schema")
	}

	if ts.Numbers[0] == nil || ts.Numbers[0].Title() != "test number" {
		t.Errorf("fail to get Numbers type schema: %+v", ts.Numbers[0])
	}

	if len(ts.Integers) != 2 {
		t.Fatal("fail to parse Integer type schema")
	}

	if ts.Integers[0] == nil || ts.Integers[0].Title() != "test integer" {
		t.Errorf("fail to get Integer type schema: %+v", ts.Integers[0])
	}

	if len(ts.Strings) != 1 {
		t.Fatal("fail to parse String type schema")
	}

	if ts.Strings[0] == nil || ts.Strings[0].Title() != "test string" {
		t.Errorf("fail to get Strings type schema: %+v", ts.Strings[0])
	}

	if len(ts.Properties) != 2 {
		t.Fatal("fail to parse Properties type schema")
	}

	if len(ts.Definitions) != 7 {
		t.Fatal("fail to parse Definitions")
	}

	for _, v := range ts.Properties {
		switch v.Key() {
		case "test_multitype_in_link":
			if v.Title() != "test multitype" {
				t.Errorf("fail to get Properties type not link extra schema: %+v", v)
			}
		case "test_multitype":
			if v.Title() != "test multitype" {
				t.Errorf("fail to get Properties type link extra schema: %+v", v)
			}
		default:
			t.Errorf("fail to get Properties type schema, specify one of key: %s", v)
		}
	}

	if len(ts.Links) != 1 {
		t.Fatal("fail to parse Links type schema")
	}

	for _, v := range ts.Links {
		switch obj := v.Schema.(type) {
		case *jstypes.Object:
			for _, p := range obj.Properties {
				switch p.Key() {
				case "test_multitype_in_link":
					if p.Title() != "test multitype" {
						t.Errorf("fail to get Links type link schema: %+v", p)
					}
				case "test_multitype":
					if p.Title() != "test multitype" {
						t.Errorf("fail to get Links type not link schema: %+v", p)
					}
				default:
					t.Errorf("failt to get Links type schema, specify one of keys: %+v", p)
				}
			}
		default:
			t.Errorf("fail to get Links type, should be object schema: %+v", v)
		}
	}
}

func TestResolvePass(t *testing.T) {
	hs, err := ParseHschema("./test/resolve_pass.yml")
	if err != nil {
		t.Fatalf("fail to parse resolve: %v", err)
	}

	if hs.Schema.Definitions["test_link"] == nil {
		t.Fatalf("fail to get schema: %+v", hs)
	}

	sc := hs.Schema.Definitions["test_link"]
	ctx := &jstypes.Context{
		Validations: map[string]bool{},
	}

	for k := range hs.Definitions {
		ctx.Key = k
	}

	scm, err := resolve(sc, hs.Schema, ctx)
	if err != nil {
		t.Fatalf("fail to resolve: %s", err)
	}

	if scm.Title() != "test" {
		t.Errorf("fail to resolve link schema: title should be test: %+v", scm)
	}
}
<|endoftext|>


<commit_before>package cmap

import "testing"

type CMapTest struct {
	CMap     CMap
	Do       func(c *CMap)
	Expected map[CMKey]Value
}

var cmapTests = []CMapTest{
	{
		CMap:     NewCMap(),
		Expected: map[CMKey]Value{},
	},
	{
		CMap:     MakeCMap(999),
		Expected: NewCMap().Snapshot(),
	},
	{
		CMap:     NewCMap(),
		Expected: NewCMap().Snapshot(),
	},
	{
		CMap:     NewCMap("one"),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap:     NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap:     NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(func(v Value) bool { return v.ID() == "one" })
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(nil)
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(func(v Value) bool { return v.ID() == "two" })
		},
		Expected: map[CMKey]Value{},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			ok := c.Add("two")
			if !ok {
				panic("failed to add two")
			}
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			ok := c.Add("one")
			if ok {
				panic("added one twice")
			}
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.MustAdd("two")
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.AddAll(NewCMap("two", "three"))
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two", "three": "three"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.AddAll(NewCMap("two", "three"))
			c.Remove("two")
		},
		Expected: map[CMKey]Value{"one": "one", "three": "three"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = NewCMapFromMap(c.FilteredSnapshot(func(v Value) bool {
				return v == "two"
			}))
		},
		Expected: map[CMKey]Value{},
	},
	{
		CMap: NewCMap(),
		Do: func(c *CMap) {
			c.SetAll(map[CMKey]Value{"set": "set", "all": "all"})
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"set": "set", "all": "all"}),
		Do: func(c *CMap) {
			*c = NewCMapFromMap(c.GetAll())
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"set": "set", "all": "all"}),
		Do: func(c *CMap) {
			*c = c.Clone()
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Get("two")
			if !ok {
				panic("missing key two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{}),
		Do: func(c *CMap) {
			c.Set("two", "two")
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Single(func(v Value) bool {
				return v == "two"
			})
			if !ok {
				panic("no single value two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Single(func(v Value) bool {
				return v == "nonexistent"
			})
			if ok {
				panic("found nonexistent value")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"": ""},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Any(func(v Value) bool {
				return v == "two"
			})
			if !ok {
				panic("no value two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Any(func(v Value) bool {
				return v == "nonexistent"
			})
			if ok {
				panic("found value; should not have")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"": ""},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			other := NewCMapFromMap(map[CMKey]Value{"two": "two"})
			*c = c.Merge(other)
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			vals := []Value{}
			for _, k := range c.Keys() {
				vals = append(vals, Value(string(k)))
			}
			other := NewCMap(vals...)
			*c = c.Merge(other)
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
}

func TestCMap(t *testing.T) {

	for _, test := range cmapTests {
		if test.Do != nil {
			test.Do(&test.CMap)
		}
		actual := test.CMap.Snapshot()
		expected := test.Expected
		if test.CMap.Len() != len(actual) {
			t.Errorf("Len ≠ len")
		}
		if len(actual) != len(expected) {
			t.Errorf("got len %d; want %d", len(actual), len(expected))
		}
		for actualKey := range actual {
			if _, ok := expected[actualKey]; !ok {
				t.Errorf("extra key %q", actualKey)
			}
		}
		for expectedKey := range expected {
			if _, ok := actual[expectedKey]; !ok {
				t.Errorf("missing key %q", expectedKey)
			}
		}
	}

}
<commit_msg>Test concurrent maps in parallel.<commit_after>package cmap

import (
	"sync"
	"testing"
)

type CMapTest struct {
	CMap     CMap
	Do       func(c *CMap)
	Expected map[CMKey]Value
}

var cmapTests = []CMapTest{
	{
		CMap:     NewCMap(),
		Expected: map[CMKey]Value{},
	},
	{
		CMap:     MakeCMap(999),
		Expected: NewCMap().Snapshot(),
	},
	{
		CMap:     NewCMap(),
		Expected: NewCMap().Snapshot(),
	},
	{
		CMap:     NewCMap("one"),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap:     NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap:     NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(func(v Value) bool { return v.ID() == "one" })
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(nil)
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = c.Filter(func(v Value) bool { return v.ID() == "two" })
		},
		Expected: map[CMKey]Value{},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			ok := c.Add("two")
			if !ok {
				panic("failed to add two")
			}
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			ok := c.Add("one")
			if ok {
				panic("added one twice")
			}
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.MustAdd("two")
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.AddAll(NewCMap("two", "three"))
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two", "three": "three"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			c.AddAll(NewCMap("two", "three"))
			c.Remove("two")
		},
		Expected: map[CMKey]Value{"one": "one", "three": "three"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			*c = NewCMapFromMap(c.FilteredSnapshot(func(v Value) bool {
				return v == "two"
			}))
		},
		Expected: map[CMKey]Value{},
	},
	{
		CMap: NewCMap(),
		Do: func(c *CMap) {
			c.SetAll(map[CMKey]Value{"set": "set", "all": "all"})
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"set": "set", "all": "all"}),
		Do: func(c *CMap) {
			*c = NewCMapFromMap(c.GetAll())
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"set": "set", "all": "all"}),
		Do: func(c *CMap) {
			*c = c.Clone()
		},
		Expected: map[CMKey]Value{"set": "set", "all": "all"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Get("two")
			if !ok {
				panic("missing key two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{}),
		Do: func(c *CMap) {
			c.Set("two", "two")
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Single(func(v Value) bool {
				return v == "two"
			})
			if !ok {
				panic("no single value two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Single(func(v Value) bool {
				return v == "nonexistent"
			})
			if ok {
				panic("found nonexistent value")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"": ""},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Any(func(v Value) bool {
				return v == "two"
			})
			if !ok {
				panic("no value two")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one", "two": "two"}),
		Do: func(c *CMap) {
			v, ok := c.Any(func(v Value) bool {
				return v == "nonexistent"
			})
			if ok {
				panic("found value; should not have")
			}
			*c = NewCMap(v)
		},
		Expected: map[CMKey]Value{"": ""},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			other := NewCMapFromMap(map[CMKey]Value{"two": "two"})
			*c = c.Merge(other)
		},
		Expected: map[CMKey]Value{"one": "one", "two": "two"},
	},
	{
		CMap: NewCMapFromMap(map[CMKey]Value{"one": "one"}),
		Do: func(c *CMap) {
			vals := []Value{}
			for _, k := range c.Keys() {
				vals = append(vals, Value(string(k)))
			}
			other := NewCMap(vals...)
			*c = c.Merge(other)
		},
		Expected: map[CMKey]Value{"one": "one"},
	},
}

func TestCMap(t *testing.T) {

	wg := sync.WaitGroup{}
	wg.Add(len(cmapTests))
	for _, test := range cmapTests {
		test := test
		go func() {
			defer wg.Done()
			if test.Do != nil {
				test.Do(&test.CMap)
			}
			actual := test.CMap.Snapshot()
			expected := test.Expected
			if test.CMap.Len() != len(actual) {
				t.Errorf("Len ≠ len")
			}
			if len(actual) != len(expected) {
				t.Errorf("got len %d; want %d", len(actual), len(expected))
			}
			for actualKey := range actual {
				if _, ok := expected[actualKey]; !ok {
					t.Errorf("extra key %q", actualKey)
				}
			}
			for expectedKey := range expected {
				if _, ok := actual[expectedKey]; !ok {
					t.Errorf("missing key %q", expectedKey)
				}
			}
		}()
	}
	wg.Wait()

}
<|endoftext|>