<commit_before>package grunway

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/amattn/deeperror"
)

type Context struct {
	Req *http.Request // original http request
	End Endpoint      // parsed endpoint information

	// only populated after a call to ctx.RequestBody()
	cachedRequestBody      []byte
	cachedRequestBodyError error

	// exposing the responseWriter tends to induce bugs.  We keep this internal for now.
	w http.ResponseWriter

	// router
	router *Router

	// only populated after auth
	PublicKey string // for Auth'd requests, will be set to public key if Auth was successful, "" otherwise

	// generic maps for middleware to stuff arbitrary data
	middleware map[string]interface{}
	postware   map[string]interface{}

	// only populated after a write

	written       bool // true after a write, false before.  Used to prevent "double writes".
	StatusCode    int  // The http status code written out. Only populated after a write.
	ContentLength int  // The number of bytes written out. Only populated after a write.
}

func (ctx *Context) AddHeader(key, value string) {
	ctx.w.Header().Add(key, value)
}
func (ctx *Context) DelHeader(key string) {
	ctx.w.Header().Del(key)
}
func (ctx *Context) GetHeader(key string) string {
	return ctx.w.Header().Get(key)
}
func (ctx *Context) SetHeader(key, value string) {
	ctx.w.Header().Set(key, value)
}

func (ctx *Context) RequestBody() ([]byte, error) {
	if ctx.cachedRequestBody != nil {
		return ctx.cachedRequestBody, nil
	}
	if ctx.cachedRequestBodyError != nil {
		return nil, ctx.cachedRequestBodyError
	}

	ctx.cachedRequestBody, ctx.cachedRequestBodyError = ioutil.ReadAll(ctx.Req.Body)
	return ctx.cachedRequestBody, ctx.cachedRequestBodyError
}

//  #####
// #     # #####   ##   #    # #####    ##   #####  #####
// #         #    #  #  ##   # #    #  #  #  #    # #    #
//  #####    #   #    # # #  # #    # #    # #    # #    #
//       #   #   ###### #  # # #    # ###### #####  #    #
// #     #   #   #    # #   ## #    # #    # #   #  #    #
//  #####    #   #    # #    # #####  #    # #    # #####
//
// ######
// #     # ######  ####  #    # #      #####  ####
// #     # #      #      #    # #        #   #
// ######  #####   ####  #    # #        #    ####
// #   #   #           # #    # #        #        #
// #    #  #      #    # #    # #        #   #    #
// #     # ######  ####   ####  ######   #    ####
//

func (ctx *Context) MakeRouteHandlerResultError(code int, errNo int64, errMsg string) RouteHandlerResult {
	errInfo := ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errMsg,
	}
	return ctx.MakeRouteHandlerResultErrorInfo(code, errInfo)
}
func (ctx *Context) MakeRouteHandlerResultDebugError(code int, errNo int64, errMsg string, debugNo int64, debugMsg string) RouteHandlerResult {
	errInfo := ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errMsg,
		DebugNumber:  debugNo,
		DebugMessage: debugMsg,
	}
	return ctx.MakeRouteHandlerResultErrorInfo(code, errInfo)
}
func (ctx *Context) MakeRouteHandlerResultErrorInfo(code int, errInfo ErrorInfo) RouteHandlerResult {
	rerr := NewRouteError(code, errInfo)
	return RouteHandlerResult{rerr, nil, nil}
}

func (ctx *Context) MakeRouteHandlerResultAlert(code int, errNo int64, alert string) RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendErrorPayload(innerCtx, code, ErrorInfo{ErrorNumber: errNo}, alert)
	})
}
func (ctx *Context) MakeRouteHandlerResultPayloads(payloads ...Payload) RouteHandlerResult {
	return RouteHandlerResult{nil, MakePayloadMapFromPayloads(payloads...), nil}
}
func (ctx *Context) MakeRouteHandlerResultGenericJSON(v interface{}) RouteHandlerResult {
	jsonBytes, err := json.Marshal(v)
	code := http.StatusOK
	if err != nil {
		rerr := NewRouteError(
			http.StatusInternalServerError,
			ErrorInfo{
				ErrorNumber:  3913952842,
				ErrorMessage: "Internal Server Error",
			})
		return RouteHandlerResult{rerr, nil, nil}
	} else {
		return RouteHandlerResult{nil, nil, func(innerCtx *Context) {
			if rw, isResponseWriter := innerCtx.w.(http.ResponseWriter); isResponseWriter {
				rw.WriteHeader(code)
				if len(jsonBytes) == 0 {
					log.Println("jsonBytes", jsonBytes, innerCtx.Req.URL)
				}
				bytesWritten, err := rw.Write(jsonBytes)
				if err != nil {
					log.Println("3952513088 WRITE ERROR", err)
				}
				innerCtx.ContentLength = bytesWritten
			}
		}}
	}
}
func (ctx *Context) MakeRouteHandlerResultCustom(crr CustomRouteResponse) RouteHandlerResult {
	return RouteHandlerResult{nil, nil, crr}
}
func (ctx *Context) MakeRouteHandlerResultOk() RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendOkPayload(innerCtx)
	})
}
func (ctx *Context) MakeRouteHandlerResultNotFound(errNo int64) RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendNotFoundPayload(innerCtx, errNo)
	})
}

//  #####
// #     # #    #  ####  #####  ####  #    #
// #       #    # #        #   #    # ##  ##
// #       #    #  ####    #   #    # # ## #
// #       #    #      #   #   #    # #    #
// #     # #    # #    #   #   #    # #    #
//  #####   ####   ####    #    ####  #    #
//
// ######
// #     # ######  ####  #    # #      #####  ####
// #     # #      #      #    # #        #   #
// ######  #####   ####  #    # #        #    ####
// #   #   #           # #    # #        #        #
// #    #  #      #    # #    # #        #   #    #
// #     # ######  ####   ####  ######   #    ####
//

func (ctx *Context) WrapAndSendPayload(payload Payload) {
	if payload == nil {
		ctx.SendSimpleErrorPayload(http.StatusInternalServerError, 388359273, "")
		return
	}
	wrapAndSendPayload(ctx, payload)
}

// for a slice of Entities
func (ctx *Context) WrapAndSendPayloadsList(payloadList []Payload) {
	wrapAndSendPayloadsList(ctx, payloadList)
}

// for a map of slices of Entities
func (ctx *Context) WrapAndSendPayloadsMap(payloads PayloadsMap) {
	wrapAndSendPayloadsMap(ctx, payloads)
}

// Error
func (ctx *Context) SendSimpleErrorPayload(code int, errNo int64, errorMsg string) {
	ctx.SendErrorInfoPayload(code, ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errorMsg,
	})
}
func (ctx *Context) SendErrorInfoPayload(code int, errInfo ErrorInfo) {
	enduserErrMsg := errInfo.ErrorMessage
	if len(enduserErrMsg) == 0 {
		enduserErrMsg = http.StatusText(code)
	}
	sendErrorPayload(ctx, code, errInfo, "")
}

// Alert payloads are designed as a general notification service for clients (ie client must upgrade, server is in maint mode, etc.)
func (ctx *Context) SendSimpleAlertPayload(code int, errNo int64, errMsg, alert string) {
	sendErrorPayload(ctx, code, ErrorInfo{ErrorNumber: errNo, ErrorMessage: errMsg}, alert)
}

func (ctx *Context) DecodeResponseBodyOrSendError(pc PayloadController, payloadReference interface{}) interface{} {
	requestBody := ctx.Req.Body
	if requestBody == nil {
		errMsg := BadRequestPrefix + ": Expected non-empty body"
		ctx.SendSimpleErrorPayload(http.StatusBadRequest, 3003399819, errMsg)
		return nil
	}
	defer requestBody.Close()

	decoder := json.NewDecoder(requestBody)
	err := decoder.Decode(payloadReference)

	if err != nil {
		errMsg := BadRequestPrefix + ": Cannot parse body"
		derr := deeperror.New(3005488054, errMsg, err)
		log.Println("derr", derr)
		ctx.SendSimpleErrorPayload(http.StatusBadRequest, derr.Num, errMsg)
		return nil
	}

	return payloadReference
}
<commit_msg>add status code option to generic json handler<commit_after>package grunway

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/amattn/deeperror"
)

type Context struct {
	Req *http.Request // original http request
	End Endpoint      // parsed endpoint information

	// only populated after a call to ctx.RequestBody()
	cachedRequestBody      []byte
	cachedRequestBodyError error

	// exposing the responseWriter tends to induce bugs.  We keep this internal for now.
	w http.ResponseWriter

	// router
	router *Router

	// only populated after auth
	PublicKey string // for Auth'd requests, will be set to public key if Auth was successful, "" otherwise

	// generic maps for middleware to stuff arbitrary data
	middleware map[string]interface{}
	postware   map[string]interface{}

	// only populated after a write

	written       bool // true after a write, false before.  Used to prevent "double writes".
	StatusCode    int  // The http status code written out. Only populated after a write.
	ContentLength int  // The number of bytes written out. Only populated after a write.
}

func (ctx *Context) AddHeader(key, value string) {
	ctx.w.Header().Add(key, value)
}
func (ctx *Context) DelHeader(key string) {
	ctx.w.Header().Del(key)
}
func (ctx *Context) GetHeader(key string) string {
	return ctx.w.Header().Get(key)
}
func (ctx *Context) SetHeader(key, value string) {
	ctx.w.Header().Set(key, value)
}

func (ctx *Context) RequestBody() ([]byte, error) {
	if ctx.cachedRequestBody != nil {
		return ctx.cachedRequestBody, nil
	}
	if ctx.cachedRequestBodyError != nil {
		return nil, ctx.cachedRequestBodyError
	}

	ctx.cachedRequestBody, ctx.cachedRequestBodyError = ioutil.ReadAll(ctx.Req.Body)
	return ctx.cachedRequestBody, ctx.cachedRequestBodyError
}

//  #####
// #     # #####   ##   #    # #####    ##   #####  #####
// #         #    #  #  ##   # #    #  #  #  #    # #    #
//  #####    #   #    # # #  # #    # #    # #    # #    #
//       #   #   ###### #  # # #    # ###### #####  #    #
// #     #   #   #    # #   ## #    # #    # #   #  #    #
//  #####    #   #    # #    # #####  #    # #    # #####
//
// ######
// #     # ######  ####  #    # #      #####  ####
// #     # #      #      #    # #        #   #
// ######  #####   ####  #    # #        #    ####
// #   #   #           # #    # #        #        #
// #    #  #      #    # #    # #        #   #    #
// #     # ######  ####   ####  ######   #    ####
//

func (ctx *Context) MakeRouteHandlerResultError(code int, errNo int64, errMsg string) RouteHandlerResult {
	errInfo := ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errMsg,
	}
	return ctx.MakeRouteHandlerResultErrorInfo(code, errInfo)
}
func (ctx *Context) MakeRouteHandlerResultDebugError(code int, errNo int64, errMsg string, debugNo int64, debugMsg string) RouteHandlerResult {
	errInfo := ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errMsg,
		DebugNumber:  debugNo,
		DebugMessage: debugMsg,
	}
	return ctx.MakeRouteHandlerResultErrorInfo(code, errInfo)
}
func (ctx *Context) MakeRouteHandlerResultErrorInfo(code int, errInfo ErrorInfo) RouteHandlerResult {
	rerr := NewRouteError(code, errInfo)
	return RouteHandlerResult{rerr, nil, nil}
}

func (ctx *Context) MakeRouteHandlerResultAlert(code int, errNo int64, alert string) RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendErrorPayload(innerCtx, code, ErrorInfo{ErrorNumber: errNo}, alert)
	})
}
func (ctx *Context) MakeRouteHandlerResultPayloads(payloads ...Payload) RouteHandlerResult {
	return RouteHandlerResult{nil, MakePayloadMapFromPayloads(payloads...), nil}
}
func (ctx *Context) MakeRouteHandlerResultGenericJSON(v interface{}) RouteHandlerResult {
	return ctx.MakeRouteHandlerResultStatusGenericJSON(http.StatusOK, v)
}
func (ctx *Context) MakeRouteHandlerResultStatusGenericJSON(statusCode int, v interface{}) RouteHandlerResult {
	jsonBytes, err := json.Marshal(v)
	if err != nil {
		rerr := NewRouteError(
			http.StatusInternalServerError,
			ErrorInfo{
				ErrorNumber:  3913952842,
				ErrorMessage: "Internal Server Error",
			})
		return RouteHandlerResult{rerr, nil, nil}
	} else {
		return RouteHandlerResult{nil, nil, func(innerCtx *Context) {
			if rw, isResponseWriter := innerCtx.w.(http.ResponseWriter); isResponseWriter {
				rw.WriteHeader(statusCode)
				if len(jsonBytes) == 0 {
					log.Println("jsonBytes", jsonBytes, innerCtx.Req.URL)
				}
				bytesWritten, err := rw.Write(jsonBytes)
				if err != nil {
					log.Println("3952513088 WRITE ERROR", err)
				}
				innerCtx.ContentLength = bytesWritten
			}
		}}
	}
}
func (ctx *Context) MakeRouteHandlerResultCustom(crr CustomRouteResponse) RouteHandlerResult {
	return RouteHandlerResult{nil, nil, crr}
}
func (ctx *Context) MakeRouteHandlerResultOk() RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendOkPayload(innerCtx)
	})
}
func (ctx *Context) MakeRouteHandlerResultNotFound(errNo int64) RouteHandlerResult {
	return ctx.MakeRouteHandlerResultCustom(func(innerCtx *Context) {
		sendNotFoundPayload(innerCtx, errNo)
	})
}

//  #####
// #     # #    #  ####  #####  ####  #    #
// #       #    # #        #   #    # ##  ##
// #       #    #  ####    #   #    # # ## #
// #       #    #      #   #   #    # #    #
// #     # #    # #    #   #   #    # #    #
//  #####   ####   ####    #    ####  #    #
//
// ######
// #     # ######  ####  #    # #      #####  ####
// #     # #      #      #    # #        #   #
// ######  #####   ####  #    # #        #    ####
// #   #   #           # #    # #        #        #
// #    #  #      #    # #    # #        #   #    #
// #     # ######  ####   ####  ######   #    ####
//

func (ctx *Context) WrapAndSendPayload(payload Payload) {
	if payload == nil {
		ctx.SendSimpleErrorPayload(http.StatusInternalServerError, 388359273, "")
		return
	}
	wrapAndSendPayload(ctx, payload)
}

// for a slice of Entities
func (ctx *Context) WrapAndSendPayloadsList(payloadList []Payload) {
	wrapAndSendPayloadsList(ctx, payloadList)
}

// for a map of slices of Entities
func (ctx *Context) WrapAndSendPayloadsMap(payloads PayloadsMap) {
	wrapAndSendPayloadsMap(ctx, payloads)
}

// Error
func (ctx *Context) SendSimpleErrorPayload(code int, errNo int64, errorMsg string) {
	ctx.SendErrorInfoPayload(code, ErrorInfo{
		ErrorNumber:  errNo,
		ErrorMessage: errorMsg,
	})
}
func (ctx *Context) SendErrorInfoPayload(code int, errInfo ErrorInfo) {
	enduserErrMsg := errInfo.ErrorMessage
	if len(enduserErrMsg) == 0 {
		enduserErrMsg = http.StatusText(code)
	}
	sendErrorPayload(ctx, code, errInfo, "")
}

// Alert payloads are designed as a general notification service for clients (ie client must upgrade, server is in maint mode, etc.)
func (ctx *Context) SendSimpleAlertPayload(code int, errNo int64, errMsg, alert string) {
	sendErrorPayload(ctx, code, ErrorInfo{ErrorNumber: errNo, ErrorMessage: errMsg}, alert)
}

func (ctx *Context) DecodeResponseBodyOrSendError(pc PayloadController, payloadReference interface{}) interface{} {
	requestBody := ctx.Req.Body
	if requestBody == nil {
		errMsg := BadRequestPrefix + ": Expected non-empty body"
		ctx.SendSimpleErrorPayload(http.StatusBadRequest, 3003399819, errMsg)
		return nil
	}
	defer requestBody.Close()

	decoder := json.NewDecoder(requestBody)
	err := decoder.Decode(payloadReference)

	if err != nil {
		errMsg := BadRequestPrefix + ": Cannot parse body"
		derr := deeperror.New(3005488054, errMsg, err)
		log.Println("derr", derr)
		ctx.SendSimpleErrorPayload(http.StatusBadRequest, derr.Num, errMsg)
		return nil
	}

	return payloadReference
}
<|endoftext|>


<commit_before>package echo

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"mime/multipart"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

type (
	// Context represents the context of the current HTTP request. It holds request and
	// response objects, path, path parameters, data and registered handler.
	Context interface {
		// Request returns `*http.Request`.
		Request() *http.Request

		// SetRequest sets `*http.Request`.
		SetRequest(*http.Request)

		// Request returns `*Response`.
		Response() *Response

		// IsTLS returns true if HTTP connection is TLS otherwise false.
		IsTLS() bool

		// Scheme returns the HTTP protocol scheme, `http` or `https`.
		Scheme() string

		// RealIP returns the client's network address based on `X-Forwarded-For`
		// or `X-Real-IP` request header.
		RealIP() string

		// Path returns the registered path for the handler.
		Path() string

		// SetPath sets the registered path for the handler.
		SetPath(string)

		// Param returns path parameter by name.
		Param(string) string

		// ParamNames returns path parameter names.
		ParamNames() []string

		// SetParamNames sets path parameter names.
		SetParamNames(...string)

		// ParamValues returns path parameter values.
		ParamValues() []string

		// SetParamValues sets path parameter values.
		SetParamValues(...string)

		// QueryParam returns the query param for the provided name.
		QueryParam(string) string

		// QueryParams returns the query parameters as `url.Values`.
		QueryParams() url.Values

		// QueryString returns the URL query string.
		QueryString() string

		// FormValue returns the form field value for the provided name.
		FormValue(string) string

		// FormParams returns the form parameters as `url.Values`.
		FormParams() (url.Values, error)

		// FormFile returns the multipart form file for the provided name.
		FormFile(string) (*multipart.FileHeader, error)

		// MultipartForm returns the multipart form.
		MultipartForm() (*multipart.Form, error)

		// Cookie returns the named cookie provided in the request.
		Cookie(string) (*http.Cookie, error)

		// SetCookie adds a `Set-Cookie` header in HTTP response.
		SetCookie(*http.Cookie)

		// Cookies returns the HTTP cookies sent with the request.
		Cookies() []*http.Cookie

		// Get retrieves data from the context.
		Get(string) interface{}

		// Set saves data in the context.
		Set(string, interface{})

		// Bind binds the request body into provided type `i`. The default binder
		// does it based on Content-Type header.
		Bind(interface{}) error

		// Render renders a template with data and sends a text/html response with status
		// code. Templates can be registered using `Echo.Renderer`.
		Render(int, string, interface{}) error

		// HTML sends an HTTP response with status code.
		HTML(int, string) error

		// String sends a string response with status code.
		String(int, string) error

		// JSON sends a JSON response with status code.
		JSON(int, interface{}) error

		// JSONBlob sends a JSON blob response with status code.
		JSONBlob(int, []byte) error

		// JSONP sends a JSONP response with status code. It uses `callback` to construct
		// the JSONP payload.
		JSONP(int, string, interface{}) error

		// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
		// to construct the JSONP payload.
		JSONPBlob(int, string, []byte) error

		// XML sends an XML response with status code.
		XML(int, interface{}) error

		// XMLBlob sends a XML blob response with status code.
		XMLBlob(int, []byte) error

		// Blob sends a blob response with status code and content type.
		Blob(int, string, []byte) error

		// Stream sends a streaming response with status code and content type.
		Stream(int, string, io.Reader) error

		// File sends a response with the content of the file.
		File(string) error

		// Attachment sends a response as attachment, prompting client to save the
		// file.
		Attachment(string, string) error

		// Inline sends a response as inline, opening the file in the browser.
		Inline(string, string) error

		// NoContent sends a response with no body and a status code.
		NoContent(int) error

		// Redirect redirects the request with status code.
		Redirect(int, string) error

		// Error invokes the registered HTTP error handler. Generally used by middleware.
		Error(err error)

		// Handler returns the matched handler by router.
		Handler() HandlerFunc

		// SetHandler sets the matched handler by router.
		SetHandler(HandlerFunc)

		// Logger returns the `Logger` instance.
		Logger() Logger

		// Echo returns the `Echo` instance.
		Echo() *Echo

		// Reset resets the context after request completes. It must be called along
		// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
		// See `Echo#ServeHTTP()`
		Reset(*http.Request, http.ResponseWriter)
	}

	context struct {
		request  *http.Request
		response *Response
		path     string
		pnames   []string
		pvalues  []string
		query    url.Values
		handler  HandlerFunc
		store    Map
		echo     *Echo
	}
)

const (
	defaultMemory = 32 << 20 // 32 MB
	indexPage     = "index.html"
)

func (c *context) Request() *http.Request {
	return c.request
}

func (c *context) SetRequest(r *http.Request) {
	c.request = r
}

func (c *context) Response() *Response {
	return c.response
}

func (c *context) IsTLS() bool {
	return c.request.TLS != nil
}

func (c *context) Scheme() string {
	// Can't use `r.Request.URL.Scheme`
	// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
	if c.IsTLS() {
		return "https"
	}
	return "http"
}

func (c *context) RealIP() string {
	ra := c.request.RemoteAddr
	if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
		ra = ip
	} else if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
		ra = ip
	} else {
		ra, _, _ = net.SplitHostPort(ra)
	}
	return ra
}

func (c *context) Path() string {
	return c.path
}

func (c *context) SetPath(p string) {
	c.path = p
}

func (c *context) Param(name string) string {
	for i, n := range c.pnames {
		if i < len(c.pnames) {
			if strings.HasPrefix(n, name) {
				return c.pvalues[i]
			}

			// Param name with aliases
			for _, p := range strings.Split(n, ",") {
				if p == name {
					return c.pvalues[i]
				}
			}
		}
	}
	return ""
}

func (c *context) ParamNames() []string {
	return c.pnames
}

func (c *context) SetParamNames(names ...string) {
	c.pnames = names
}

func (c *context) ParamValues() []string {
	return c.pvalues
}

func (c *context) SetParamValues(values ...string) {
	c.pvalues = values
}

func (c *context) QueryParam(name string) string {
	if c.query == nil {
		c.query = c.request.URL.Query()
	}
	return c.query.Get(name)
}

func (c *context) QueryParams() url.Values {
	if c.query == nil {
		c.query = c.request.URL.Query()
	}
	return c.query
}

func (c *context) QueryString() string {
	return c.request.URL.RawQuery
}

func (c *context) FormValue(name string) string {
	return c.request.FormValue(name)
}

func (c *context) FormParams() (url.Values, error) {
	if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
		if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
			return nil, err
		}
	} else {
		if err := c.request.ParseForm(); err != nil {
			return nil, err
		}
	}
	return c.request.Form, nil
}

func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
	_, fh, err := c.request.FormFile(name)
	return fh, err
}

func (c *context) MultipartForm() (*multipart.Form, error) {
	err := c.request.ParseMultipartForm(defaultMemory)
	return c.request.MultipartForm, err
}

func (c *context) Cookie(name string) (*http.Cookie, error) {
	return c.request.Cookie(name)
}

func (c *context) SetCookie(cookie *http.Cookie) {
	http.SetCookie(c.Response(), cookie)
}

func (c *context) Cookies() []*http.Cookie {
	return c.request.Cookies()
}

func (c *context) Set(key string, val interface{}) {
	if c.store == nil {
		c.store = make(Map)
	}
	c.store[key] = val
}

func (c *context) Get(key string) interface{} {
	return c.store[key]
}

func (c *context) Bind(i interface{}) error {
	return c.echo.Binder.Bind(i, c)
}

func (c *context) Render(code int, name string, data interface{}) (err error) {
	if c.echo.Renderer == nil {
		return ErrRendererNotRegistered
	}
	buf := new(bytes.Buffer)
	if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
		return
	}
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(buf.Bytes())
	return
}

func (c *context) HTML(code int, html string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(html))
	return
}

func (c *context) String(code int, s string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(s))
	return
}

func (c *context) JSON(code int, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if c.echo.Debug {
		b, err = json.MarshalIndent(i, "", "  ")
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
}

func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	return c.JSONPBlob(code, callback, b)
}

func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(callback + "(")); err != nil {
		return
	}
	if _, err = c.response.Write(b); err != nil {
		return
	}
	_, err = c.response.Write([]byte(");"))
	return
}

func (c *context) XML(code int, i interface{}) (err error) {
	b, err := xml.Marshal(i)
	if c.echo.Debug {
		b, err = xml.MarshalIndent(i, "", "  ")
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(code, b)
}

func (c *context) XMLBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.response.Write(b)
	return
}

func (c *context) Blob(code int, contentType string, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, contentType)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
	c.response.Header().Set(HeaderContentType, contentType)
	c.response.WriteHeader(code)
	_, err = io.Copy(c.response, r)
	return
}

func (c *context) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, indexPage)
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		defer f.Close()
		if fi, err = f.Stat(); err != nil {
			return err
		}
	}
	http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
	return nil
}

func (c *context) Attachment(file, name string) (err error) {
	return c.contentDisposition(file, name, "attachment")
}

func (c *context) Inline(file, name string) (err error) {
	return c.contentDisposition(file, name, "inline")
}

func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
	c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%s", dispositionType, name))
	c.File(file)
	return
}

func (c *context) NoContent(code int) error {
	c.response.WriteHeader(code)
	return nil
}

func (c *context) Redirect(code int, url string) error {
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.response.Header().Set(HeaderLocation, url)
	c.response.WriteHeader(code)
	return nil
}

func (c *context) Error(err error) {
	c.echo.HTTPErrorHandler(err, c)
}

func (c *context) Echo() *Echo {
	return c.echo
}

func (c *context) Handler() HandlerFunc {
	return c.handler
}

func (c *context) SetHandler(h HandlerFunc) {
	c.handler = h
}

func (c *context) Logger() Logger {
	return c.echo.Logger
}

func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
	c.query = nil
	c.store = nil
	c.request = r
	c.response.reset(w)
	c.handler = NotFoundHandler
}
<commit_msg>cleaner Context#Param<commit_after>package echo

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"mime/multipart"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

type (
	// Context represents the context of the current HTTP request. It holds request and
	// response objects, path, path parameters, data and registered handler.
	Context interface {
		// Request returns `*http.Request`.
		Request() *http.Request

		// SetRequest sets `*http.Request`.
		SetRequest(*http.Request)

		// Request returns `*Response`.
		Response() *Response

		// IsTLS returns true if HTTP connection is TLS otherwise false.
		IsTLS() bool

		// Scheme returns the HTTP protocol scheme, `http` or `https`.
		Scheme() string

		// RealIP returns the client's network address based on `X-Forwarded-For`
		// or `X-Real-IP` request header.
		RealIP() string

		// Path returns the registered path for the handler.
		Path() string

		// SetPath sets the registered path for the handler.
		SetPath(string)

		// Param returns path parameter by name.
		Param(string) string

		// ParamNames returns path parameter names.
		ParamNames() []string

		// SetParamNames sets path parameter names.
		SetParamNames(...string)

		// ParamValues returns path parameter values.
		ParamValues() []string

		// SetParamValues sets path parameter values.
		SetParamValues(...string)

		// QueryParam returns the query param for the provided name.
		QueryParam(string) string

		// QueryParams returns the query parameters as `url.Values`.
		QueryParams() url.Values

		// QueryString returns the URL query string.
		QueryString() string

		// FormValue returns the form field value for the provided name.
		FormValue(string) string

		// FormParams returns the form parameters as `url.Values`.
		FormParams() (url.Values, error)

		// FormFile returns the multipart form file for the provided name.
		FormFile(string) (*multipart.FileHeader, error)

		// MultipartForm returns the multipart form.
		MultipartForm() (*multipart.Form, error)

		// Cookie returns the named cookie provided in the request.
		Cookie(string) (*http.Cookie, error)

		// SetCookie adds a `Set-Cookie` header in HTTP response.
		SetCookie(*http.Cookie)

		// Cookies returns the HTTP cookies sent with the request.
		Cookies() []*http.Cookie

		// Get retrieves data from the context.
		Get(string) interface{}

		// Set saves data in the context.
		Set(string, interface{})

		// Bind binds the request body into provided type `i`. The default binder
		// does it based on Content-Type header.
		Bind(interface{}) error

		// Render renders a template with data and sends a text/html response with status
		// code. Templates can be registered using `Echo.Renderer`.
		Render(int, string, interface{}) error

		// HTML sends an HTTP response with status code.
		HTML(int, string) error

		// String sends a string response with status code.
		String(int, string) error

		// JSON sends a JSON response with status code.
		JSON(int, interface{}) error

		// JSONBlob sends a JSON blob response with status code.
		JSONBlob(int, []byte) error

		// JSONP sends a JSONP response with status code. It uses `callback` to construct
		// the JSONP payload.
		JSONP(int, string, interface{}) error

		// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
		// to construct the JSONP payload.
		JSONPBlob(int, string, []byte) error

		// XML sends an XML response with status code.
		XML(int, interface{}) error

		// XMLBlob sends a XML blob response with status code.
		XMLBlob(int, []byte) error

		// Blob sends a blob response with status code and content type.
		Blob(int, string, []byte) error

		// Stream sends a streaming response with status code and content type.
		Stream(int, string, io.Reader) error

		// File sends a response with the content of the file.
		File(string) error

		// Attachment sends a response as attachment, prompting client to save the
		// file.
		Attachment(string, string) error

		// Inline sends a response as inline, opening the file in the browser.
		Inline(string, string) error

		// NoContent sends a response with no body and a status code.
		NoContent(int) error

		// Redirect redirects the request with status code.
		Redirect(int, string) error

		// Error invokes the registered HTTP error handler. Generally used by middleware.
		Error(err error)

		// Handler returns the matched handler by router.
		Handler() HandlerFunc

		// SetHandler sets the matched handler by router.
		SetHandler(HandlerFunc)

		// Logger returns the `Logger` instance.
		Logger() Logger

		// Echo returns the `Echo` instance.
		Echo() *Echo

		// Reset resets the context after request completes. It must be called along
		// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
		// See `Echo#ServeHTTP()`
		Reset(*http.Request, http.ResponseWriter)
	}

	context struct {
		request  *http.Request
		response *Response
		path     string
		pnames   []string
		pvalues  []string
		query    url.Values
		handler  HandlerFunc
		store    Map
		echo     *Echo
	}
)

const (
	defaultMemory = 32 << 20 // 32 MB
	indexPage     = "index.html"
)

func (c *context) Request() *http.Request {
	return c.request
}

func (c *context) SetRequest(r *http.Request) {
	c.request = r
}

func (c *context) Response() *Response {
	return c.response
}

func (c *context) IsTLS() bool {
	return c.request.TLS != nil
}

func (c *context) Scheme() string {
	// Can't use `r.Request.URL.Scheme`
	// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
	if c.IsTLS() {
		return "https"
	}
	return "http"
}

func (c *context) RealIP() string {
	ra := c.request.RemoteAddr
	if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
		ra = ip
	} else if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
		ra = ip
	} else {
		ra, _, _ = net.SplitHostPort(ra)
	}
	return ra
}

func (c *context) Path() string {
	return c.path
}

func (c *context) SetPath(p string) {
	c.path = p
}

func (c *context) Param(name string) string {
	for i, n := range c.pnames {
		if i < len(c.pnames) {
			if n == name {
				return c.pvalues[i]
			}

			// Param name with aliases
			for _, p := range strings.Split(n, ",") {
				if p == name {
					return c.pvalues[i]
				}
			}
		}
	}
	return ""
}

func (c *context) ParamNames() []string {
	return c.pnames
}

func (c *context) SetParamNames(names ...string) {
	c.pnames = names
}

func (c *context) ParamValues() []string {
	return c.pvalues
}

func (c *context) SetParamValues(values ...string) {
	c.pvalues = values
}

func (c *context) QueryParam(name string) string {
	if c.query == nil {
		c.query = c.request.URL.Query()
	}
	return c.query.Get(name)
}

func (c *context) QueryParams() url.Values {
	if c.query == nil {
		c.query = c.request.URL.Query()
	}
	return c.query
}

func (c *context) QueryString() string {
	return c.request.URL.RawQuery
}

func (c *context) FormValue(name string) string {
	return c.request.FormValue(name)
}

func (c *context) FormParams() (url.Values, error) {
	if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
		if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
			return nil, err
		}
	} else {
		if err := c.request.ParseForm(); err != nil {
			return nil, err
		}
	}
	return c.request.Form, nil
}

func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
	_, fh, err := c.request.FormFile(name)
	return fh, err
}

func (c *context) MultipartForm() (*multipart.Form, error) {
	err := c.request.ParseMultipartForm(defaultMemory)
	return c.request.MultipartForm, err
}

func (c *context) Cookie(name string) (*http.Cookie, error) {
	return c.request.Cookie(name)
}

func (c *context) SetCookie(cookie *http.Cookie) {
	http.SetCookie(c.Response(), cookie)
}

func (c *context) Cookies() []*http.Cookie {
	return c.request.Cookies()
}

func (c *context) Set(key string, val interface{}) {
	if c.store == nil {
		c.store = make(Map)
	}
	c.store[key] = val
}

func (c *context) Get(key string) interface{} {
	return c.store[key]
}

func (c *context) Bind(i interface{}) error {
	return c.echo.Binder.Bind(i, c)
}

func (c *context) Render(code int, name string, data interface{}) (err error) {
	if c.echo.Renderer == nil {
		return ErrRendererNotRegistered
	}
	buf := new(bytes.Buffer)
	if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
		return
	}
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write(buf.Bytes())
	return
}

func (c *context) HTML(code int, html string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(html))
	return
}

func (c *context) String(code int, s string) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	c.response.WriteHeader(code)
	_, err = c.response.Write([]byte(s))
	return
}

func (c *context) JSON(code int, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if c.echo.Debug {
		b, err = json.MarshalIndent(i, "", "  ")
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
}

func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	return c.JSONPBlob(code, callback, b)
}

func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(callback + "(")); err != nil {
		return
	}
	if _, err = c.response.Write(b); err != nil {
		return
	}
	_, err = c.response.Write([]byte(");"))
	return
}

func (c *context) XML(code int, i interface{}) (err error) {
	b, err := xml.Marshal(i)
	if c.echo.Debug {
		b, err = xml.MarshalIndent(i, "", "  ")
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(code, b)
}

func (c *context) XMLBlob(code int, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	c.response.WriteHeader(code)
	if _, err = c.response.Write([]byte(xml.Header)); err != nil {
		return
	}
	_, err = c.response.Write(b)
	return
}

func (c *context) Blob(code int, contentType string, b []byte) (err error) {
	c.response.Header().Set(HeaderContentType, contentType)
	c.response.WriteHeader(code)
	_, err = c.response.Write(b)
	return
}

func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
	c.response.Header().Set(HeaderContentType, contentType)
	c.response.WriteHeader(code)
	_, err = io.Copy(c.response, r)
	return
}

func (c *context) File(file string) error {
	f, err := os.Open(file)
	if err != nil {
		return ErrNotFound
	}
	defer f.Close()

	fi, _ := f.Stat()
	if fi.IsDir() {
		file = filepath.Join(file, indexPage)
		f, err = os.Open(file)
		if err != nil {
			return ErrNotFound
		}
		defer f.Close()
		if fi, err = f.Stat(); err != nil {
			return err
		}
	}
	http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
	return nil
}

func (c *context) Attachment(file, name string) (err error) {
	return c.contentDisposition(file, name, "attachment")
}

func (c *context) Inline(file, name string) (err error) {
	return c.contentDisposition(file, name, "inline")
}

func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
	c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%s", dispositionType, name))
	c.File(file)
	return
}

func (c *context) NoContent(code int) error {
	c.response.WriteHeader(code)
	return nil
}

func (c *context) Redirect(code int, url string) error {
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	c.response.Header().Set(HeaderLocation, url)
	c.response.WriteHeader(code)
	return nil
}

func (c *context) Error(err error) {
	c.echo.HTTPErrorHandler(err, c)
}

func (c *context) Echo() *Echo {
	return c.echo
}

func (c *context) Handler() HandlerFunc {
	return c.handler
}

func (c *context) SetHandler(h HandlerFunc) {
	c.handler = h
}

func (c *context) Logger() Logger {
	return c.echo.Logger
}

func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
	c.query = nil
	c.store = nil
	c.request = r
	c.response.reset(w)
	c.handler = NotFoundHandler
}
<|endoftext|>


<commit_before>package stash

import (
	"fmt"
)

type Project struct {
	Key string `"json:key"`
}

type Repo struct {
	Name    string `"json:name"`
	Slug    string `"json:slug"`
	Project *Project
}

type RepoResource struct {
	client *Client
}

// Get the named repository
func (r *RepoResource) Find(project, slug string) (*Repo, error) {
	repo := Repo{}
	path := fmt.Sprintf("/projects/%s/repos/%s", project, slug)

	if err := r.client.do("GET", path, nil, nil, &repo); err != nil {
		return nil, err
	}

	return &repo, nil
}

// Enable hook for named repository
func (r *RepoResource) CreateHook(project, slug, hook string) (*Repo, error) {
	repo := Repo{}
	path := fmt.Sprintf("/projects/%s/repos/%s/settings/hooks/%s/enabled",
		project, slug, hook)

	if err := r.clent.do("GET", path, nil, nil&repo); err != nil {
		return nil, err
	}

	return &repo, nil
}
<commit_msg>fixed parse errors<commit_after>package stash

import (
	"fmt"
)

type Project struct {
	Key string `"json:key"`
}

type Repo struct {
	Name    string `"json:name"`
	Slug    string `"json:slug"`
	Project *Project
}

type RepoResource struct {
	client *Client
}

// Get the named repository
func (r *RepoResource) Find(project, slug string) (*Repo, error) {
	repo := Repo{}
	path := fmt.Sprintf("/projects/%s/repos/%s", project, slug)

	if err := r.client.do("GET", path, nil, nil, &repo); err != nil {
		return nil, err
	}

	return &repo, nil
}

// Enable hook for named repository
func (r *RepoResource) CreateHook(project, slug, hook string) (*Repo, error) {
	repo := Repo{}
	path := fmt.Sprintf("/projects/%s/repos/%s/settings/hooks/%s/enabled",
		project, slug, hook)

	if err := r.client.do("GET", path, nil, nil, &repo); err != nil {
		return nil, err
	}

	return &repo, nil
}
<|endoftext|>


<commit_before>//
package contour

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/BurntSushi/toml"
	utils "github.com/mohae/utilitybelt"
)

// Environment Variable constants for common environment variables.
// Or you can supply your own values. Contour automatically downcases
// environment variables for consistency across formats.
var (
	EnvConfigFilename string = "configfilename"
	EnvConfigFormat string = "configformat"
	EnvLogFilename string = "logfilename"
	EnvLogging string = "logging"
)

// settingAlias are aliases to settings, each setting is its own alias.
var settingAlias map[string]string = make(map[string]string)

// commandAlias are aliases to commands, each command is its own alias.
var commandAlias map[string]string = make(map[string]string)

// configFile holds the contents of the configuration file
var configFile map[string]interface{} = make(map[string]interface{})

// config holds the current application configuration
var AppConfig *Config = &Config{Settings: map[string]*setting{}}

const (
	SettingNotFoundErr = " setting was not found"
)

// Config is a group of settings and holds all of the application setting
// information. Even though contour automatically uses environment variables,
// unless its told to ignore them, it still needs to maintain state
// information about each setting so it knows how to handle attempst to update.
// TODO:
//	* support ignoring environment variables
//
type Config struct {

	// code is the shortcode for this configuration. It is mostly used to
	// prefix environment variables, when used.
	code 	string
	Settings 	map[string]*setting
}

// GetAppConfig returns the AppConfig to the caller. Any contour function
// called uses this config.
func GetAppConfig() *Config {
	return AppConfig
}

// NewConfig returns a *Config to the caller. Any config created by NewConfig()
// is independent of the AppConfig
func NewConfig() *Config {
	return &Config{Settings: map[string]*setting{}}
}

func (c *Config) GetCode() string {
	return c.code
}

// SetAppCode set's the appcode. This can only be done once. If it is already
// set, it will return an error.
func (c *Config) SetCode(s string) error {
	if c.code != "" {
		return errors.New("appCode is already set. AppCode is idempotent. Once set, it cannot be altered")
	}

	c.code = s

	return nil
}

// setting holds the information for a configuration setting.
type setting struct {
	// Code of the setting
	Code string

	// Type is the datatype for the setting
	Type string

	// The current value of the setting
	Value interface{}

	// IsFlag:  whether or not this is a flag.
	IsFlag bool

	// IsIdempotent: whether or not this value can be overwritten once set.
	IsIdempotent bool

	// SourceIsEnv: whether or not the original source of this setting was
	// its environment variables, vs. flags or config, etc. This is tracked
	// because it has implications on override behavior.
	SourceIsEnv bool

	// IsCore: whether or not this is considered a core setting. Core
	// settings if for things like application name, where you don't want
	// anything else overwriting that value, once set, and you want to be
	// able to overwrite any existing ENV value if contour hasn't already
	// set it. Once set, IsIdempotent is also true.
	IsCore bool
}

// getConfigFormat gets the configured config filename and returns the format
// it is in, if it is a supported format; otherwise an error.
func getConfigFormat() (string, error) {
	// If the format is already set, we don't override the setting.
	// A nil is returned because this is not an error.
	format := os.Getenv(EnvConfigFormat)
	if format != "" {
		// See if the set format is supported, if it is,
		if isSupportedFormat(format) {
			return format, nil
		}
	}

	// Format is either unknown, or not supported; try to resolve it.
	fname := os.Getenv(EnvConfigFilename)
	if fname == "" {
		return "", errors.New("unable to determine config format, filename not set")
	}

	parts := strings.Split(fname, ".")

	// case 0 has already been evaluated
	switch len(parts) {
	case 1:
		return "", errors.New("unable to determine config format, the configuration file " + fname + " doesn't have an extension")
	case 2:
		format = parts[1]
	default:
		// assume its the last part
		format = parts[len(parts) - 1]
	}

	if isSupportedFormat(format) {
		return "", errors.New(format + " is an unsupported format for configuration files")
	}

	return format, nil

}

// isSupportedFormat checks to see if the passed string represents a supported
// config format.
func isSupportedFormat(s string) bool {
        switch s {
        case "json":
                return true
	case "toml":
                return true
        default:
                return  false
        }

        return false
}

// SetFromEnv updates the configuration from the environment variable values.
// A setting is only updated if it IsUpdateable.
func SetFromEnv() {
	for k, _ := range AppConfig.Settings {
		// See if k exists as an env variable
		v := os.Getenv(k)
		if v == "" {
			continue
		}

		// Only core and idempotent are updateable
		if !CanSetUsingEnv(k) {
			continue
		}

		// Gotten this far, set it
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].SourceIsEnv = true
	}

}

// SetFromConfigFile populates configFile from the configured config file.
// The config file entries are then processed, updating their associated
// settings. A setting is only updated if it IsUpdateable.
func SetFromConfigFile() error {
	// ConfigFile should be set and its format type should be known.
	err := LoadConfigFile()
	if err != nil {
		return err
	}

	// ProcessConfigFile, setting what's appropriate.
	for k, v := range configFile {
		// Find the key in the settings
		_, ok := AppConfig.Settings[k]
		if !ok {
			// skip settings that don't already exist
			continue
		}

		// Skip if IsIdempotent, IsCore, SourceIsEnv since they aren't
		// overridable by ConfigFile.
		if !IsUpdateable(k) {
			continue
		}

		// Update the setting with file's
		Update(k, v)
	}

	return nil
}

// LoadConfigFile() is the entry point for reading the configuration file.
func LoadConfigFile() error {
	n := os.Getenv(EnvConfigFilename)
	if n == "" {
		// This isn't an error as config file is allowed to not exist
		// TODO:
		//	Possible add a ConfigFileRequired flag
		//	Add logging support
		return nil
	}

	fBytes, err := readConfigFile(n)
	if err != nil {
		return err
	}

	err = MarshalFormatReader(os.Getenv(EnvConfigFormat),bytes.NewReader(fBytes))
	if err != nil {
		return err
	}

	return nil
}

// readConfigFile reads the configFile
func readConfigFile(n string) ([]byte, error) {
	cfg, err := ioutil.ReadFile(n)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

// MarshalFormatReader
func MarshalFormatReader(t string, r io.Reader) error {
	b := new(bytes.Buffer)
	b.ReadFrom(r)

	switch t{
	case "json":
		err := json.Unmarshal(b.Bytes(), &configFile)
		if err != nil {
			return err
		}

	case "toml":
		_, err := toml.Decode(b.String(), &configFile)
		if err != nil {
			return err
		}

	}
	return nil
}

// SetIdempotentString sets the value of idempotent configuration settings
// that are strings.
func SetIdempotentString(k, v string) error {
	// see if the key already exists, if it does, it can't be set
	_, ok := AppConfig.Settings[k]
	if ok {
		return nil
	}

	// Set the environment variable for it
	err := os.Setenv(k, v)
	if err != nil {
		return err
	}

	AppConfig.Settings[k] = &setting{Type: "string",  Value: v, IsIdempotent: true}

	return nil
}

// SetIdemString is a convenience function that wraps SetIdempotentString()
func SetIdemString(k, v string) {
	SetIdempotentString(k, v)
}

// SetBoolFlag sets the value of a configuration setting that is also a flag.
func SetBoolFlag(k, f string, v bool) {
	// see if the key exists
	_, ok := AppConfig.Settings[k]
	if ok {
		// see if it can be set
		if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv {
			return
		}

		// replace current settings with new
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].IsFlag = true
		AppConfig.Settings[k].Code = f
		return
	}

	// otherwise add it
	s := utils.BoolToString(v)
	os.Setenv(AppConfig.GetCode() + k, s)
	AppConfig.Settings[k] = &setting{Value: v, Code: f, IsFlag: true}
}

// SetStringFlag sets the value of a configuration setting that is also a flag.
func SetStringFlag(k, f string, v string) {
	// see if the key exists
	_, ok := AppConfig.Settings[k]
	if ok {
		// see if it can be set
		if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv || AppConfig.Settings[k].IsCore {
			return
		}

		// replace current settings with new
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].IsFlag = true
		AppConfig.Settings[k].Code = f
		return
	}

	// otherwise add it
	os.Setenv(AppConfig.GetCode() + k, v)
	AppConfig.Settings[k] = &setting{Value: v, Code: f, IsFlag: true}
}

// Update updates the passed key with the passed value.
func Update(k string, v interface{}) error {
	if !IsUpdateable(k) {
		return nil
	}

	err := os.Setenv(AppConfig.GetCode() + k, v.(string))
	if err != nil {
		return err
	}

	set(k, v)

	return nil
}

func set(k string, v interface{}) {
	// Cast according to type for this key
	switch AppConfig.Settings[k].Type {
	case "string":
		AppConfig.Settings[k].Value = v.(string)

	case "bool":
		AppConfig.Settings[k].Value = v.(bool)

	case "int", "int8", "int16", "int32", "int64":
		AppConfig.Settings[k].Value = v.(int)

	default:
		AppConfig.Settings[k].Value = v
	}
}

// IsUpdateable checks to see if the passed setting key is updateable.
func IsUpdateable(k string) bool {
	// See if the key exists, if it doesn't already exist, it can't be
	// updated.
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false
	}

	// See if there are any settings that prevent it from being updated.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// Override overrides the setting, if it is overrideable. This is used to
// override any environment variable that had pre-existing values.
func Override(k string, v interface{}) error {
	if !IsOverrideable(k) {
		return nil
	}

	err := os.Setenv(AppConfig.GetCode() + k, v.(string))
	if err != nil {
		return err
	}

	// Set the new value
	set(k, v)

	return nil
}

// IsOverrideable() checks to see if the setting can be overridden. Overrides
// only come from args and flags. ConfigFile settings must be updated instead.
func IsOverrideable(k string) bool {
	// See if the key exists, if it doesn't already exist, it can't be
	// overridden
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false
	}

	// See if there are any settings that prevent it from being overridden.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// CanSetUsingEnv checks to see if the setting is settable using an env
// variable.
func CanSetUsingEnv(k string) bool {
	// If something is flagged as idempotent, it can't be set be changed.
	// Same with core settings.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// AddCommandAlias adds an alias for a command. The first time a command is
// added, it's added as an alias of itself too.
func AddCommandAlias(command, alias string) error {
	// see if an alias already exists
	v, ok := commandAlias[alias]
	if ok {
		err := errors.New(alias + " is an alias of the command " + v + " cannot make it an alias of " + command)
		return err
	}

	// see if the command already has aliases
	v, ok = commandAlias[command]
	if !ok {
		// Add it as an alias of itself first
		commandAlias[command] = command
	}

	commandAlias[alias] = command

	return nil
}

// AddSettingAlias adds an alias for a setting. The first time a setting is
// added, it's added as an alias of itself too.
func AddSettingAlias(setting, alias string) error {
	// see if an alias already exists
	v, ok := settingAlias[alias]
	if ok {
		err := errors.New(alias + " is an alias of the setting " + v + " cannot make it an alias of " + setting)
		return err
	}

	// see if the setting already has aliases
	v, ok = settingAlias[setting]
	if !ok {
		// Add it as an alias of itself first
		settingAlias[setting] = setting
	}

	settingAlias[alias] = setting

	return nil
}

// Set
// resetAppConfig resets the application's configuration struct to empty.
// This does not affect their respective environment variables
func resetAppConfig() {
	AppConfig = &Config{Settings: map[string]*setting{}}
}

func Get(k string) (interface{}, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value, nil
}

func GetBool(k string) (bool, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(bool), nil
}

func GetInt(k string) (int, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(int), nil
}

func GetString(k string) (string, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(string), nil
}

// GetInterface is a convenience wrapper function to Get
func GetInterface(k string) (interface{}, error) {
	return Get(k)
}

func notFoundErr(k string) error {
	return errors.New(k + " not found")
}
<commit_msg>added setting the value for Type, was causing panic, oops<commit_after>//
package contour

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/BurntSushi/toml"
	utils "github.com/mohae/utilitybelt"
)

// Environment Variable constants for common environment variables.
// Or you can supply your own values. Contour automatically downcases
// environment variables for consistency across formats.
var (
	EnvConfigFilename string = "configfilename"
	EnvConfigFormat string = "configformat"
	EnvLogFilename string = "logfilename"
	EnvLogging string = "logging"
)

// settingAlias are aliases to settings, each setting is its own alias.
var settingAlias map[string]string = make(map[string]string)

// commandAlias are aliases to commands, each command is its own alias.
var commandAlias map[string]string = make(map[string]string)

// configFile holds the contents of the configuration file
var configFile map[string]interface{} = make(map[string]interface{})

// config holds the current application configuration
var AppConfig *Config = &Config{Settings: map[string]*setting{}}

const (
	SettingNotFoundErr = " setting was not found"
)

// Config is a group of settings and holds all of the application setting
// information. Even though contour automatically uses environment variables,
// unless its told to ignore them, it still needs to maintain state
// information about each setting so it knows how to handle attempst to update.
// TODO:
//	* support ignoring environment variables
//
type Config struct {

	// code is the shortcode for this configuration. It is mostly used to
	// prefix environment variables, when used.
	code 	string
	Settings 	map[string]*setting
}

// GetAppConfig returns the AppConfig to the caller. Any contour function
// called uses this config.
func GetAppConfig() *Config {
	return AppConfig
}

// NewConfig returns a *Config to the caller. Any config created by NewConfig()
// is independent of the AppConfig
func NewConfig() *Config {
	return &Config{Settings: map[string]*setting{}}
}

func (c *Config) GetCode() string {
	return c.code
}

// SetAppCode set's the appcode. This can only be done once. If it is already
// set, it will return an error.
func (c *Config) SetCode(s string) error {
	if c.code != "" {
		return errors.New("appCode is already set. AppCode is idempotent. Once set, it cannot be altered")
	}

	c.code = s

	return nil
}

// setting holds the information for a configuration setting.
type setting struct {
	// Code of the setting
	Code string

	// Type is the datatype for the setting
	Type string

	// The current value of the setting
	Value interface{}

	// IsFlag:  whether or not this is a flag.
	IsFlag bool

	// IsIdempotent: whether or not this value can be overwritten once set.
	IsIdempotent bool

	// SourceIsEnv: whether or not the original source of this setting was
	// its environment variables, vs. flags or config, etc. This is tracked
	// because it has implications on override behavior.
	SourceIsEnv bool

	// IsCore: whether or not this is considered a core setting. Core
	// settings if for things like application name, where you don't want
	// anything else overwriting that value, once set, and you want to be
	// able to overwrite any existing ENV value if contour hasn't already
	// set it. Once set, IsIdempotent is also true.
	IsCore bool
}

// getConfigFormat gets the configured config filename and returns the format
// it is in, if it is a supported format; otherwise an error.
func getConfigFormat() (string, error) {
	// If the format is already set, we don't override the setting.
	// A nil is returned because this is not an error.
	format := os.Getenv(EnvConfigFormat)
	if format != "" {
		// See if the set format is supported, if it is,
		if isSupportedFormat(format) {
			return format, nil
		}
	}

	// Format is either unknown, or not supported; try to resolve it.
	fname := os.Getenv(EnvConfigFilename)
	if fname == "" {
		return "", errors.New("unable to determine config format, filename not set")
	}

	parts := strings.Split(fname, ".")

	// case 0 has already been evaluated
	switch len(parts) {
	case 1:
		return "", errors.New("unable to determine config format, the configuration file " + fname + " doesn't have an extension")
	case 2:
		format = parts[1]
	default:
		// assume its the last part
		format = parts[len(parts) - 1]
	}

	if isSupportedFormat(format) {
		return "", errors.New(format + " is an unsupported format for configuration files")
	}

	return format, nil

}

// isSupportedFormat checks to see if the passed string represents a supported
// config format.
func isSupportedFormat(s string) bool {
        switch s {
        case "json":
                return true
	case "toml":
                return true
        default:
                return  false
        }

        return false
}

// SetFromEnv updates the configuration from the environment variable values.
// A setting is only updated if it IsUpdateable.
func SetFromEnv() {
	for k, _ := range AppConfig.Settings {
		// See if k exists as an env variable
		v := os.Getenv(k)
		if v == "" {
			continue
		}

		// Only core and idempotent are updateable
		if !CanSetUsingEnv(k) {
			continue
		}

		// Gotten this far, set it
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].SourceIsEnv = true
	}

}

// SetFromConfigFile populates configFile from the configured config file.
// The config file entries are then processed, updating their associated
// settings. A setting is only updated if it IsUpdateable.
func SetFromConfigFile() error {
	// ConfigFile should be set and its format type should be known.
	err := LoadConfigFile()
	if err != nil {
		return err
	}

	// ProcessConfigFile, setting what's appropriate.
	for k, v := range configFile {
		// Find the key in the settings
		_, ok := AppConfig.Settings[k]
		if !ok {
			// skip settings that don't already exist
			continue
		}

		// Skip if IsIdempotent, IsCore, SourceIsEnv since they aren't
		// overridable by ConfigFile.
		if !IsUpdateable(k) {
			continue
		}

		// Update the setting with file's
		Update(k, v)
	}

	return nil
}

// LoadConfigFile() is the entry point for reading the configuration file.
func LoadConfigFile() error {
	n := os.Getenv(EnvConfigFilename)
	if n == "" {
		// This isn't an error as config file is allowed to not exist
		// TODO:
		//	Possible add a ConfigFileRequired flag
		//	Add logging support
		return nil
	}

	fBytes, err := readConfigFile(n)
	if err != nil {
		return err
	}

	err = MarshalFormatReader(os.Getenv(EnvConfigFormat),bytes.NewReader(fBytes))
	if err != nil {
		return err
	}

	return nil
}

// readConfigFile reads the configFile
func readConfigFile(n string) ([]byte, error) {
	cfg, err := ioutil.ReadFile(n)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

// MarshalFormatReader
func MarshalFormatReader(t string, r io.Reader) error {
	b := new(bytes.Buffer)
	b.ReadFrom(r)

	switch t{
	case "json":
		err := json.Unmarshal(b.Bytes(), &configFile)
		if err != nil {
			return err
		}

	case "toml":
		_, err := toml.Decode(b.String(), &configFile)
		if err != nil {
			return err
		}

	}
	return nil
}

// SetIdempotentString sets the value of idempotent configuration settings
// that are strings.
func SetIdempotentString(k, v string) error {
	// see if the key already exists, if it does, it can't be set
	_, ok := AppConfig.Settings[k]
	if ok {
		return nil
	}

	// Set the environment variable for it
	err := os.Setenv(k, v)
	if err != nil {
		return err
	}

	AppConfig.Settings[k] = &setting{Type: "string",  Value: v, IsIdempotent: true}

	return nil
}

// SetIdemString is a convenience function that wraps SetIdempotentString()
func SetIdemString(k, v string) {
	SetIdempotentString(k, v)
}

// SetBoolFlag sets the value of a configuration setting that is also a flag.
func SetBoolFlag(k, f string, v bool) {
	// see if the key exists
	_, ok := AppConfig.Settings[k]
	if ok {
		// see if it can be set
		if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv {
			return
		}

		// replace current settings with new
		AppConfig.Settings[k].Type = "bool"
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].IsFlag = true
		AppConfig.Settings[k].Code = f
		return
	}

	// otherwise add it
	s := utils.BoolToString(v)
	os.Setenv(AppConfig.GetCode() + k, s)
	AppConfig.Settings[k] = &setting{Type: "bool", Value: v, Code: f, IsFlag: true}
}

// SetStringFlag sets the value of a configuration setting that is also a flag.
func SetStringFlag(k, f string, v string) {
	// see if the key exists
	_, ok := AppConfig.Settings[k]
	if ok {
		// see if it can be set
		if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv || AppConfig.Settings[k].IsCore {
			return
		}

		// replace current settings with new
		AppConfig.Settings[k].Type = "string"
		AppConfig.Settings[k].Value = v
		AppConfig.Settings[k].IsFlag = true
		AppConfig.Settings[k].Code = f
		return
	}

	// otherwise add it
	os.Setenv(AppConfig.GetCode() + k, v)
	AppConfig.Settings[k] = &setting{Type: "string", Value: v, Code: f, IsFlag: true}
}

// Update updates the passed key with the passed value.
func Update(k string, v interface{}) error {
	if !IsUpdateable(k) {
		return nil
	}

	err := os.Setenv(AppConfig.GetCode() + k, v.(string))
	if err != nil {
		return err
	}

	set(k, v)

	return nil
}

func set(k string, v interface{}) {
	// Cast according to type for this key
	switch AppConfig.Settings[k].Type {
	case "string":
		AppConfig.Settings[k].Value = v.(string)

	case "bool":
		AppConfig.Settings[k].Value = v.(bool)

	case "int", "int8", "int16", "int32", "int64":
		AppConfig.Settings[k].Value = v.(int)

	default:
		AppConfig.Settings[k].Value = v
	}
}

// IsUpdateable checks to see if the passed setting key is updateable.
func IsUpdateable(k string) bool {
	// See if the key exists, if it doesn't already exist, it can't be
	// updated.
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false
	}

	// See if there are any settings that prevent it from being updated.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].SourceIsEnv || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// Override overrides the setting, if it is overrideable. This is used to
// override any environment variable that had pre-existing values.
func Override(k string, v interface{}) error {
	if !IsOverrideable(k) {
		return nil
	}

	err := os.Setenv(AppConfig.GetCode() + k, v.(string))
	if err != nil {
		return err
	}

	// Set the new value
	set(k, v)

	return nil
}

// IsOverrideable() checks to see if the setting can be overridden. Overrides
// only come from args and flags. ConfigFile settings must be updated instead.
func IsOverrideable(k string) bool {
	// See if the key exists, if it doesn't already exist, it can't be
	// overridden
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false
	}

	// See if there are any settings that prevent it from being overridden.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// CanSetUsingEnv checks to see if the setting is settable using an env
// variable.
func CanSetUsingEnv(k string) bool {
	// If something is flagged as idempotent, it can't be set be changed.
	// Same with core settings.
	if AppConfig.Settings[k].IsIdempotent || AppConfig.Settings[k].IsCore {
		return false
	}

	return true
}

// AddCommandAlias adds an alias for a command. The first time a command is
// added, it's added as an alias of itself too.
func AddCommandAlias(command, alias string) error {
	// see if an alias already exists
	v, ok := commandAlias[alias]
	if ok {
		err := errors.New(alias + " is an alias of the command " + v + " cannot make it an alias of " + command)
		return err
	}

	// see if the command already has aliases
	v, ok = commandAlias[command]
	if !ok {
		// Add it as an alias of itself first
		commandAlias[command] = command
	}

	commandAlias[alias] = command

	return nil
}

// AddSettingAlias adds an alias for a setting. The first time a setting is
// added, it's added as an alias of itself too.
func AddSettingAlias(setting, alias string) error {
	// see if an alias already exists
	v, ok := settingAlias[alias]
	if ok {
		err := errors.New(alias + " is an alias of the setting " + v + " cannot make it an alias of " + setting)
		return err
	}

	// see if the setting already has aliases
	v, ok = settingAlias[setting]
	if !ok {
		// Add it as an alias of itself first
		settingAlias[setting] = setting
	}

	settingAlias[alias] = setting

	return nil
}

// Set
// resetAppConfig resets the application's configuration struct to empty.
// This does not affect their respective environment variables
func resetAppConfig() {
	AppConfig = &Config{Settings: map[string]*setting{}}
}

func Get(k string) (interface{}, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value, nil
}

func GetBool(k string) (bool, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(bool), nil
}

func GetInt(k string) (int, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(int), nil
}

func GetString(k string) (string, error) {
	_, ok := AppConfig.Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	return AppConfig.Settings[k].Value.(string), nil
}

// GetInterface is a convenience wrapper function to Get
func GetInterface(k string) (interface{}, error) {
	return Get(k)
}

func notFoundErr(k string) error {
	return errors.New(k + " not found")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"time"
	"github.com/mapmyfitness/go-opentsdb/tsdb"
)

const (
	VERSION                 = "0.5.2-alpha"
	MAX_UNPROCESSED_PACKETS = 1000
	MAX_UDP_PACKET_SIZE     = 512
)

var signalchan chan os.Signal

type Packet struct {
	Bucket   string
	Value    interface{}
	Modifier string
	Sampling float32
}

type Uint64Slice []uint64

func (s Uint64Slice) Len() int           { return len(s) }
func (s Uint64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s Uint64Slice) Less(i, j int) bool { return s[i] < s[j] }

type Percentiles []*Percentile
type Percentile struct {
	float float64
	str   string
}

func (a *Percentiles) Set(s string) error {
	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return err
	}
	*a = append(*a, &Percentile{f, strings.Replace(s, ".", "_", -1)})
	return nil
}
func (p *Percentile) String() string {
	return p.str
}
func (a *Percentiles) String() string {
	return fmt.Sprintf("%v", *a)
}

var (
	serviceAddress   = flag.String("address", ":8125", "UDP service address")
	graphiteAddress  = flag.String("graphite", "127.0.0.1:2003", "Graphite service address (or - to disable)")
	flushInterval    = flag.Int64("flush-interval", 10, "Flush interval (seconds)")
	debug            = flag.Bool("debug", false, "print statistics sent to graphite")
	showVersion      = flag.Bool("version", false, "print version string")
	persistCountKeys = flag.Int64("persist-count-keys", 60, "number of flush-interval's to persist count keys")
	receiveCounter  = flag.String("receive-counter", "", "Metric name for total metrics recevied per interval")
	prefix           = flag.String("prefix", "stats", "Prefix of reported metrics")
	percentThreshold = Percentiles{}
	openTSDBAddress  = flag.String("opentsdb", "127.0.0.1:2003", "openTSDB service address (or - to disable)")

)

func init() {
	flag.Var(&percentThreshold, "percent-threshold", "Threshold percent (0-100, may be given multiple times)")
}

var (
	In       = make(chan *Packet, MAX_UNPROCESSED_PACKETS)
	counters = make(map[string]int64)
	gauges   = make(map[string]uint64)
	timers   = make(map[string]Uint64Slice)
)

func monitor() {
	period := time.Duration(*flushInterval) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
			return
		case <-ticker.C:
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
		case s := <-In:
			if (*receiveCounter != "") {
				v, ok := counters[*receiveCounter]
				if !ok || v < 0 {
					counters[*receiveCounter] = 0
				}
				counters[*receiveCounter] += 1
			}

			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t Uint64Slice
					timers[s.Bucket] = t
				}
				timers[s.Bucket] = append(timers[s.Bucket], s.Value.(uint64))
			} else if s.Modifier == "g" {
				gauges[s.Bucket] = s.Value.(uint64)
			} else {
				v, ok := counters[s.Bucket]
				if !ok || v < 0 {
					counters[s.Bucket] = 0
				}
				counters[s.Bucket] += int64(float64(s.Value.(int64)) * float64(1/s.Sampling))
			}
		}
	}
}

func submit(deadline time.Time) error {
	var buffer bytes.Buffer
	var num int64
	now := time.Now().Unix()
	num += processCounters(&buffer, now)
	num += processGauges(&buffer, now)
	num += processTimers(&buffer, now, percentThreshold)
	fmt.Printf("buffer: "+buffer.String()+"\n")
	fmt.Printf("num: "+string(num)+"\n")
	fmt.Printf("deadline: ")
	fmt.Printf("%v", deadline)
	fmt.Printf("\n")
	fmt.Printf("now: ")
	fmt.Printf("%v",now)
	fmt.Printf("\n")
	if *graphiteAddress!="-" {
		client, err := net.Dial("tcp", *graphiteAddress)
		if err != nil {
			if *debug {
				log.Printf("WARNING: resetting counters when in debug mode")
				processCounters(&buffer, now)
				processGauges(&buffer, now)
				processTimers(&buffer, now, percentThreshold)
			}
			errmsg := fmt.Sprintf("dialing %s failed - %s", *graphiteAddress, err)
			return errors.New(errmsg)
		}
		defer client.Close()

		err = client.SetDeadline(deadline)
		if err != nil {
			errmsg := fmt.Sprintf("could not set deadline:", err)
			return errors.New(errmsg)
		}

		if num == 0 {
			return nil
		}

		if *debug {
			for _, line := range bytes.Split(buffer.Bytes(), []byte("\n")) {
				if len(line) == 0 {
					continue
				}
				log.Printf("DEBUG: %s", line)
			}
		}

		_, err = client.Write(buffer.Bytes())
		if err != nil {
			errmsg := fmt.Sprintf("failed to write stats - %s", err)
			return errors.New(errmsg)
		}

		log.Printf("sent %d stats to %s", num, *graphiteAddress)

	}
	if(*openTSDBAddress!=""){
		datapoints:=[]tsdb.DataPoint{}//for testing
		datapoint:=tsdb.DataPoint{}
		TSDB:=tsdb.TSDB{}
		server:=tsdb.Server{}
		datapoint.Metric.Set("woohoo")
		fmt.Printf("%v",datapoint.Metric)
		datapoint.Value.Set(0.1)
		datapoint.Tags.Set("a","B")
		//datapoint.Timestamp
		server.Host="188.40.45.201"
		server.Port=uint(4242)
		datapoints=append(datapoints,datapoint)
		response,err:=TSDB.Put(datapoints)
		fmt.Printf("error, response")
		fmt.Printf("%v",err)
		fmt.Printf("%v",response)

	}
	return nil
}

func processCounters(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	var realc float64
	// continue sending zeros for counters for a short period of time even if we have no new data
	// note we use the same in-memory value to denote both the actual value of the counter (value >= 0)
	// as well as how many turns to keep the counter for (value < 0)
	// for more context see https://github.com/bitly/statsdaemon/pull/8
	for s, c := range counters {
		switch {
		case c <= *persistCountKeys:
			// consider this purgable
			delete(counters, s)
			continue
		case c < 0:
			counters[s] -= 1
			fmt.Fprintf(buffer, "%s.%s %d %d\n", *prefix, s, 0, now)
		case c >= 0:
			counters[s] = -1
			realc = float64(c)/10.0
			fmt.Fprintf(buffer, "%s.%s %.6f %d\n", *prefix, s, realc, now)
		}
		num++
	}
	return num
}

func processGauges(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for g, c := range gauges {
		if c == math.MaxUint64 {
			continue
		}
		fmt.Fprintf(buffer, "%s.%s %d %d\n", *prefix, g, c, now)
		gauges[g] = math.MaxUint64
		num++
	}
	return num
}

func processTimers(buffer *bytes.Buffer, now int64, pctls Percentiles) int64 {
	var num int64
	for u, t := range timers {
		if len(t) > 0 {
			num++

			sort.Sort(t)
			min := t[0]
			max := t[len(t)-1]
			maxAtThreshold := max
			count := len(t)

			sum := uint64(0)
			for _, value := range t {
				sum += value
			}
			mean := float64(sum) / float64(len(t))

			for _, pct := range pctls {

				if len(t) > 1 {
					var abs float64
					if pct.float >= 0 {
						abs = pct.float
					} else {
						abs = 100 + pct.float
					}
					// poor man's math.Round(x):
					// math.Floor(x + 0.5)
					indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
					if pct.float >= 0 {
						indexOfPerc -= 1 // index offset=0
					}
					maxAtThreshold = t[indexOfPerc]
				}

				var tmpl string
				var pctstr string
				if pct.float >= 0 {
					tmpl = "%s.timers.%s.upper_%s %d %d\n"
					pctstr = pct.str
				} else {
					tmpl = "%s.timers.%s.lower_%s %d %d\n"
					pctstr = pct.str[1:]
				}
				fmt.Fprintf(buffer, tmpl, *prefix, u, pctstr, maxAtThreshold, now)
			}

			var z Uint64Slice
			timers[u] = z

			fmt.Fprintf(buffer, "%s.timers.%s.mean %f %d\n", *prefix, u, mean, now)
			fmt.Fprintf(buffer, "%s.timers.%s.upper %d %d\n", *prefix, u, max, now)
			fmt.Fprintf(buffer, "%s.timers.%s.lower %d %d\n", *prefix, u, min, now)
			fmt.Fprintf(buffer, "%s.timers.%s.count %d %d\n", *prefix, u, count, now)
		}
	}
	return num
}

var packetRegexp = regexp.MustCompile("^([^:]+):(-?[0-9]+)\\.?[0-9]*\\|(g|c|ms)(\\|@([0-9\\.]+))?\n?$")

func parseMessage(data []byte) []*Packet {
	var output []*Packet
	for _, line := range bytes.Split(data, []byte("\n")) {
		if len(line) == 0 {
			continue
		}

		item := packetRegexp.FindSubmatch(line)
		if len(item) == 0 {
			continue
		}

		var err error
		var value interface{}
		modifier := string(item[3])
		switch modifier {
		case "c":
			value, err = strconv.ParseInt(string(item[2]), 10, 64)
			if err != nil {
				log.Printf("ERROR: failed to ParseInt %s - %s", item[2], err)
				continue
			}
		default:
			value, err = strconv.ParseUint(string(item[2]), 10, 64)
			if err != nil {
				log.Printf("ERROR: failed to ParseUint %s - %s", item[2], err)
				continue
			}
		}

		sampleRate, err := strconv.ParseFloat(string(item[5]), 32)
		if err != nil {
			sampleRate = 1
		}

		packet := &Packet{
			Bucket:   string(item[1]),
			Value:    value,
			Modifier: modifier,
			Sampling: float32(sampleRate),
		}
		output = append(output, packet)
	}
	return output
}

func udpListener() {
	address, _ := net.ResolveUDPAddr("udp", *serviceAddress)
	log.Printf("listening on %s", address)
	listener, err := net.ListenUDP("udp", address)
	if err != nil {
		log.Fatalf("ERROR: ListenUDP - %s", err)
	}
	defer listener.Close()

	message := make([]byte, MAX_UDP_PACKET_SIZE)
	for {
		n, remaddr, err := listener.ReadFromUDP(message)
		if err != nil {
			log.Printf("ERROR: reading UDP packet from %+v - %s", remaddr, err)
			continue
		}

		for _, p := range parseMessage(message[:n]) {
			In <- p
		}
	}
}

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Printf("statsdaemon v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}
	signalchan = make(chan os.Signal, 1)
	signal.Notify(signalchan, syscall.SIGTERM)
	*persistCountKeys = -1 * (*persistCountKeys)

	go udpListener()
	monitor()
}
<commit_msg>Working with openTSDB added<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"time"
	"github.com/mapmyfitness/go-opentsdb/tsdb"
)

const (
	VERSION                 = "0.5.2-alpha"
	MAX_UNPROCESSED_PACKETS = 1000
	MAX_UDP_PACKET_SIZE     = 512
)

var signalchan chan os.Signal

type Packet struct {
	Bucket   string
	Value    interface{}
	Modifier string
	Sampling float32
}

type Uint64Slice []uint64

func (s Uint64Slice) Len() int           { return len(s) }
func (s Uint64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s Uint64Slice) Less(i, j int) bool { return s[i] < s[j] }

type Percentiles []*Percentile
type Percentile struct {
	float float64
	str   string
}

func (a *Percentiles) Set(s string) error {
	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return err
	}
	*a = append(*a, &Percentile{f, strings.Replace(s, ".", "_", -1)})
	return nil
}
func (p *Percentile) String() string {
	return p.str
}
func (a *Percentiles) String() string {
	return fmt.Sprintf("%v", *a)
}

var (
	serviceAddress   = flag.String("address", ":8125", "UDP service address")
	graphiteAddress  = flag.String("graphite", "127.0.0.1:2003", "Graphite service address (or - to disable)")
	flushInterval    = flag.Int64("flush-interval", 10, "Flush interval (seconds)")
	debug            = flag.Bool("debug", false, "print statistics sent to graphite")
	showVersion      = flag.Bool("version", false, "print version string")
	persistCountKeys = flag.Int64("persist-count-keys", 60, "number of flush-interval's to persist count keys")
	receiveCounter  = flag.String("receive-counter", "", "Metric name for total metrics recevied per interval")
	prefix           = flag.String("prefix", "stats", "Prefix of reported metrics")
	percentThreshold = Percentiles{}
	openTSDBAddress  = flag.String("opentsdb", "-", "openTSDB service address")

)

func init() {
	flag.Var(&percentThreshold, "percent-threshold", "Threshold percent (0-100, may be given multiple times)")
}

var (
	In       = make(chan *Packet, MAX_UNPROCESSED_PACKETS)
	counters = make(map[string]int64)
	gauges   = make(map[string]uint64)
	timers   = make(map[string]Uint64Slice)
)

func monitor() {
	period := time.Duration(*flushInterval) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
			return
		case <-ticker.C:
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
		case s := <-In:
			if (*receiveCounter != "") {
				v, ok := counters[*receiveCounter]
				if !ok || v < 0 {
					counters[*receiveCounter] = 0
				}
				counters[*receiveCounter] += 1
			}

			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t Uint64Slice
					timers[s.Bucket] = t
				}
				timers[s.Bucket] = append(timers[s.Bucket], s.Value.(uint64))
			} else if s.Modifier == "g" {
				gauges[s.Bucket] = s.Value.(uint64)
			} else {
				v, ok := counters[s.Bucket]
				if !ok || v < 0 {
					counters[s.Bucket] = 0
				}
				counters[s.Bucket] += int64(float64(s.Value.(int64)) * float64(1/s.Sampling))
			}
		}
	}
}

func submit(deadline time.Time) error {
	var buffer bytes.Buffer
	var num int64
	now := time.Now().Unix()
	num += processCounters(&buffer, now)
	num += processGauges(&buffer, now)
	num += processTimers(&buffer, now, percentThreshold)
	if *graphiteAddress!="-" {
		client, err := net.Dial("tcp", *graphiteAddress)
		if err != nil {
			if *debug {
				log.Printf("WARNING: resetting counters when in debug mode")
				processCounters(&buffer, now)
				processGauges(&buffer, now)
				processTimers(&buffer, now, percentThreshold)
			}
			errmsg := fmt.Sprintf("dialing %s failed - %s", *graphiteAddress, err)
			return errors.New(errmsg)
		}
		defer client.Close()

		err = client.SetDeadline(deadline)
		if err != nil {
			errmsg := fmt.Sprintf("could not set deadline:", err)
			return errors.New(errmsg)
		}

		if num == 0 {
			return nil
		}

		if *debug {
			for _, line := range bytes.Split(buffer.Bytes(), []byte("\n")) {
				if len(line) == 0 {
					continue
				}
				log.Printf("DEBUG: %s", line)
			}
		}

		_, err = client.Write(buffer.Bytes())
		if err != nil {
			errmsg := fmt.Sprintf("failed to write stats - %s", err)
			return errors.New(errmsg)
		}

		log.Printf("sent %d stats to %s", num, *graphiteAddress)

	}
	if(*openTSDBAddress!="-"){
		datapoints:=[]tsdb.DataPoint{}
		TSDB:=tsdb.TSDB{}
		server:=tsdb.Server{}
		serverAdress:=strings.Split(*openTSDBAddress,":")
		if(len(serverAdress)!=2){
			errmsg := fmt.Sprintf("Error: Incorrect openTSDB server address")
			return errors.New(errmsg)
		}
		port,err:=strconv.ParseUint(serverAdress[1],10,32)
		if(err!=nil){
			return err
		}
		server.Host=serverAdress[0]
		server.Port=uint(port)
		metrics := strings.Split(buffer.String(),"\n")
		for _,mtr := range metrics {
			data:= strings.Split(mtr," ")
			if len(data)==3 {
				metric:=tsdb.Metric{}
				value:=tsdb.Value{}
				tags:=tsdb.Tags{}
				timestamp:=tsdb.Time{}
				datapoint:=tsdb.DataPoint{}
				val,err := strconv.ParseFloat(data[1],64)
				if err!=nil {
					return err
				}
				value.Set(val)
				err=timestamp.Parse(data[2])
				if err!=nil {
					return err
				}
				metricAndTags:=strings.Split(data[0],"?")
				if(metricAndTags[0]!=data[0]){
					err=metric.Set(metricAndTags[0])
					if err!=nil {
						return err
					}
					for _, tagVal := range strings.Split(metricAndTags[1],"&"){
						arrTagVal:= strings.Split(tagVal,"=")
						if(len(arrTagVal)!=2){
							errmsg := fmt.Sprintf("Error: Incorrect metric format")
							return errors.New(errmsg)
						}
						tags.Set(arrTagVal[0],arrTagVal[1])
					}
				} else {
					metricAndTags:=strings.Split(data[0],"._t_")
					if(len(metricAndTags)!=2){
						errmsg := fmt.Sprintf("Error: Incorrect metric format")
						return errors.New(errmsg)
					}
					err=metric.Set(metricAndTags[0])
					if err!=nil {
						return err
					}
					arrTagVal:= strings.Split (metricAndTags[1],".")
					if(len(arrTagVal)!=2){
						errmsg := fmt.Sprintf("Error: Incorrect metric format")
						return errors.New(errmsg)
					}
					tags.Set(arrTagVal[0],arrTagVal[1])
				}

				datapoint.Value=&value
				datapoint.Metric=&metric
				datapoint.Tags=&tags
				datapoint.Timestamp=&timestamp
				datapoints=append(datapoints,datapoint)

			}

		}

		TSDB.Servers=append(TSDB.Servers,server)
		_,err=TSDB.Put(datapoints)
		if err!=nil {
			return err
		}
		log.Printf("sent %d stats to %s", num, *openTSDBAddress)

	}
	return nil
}

func processCounters(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	var realc float64
	// continue sending zeros for counters for a short period of time even if we have no new data
	// note we use the same in-memory value to denote both the actual value of the counter (value >= 0)
	// as well as how many turns to keep the counter for (value < 0)
	// for more context see https://github.com/bitly/statsdaemon/pull/8
	for s, c := range counters {
		switch {
		case c <= *persistCountKeys:
			// consider this purgable
			delete(counters, s)
			continue
		case c < 0:
			counters[s] -= 1
			fmt.Fprintf(buffer, "%s.%s %d %d\n", *prefix, s, 0, now)
		case c >= 0:
			counters[s] = -1
			realc = float64(c)/10.0
			fmt.Fprintf(buffer, "%s.%s %.6f %d\n", *prefix, s, realc, now)
		}
		num++
	}
	return num
}

func processGauges(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for g, c := range gauges {
		if c == math.MaxUint64 {
			continue
		}
		fmt.Fprintf(buffer, "%s.%s %d %d\n", *prefix, g, c, now)
		gauges[g] = math.MaxUint64
		num++
	}
	return num
}

func processTimers(buffer *bytes.Buffer, now int64, pctls Percentiles) int64 {
	var num int64
	for u, t := range timers {
		if len(t) > 0 {
			num++

			sort.Sort(t)
			min := t[0]
			max := t[len(t)-1]
			maxAtThreshold := max
			count := len(t)

			sum := uint64(0)
			for _, value := range t {
				sum += value
			}
			mean := float64(sum) / float64(len(t))

			for _, pct := range pctls {

				if len(t) > 1 {
					var abs float64
					if pct.float >= 0 {
						abs = pct.float
					} else {
						abs = 100 + pct.float
					}
					// poor man's math.Round(x):
					// math.Floor(x + 0.5)
					indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
					if pct.float >= 0 {
						indexOfPerc -= 1 // index offset=0
					}
					maxAtThreshold = t[indexOfPerc]
				}

				var tmpl string
				var pctstr string
				if pct.float >= 0 {
					tmpl = "%s.timers.%s.upper_%s %d %d\n"
					pctstr = pct.str
				} else {
					tmpl = "%s.timers.%s.lower_%s %d %d\n"
					pctstr = pct.str[1:]
				}
				fmt.Fprintf(buffer, tmpl, *prefix, u, pctstr, maxAtThreshold, now)
			}

			var z Uint64Slice
			timers[u] = z

			fmt.Fprintf(buffer, "%s.timers.%s.mean %f %d\n", *prefix, u, mean, now)
			fmt.Fprintf(buffer, "%s.timers.%s.upper %d %d\n", *prefix, u, max, now)
			fmt.Fprintf(buffer, "%s.timers.%s.lower %d %d\n", *prefix, u, min, now)
			fmt.Fprintf(buffer, "%s.timers.%s.count %d %d\n", *prefix, u, count, now)
		}
	}
	return num
}

var packetRegexp = regexp.MustCompile("^([^:]+):(-?[0-9]+)\\.?[0-9]*\\|(g|c|ms)(\\|@([0-9\\.]+))?\n?$")

func parseMessage(data []byte) []*Packet {
	var output []*Packet
	for _, line := range bytes.Split(data, []byte("\n")) {
		if len(line) == 0 {
			continue
		}

		item := packetRegexp.FindSubmatch(line)
		if len(item) == 0 {
			continue
		}

		var err error
		var value interface{}
		modifier := string(item[3])
		switch modifier {
		case "c":
			value, err = strconv.ParseInt(string(item[2]), 10, 64)
			if err != nil {
				log.Printf("ERROR: failed to ParseInt %s - %s", item[2], err)
				continue
			}
		default:
			value, err = strconv.ParseUint(string(item[2]), 10, 64)
			if err != nil {
				log.Printf("ERROR: failed to ParseUint %s - %s", item[2], err)
				continue
			}
		}

		sampleRate, err := strconv.ParseFloat(string(item[5]), 32)
		if err != nil {
			sampleRate = 1
		}

		packet := &Packet{
			Bucket:   string(item[1]),
			Value:    value,
			Modifier: modifier,
			Sampling: float32(sampleRate),
		}
		output = append(output, packet)
	}
	return output
}

func udpListener() {
	address, _ := net.ResolveUDPAddr("udp", *serviceAddress)
	log.Printf("listening on %s", address)
	listener, err := net.ListenUDP("udp", address)
	if err != nil {
		log.Fatalf("ERROR: ListenUDP - %s", err)
	}
	defer listener.Close()

	message := make([]byte, MAX_UDP_PACKET_SIZE)
	for {
		n, remaddr, err := listener.ReadFromUDP(message)
		if err != nil {
			log.Printf("ERROR: reading UDP packet from %+v - %s", remaddr, err)
			continue
		}

		for _, p := range parseMessage(message[:n]) {
			In <- p
		}
	}
}

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Printf("statsdaemon v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}
	signalchan = make(chan os.Signal, 1)
	signal.Notify(signalchan, syscall.SIGTERM)
	*persistCountKeys = -1 * (*persistCountKeys)

	go udpListener()
	monitor()
}
<|endoftext|>