<commit_before>package buffalo

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/plush"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func testApp() *App {
	a := New(Options{})
	a.Redirect(301, "/foo", "/bar")
	a.GET("/bar", func(c Context) error {
		return c.Render(200, render.String("bar"))
	})

	rt := a.Group("/router/tests")

	h := func(c Context) error {
		return c.Render(200, render.String(c.Request().Method+"|"+c.Value("current_path").(string)))
	}

	rt.GET("/", h)
	rt.POST("/", h)
	rt.PUT("/", h)
	rt.DELETE("/", h)
	rt.OPTIONS("/", h)
	rt.PATCH("/", h)
	return a
}

func Test_Router(t *testing.T) {
	r := require.New(t)

	table := []string{
		"GET",
		"POST",
		"PUT",
		"DELETE",
		"OPTIONS",
		"PATCH",
	}

	ts := httptest.NewServer(testApp())
	defer ts.Close()

	for _, v := range table {
		req, err := http.NewRequest(v, fmt.Sprintf("%s/router/tests", ts.URL), nil)
		r.NoError(err)
		res, err := http.DefaultClient.Do(req)
		r.NoError(err)
		b, _ := ioutil.ReadAll(res.Body)
		r.Equal(fmt.Sprintf("%s|/router/tests", v), string(b))
	}
}

func Test_Router_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/users").Get()
	r.Equal(201, res.Code)
}

func Test_Router_Group_on_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})
	f := g.Group("/foo")
	f.GET("/bar", func(c Context) error {
		return c.Render(420, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/foo/bar").Get()
	r.Equal(420, res.Code)
}

func Test_Router_Group_Middleware(t *testing.T) {
	r := require.New(t)

	a := testApp()
	a.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)

	g := a.Group("/api/v1")
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 1)

	g.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 2)
}

func Test_Router_Redirect(t *testing.T) {
	r := require.New(t)
	w := willie.New(testApp())
	res := w.Request("/foo").Get()
	r.Equal(301, res.Code)
	r.Equal("/bar", res.Location())
}

func Test_Router_ServeFiles(t *testing.T) {
	r := require.New(t)

	tmpFile, err := ioutil.TempFile("", "assets")
	r.NoError(err)

	af := []byte("hi")
	_, err = tmpFile.Write(af)
	r.NoError(err)

	a := New(Options{})
	a.ServeFiles("/assets", http.Dir(filepath.Dir(tmpFile.Name())))

	w := willie.New(a)
	res := w.Request("/assets/%s", filepath.Base(tmpFile.Name())).Get()

	r.Equal(200, res.Code)
	r.Equal(af, res.Body.Bytes())
}

func Test_App_NamedRoutes(t *testing.T) {

	type CarsResource struct {
		*BaseResource
	}

	r := require.New(t)
	a := Automatic(Options{})

	var carsResource Resource
	carsResource = CarsResource{&BaseResource{}}

	rr := render.New(render.Options{
		HTMLLayout:     "application.html",
		TemplateEngine: plush.BuffaloRenderer,
		TemplatesBox:   packr.NewBox("../templates"),
		Helpers:        map[string]interface{}{},
	})

	sampleHandler := func(c Context) error {
		c.Set("opts", map[string]interface{}{})
		return c.Render(200, rr.String(`
			1. <%= rootPath() %>
			2. <%= usersPath() %>
			3. <%= userPath({user_id: 1}) %>
			4. <%= myPeepsPath() %>
			5. <%= userPath(opts) %>
			6. <%= carPath({car_id: 1}) %>
			7. <%= newCarPath() %>
			8. <%= editCarPath({car_id: 1}) %>
			9. <%= editCarPath({car_id: 1, other: 12}) %>
			10. <%= rootPath({"some":"variable","other": 12}) %>
		`))
	}

	a.GET("/", sampleHandler)
	a.GET("/users", sampleHandler)
	a.GET("/users/{user_id}", sampleHandler)
	a.GET("/peeps", sampleHandler).Name("myPeeps")
	a.Resource("/car", carsResource)

	w := willie.New(a)
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "1. /")
	r.Contains(res.Body.String(), "2. /users")
	r.Contains(res.Body.String(), "3. /users/1")
	r.Contains(res.Body.String(), "4. /peeps")
	r.Contains(res.Body.String(), "5. /users/{user_id}")
	r.Contains(res.Body.String(), "6. /car/1")
	r.Contains(res.Body.String(), "7. /car/new")
	r.Contains(res.Body.String(), "8. /car/1/edit")
	r.Contains(res.Body.String(), "9. /car/1/edit?other=12")
	r.Contains(res.Body.String(), "10. /?other=12&some=variable")
}

func Test_Resource(t *testing.T) {
	r := require.New(t)

	type trs struct {
		Method string
		Path   string
		Result string
	}

	tests := []trs{
		{
			Method: "GET",
			Path:   "",
			Result: "list",
		},
		{
			Method: "GET",
			Path:   "/new",
			Result: "new",
		},
		{
			Method: "GET",
			Path:   "/1",
			Result: "show 1",
		},
		{
			Method: "GET",
			Path:   "/1/edit",
			Result: "edit 1",
		},
		{
			Method: "POST",
			Path:   "",
			Result: "create",
		},
		{
			Method: "PUT",
			Path:   "/1",
			Result: "update 1",
		},
		{
			Method: "DELETE",
			Path:   "/1",
			Result: "destroy 1",
		},
	}

	a := Automatic(Options{})
	a.Resource("/users", &userResource{})
	a.Resource("/api/v1/users", &userResource{})

	ts := httptest.NewServer(a)
	defer ts.Close()

	c := http.Client{}
	for _, path := range []string{"/users", "/api/v1/users"} {
		for _, test := range tests {
			u := ts.URL + path + test.Path
			req, err := http.NewRequest(test.Method, u, nil)
			r.NoError(err)
			res, err := c.Do(req)
			r.NoError(err)
			b, err := ioutil.ReadAll(res.Body)
			r.NoError(err)
			r.Equal(test.Result, string(b))
		}
	}

}

type userResource struct{}

func (u *userResource) List(c Context) error {
	return c.Render(200, render.String("list"))
}

func (u *userResource) Show(c Context) error {
	return c.Render(200, render.String(`show <%=params["user_id"] %>`))
}

func (u *userResource) New(c Context) error {
	return c.Render(200, render.String("new"))
}

func (u *userResource) Create(c Context) error {
	return c.Render(200, render.String("create"))
}

func (u *userResource) Edit(c Context) error {
	return c.Render(200, render.String(`edit <%=params["user_id"] %>`))
}

func (u *userResource) Update(c Context) error {
	return c.Render(200, render.String(`update <%=params["user_id"] %>`))
}

func (u *userResource) Destroy(c Context) error {
	return c.Render(200, render.String(`destroy <%=params["user_id"] %>`))
}

func Test_buildRouteName(t *testing.T) {
	r := require.New(t)
	cases := map[string]string{
		"/":                                          "root",
		"/users":                                     "users",
		"/users/new":                                 "newUsers",
		"/users/{user_id}":                           "user",
		"/users/{user_id}/children":                  "userChildren",
		"/users/{user_id}/children/{child_id}":       "userChild",
		"/users/{user_id}/children/new":              "newUserChildren",
		"/users/{user_id}/children/{child_id}/build": "userChildBuild",
		"/admin/planes":                              "adminPlanes",
		"/admin/planes/{plane_id}":                   "adminPlane",
		"/admin/planes/{plane_id}/edit":              "editAdminPlane",
	}

	for input, result := range cases {
		fResult := buildRouteName(input)
		r.Equal(result, fResult, input)
	}
}

func Test_CatchAll_Route(t *testing.T) {
	r := require.New(t)
	rr := render.New(render.Options{
		// HTMLLayout:     "application.html",
		TemplateEngine: plush.BuffaloRenderer,
		TemplatesBox:   packr.NewBox("../templates"),
		Helpers:        map[string]interface{}{},
	})

	a := Automatic(Options{})
	a.GET("/{name:.+}", func(c Context) error {
		name := c.Param("name")
		return c.Render(200, rr.String(name))
	})

	w := willie.New(a)
	res := w.Request("/john").Get()

	r.Contains(res.Body.String(), "john")
}
<commit_msg>cleaning out test to use only what it needs<commit_after>package buffalo

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"testing"

	"github.com/gobuffalo/buffalo/render"
	"github.com/gobuffalo/packr"
	"github.com/gobuffalo/plush"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func testApp() *App {
	a := New(Options{})
	a.Redirect(301, "/foo", "/bar")
	a.GET("/bar", func(c Context) error {
		return c.Render(200, render.String("bar"))
	})

	rt := a.Group("/router/tests")

	h := func(c Context) error {
		return c.Render(200, render.String(c.Request().Method+"|"+c.Value("current_path").(string)))
	}

	rt.GET("/", h)
	rt.POST("/", h)
	rt.PUT("/", h)
	rt.DELETE("/", h)
	rt.OPTIONS("/", h)
	rt.PATCH("/", h)
	return a
}

func Test_Router(t *testing.T) {
	r := require.New(t)

	table := []string{
		"GET",
		"POST",
		"PUT",
		"DELETE",
		"OPTIONS",
		"PATCH",
	}

	ts := httptest.NewServer(testApp())
	defer ts.Close()

	for _, v := range table {
		req, err := http.NewRequest(v, fmt.Sprintf("%s/router/tests", ts.URL), nil)
		r.NoError(err)
		res, err := http.DefaultClient.Do(req)
		r.NoError(err)
		b, _ := ioutil.ReadAll(res.Body)
		r.Equal(fmt.Sprintf("%s|/router/tests", v), string(b))
	}
}

func Test_Router_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/users").Get()
	r.Equal(201, res.Code)
}

func Test_Router_Group_on_Group(t *testing.T) {
	r := require.New(t)

	a := testApp()
	g := a.Group("/api/v1")
	g.GET("/users", func(c Context) error {
		return c.Render(201, nil)
	})
	f := g.Group("/foo")
	f.GET("/bar", func(c Context) error {
		return c.Render(420, nil)
	})

	w := willie.New(a)
	res := w.Request("/api/v1/foo/bar").Get()
	r.Equal(420, res.Code)
}

func Test_Router_Group_Middleware(t *testing.T) {
	r := require.New(t)

	a := testApp()
	a.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)

	g := a.Group("/api/v1")
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 1)

	g.Use(func(h Handler) Handler { return h })
	r.Len(a.Middleware.stack, 1)
	r.Len(g.Middleware.stack, 2)
}

func Test_Router_Redirect(t *testing.T) {
	r := require.New(t)
	w := willie.New(testApp())
	res := w.Request("/foo").Get()
	r.Equal(301, res.Code)
	r.Equal("/bar", res.Location())
}

func Test_Router_ServeFiles(t *testing.T) {
	r := require.New(t)

	tmpFile, err := ioutil.TempFile("", "assets")
	r.NoError(err)

	af := []byte("hi")
	_, err = tmpFile.Write(af)
	r.NoError(err)

	a := New(Options{})
	a.ServeFiles("/assets", http.Dir(filepath.Dir(tmpFile.Name())))

	w := willie.New(a)
	res := w.Request("/assets/%s", filepath.Base(tmpFile.Name())).Get()

	r.Equal(200, res.Code)
	r.Equal(af, res.Body.Bytes())
}

func Test_App_NamedRoutes(t *testing.T) {

	type CarsResource struct {
		*BaseResource
	}

	r := require.New(t)
	a := Automatic(Options{})

	var carsResource Resource
	carsResource = CarsResource{&BaseResource{}}

	rr := render.New(render.Options{
		HTMLLayout:     "application.html",
		TemplateEngine: plush.BuffaloRenderer,
		TemplatesBox:   packr.NewBox("../templates"),
		Helpers:        map[string]interface{}{},
	})

	sampleHandler := func(c Context) error {
		c.Set("opts", map[string]interface{}{})
		return c.Render(200, rr.String(`
			1. <%= rootPath() %>
			2. <%= usersPath() %>
			3. <%= userPath({user_id: 1}) %>
			4. <%= myPeepsPath() %>
			5. <%= userPath(opts) %>
			6. <%= carPath({car_id: 1}) %>
			7. <%= newCarPath() %>
			8. <%= editCarPath({car_id: 1}) %>
			9. <%= editCarPath({car_id: 1, other: 12}) %>
			10. <%= rootPath({"some":"variable","other": 12}) %>
		`))
	}

	a.GET("/", sampleHandler)
	a.GET("/users", sampleHandler)
	a.GET("/users/{user_id}", sampleHandler)
	a.GET("/peeps", sampleHandler).Name("myPeeps")
	a.Resource("/car", carsResource)

	w := willie.New(a)
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "1. /")
	r.Contains(res.Body.String(), "2. /users")
	r.Contains(res.Body.String(), "3. /users/1")
	r.Contains(res.Body.String(), "4. /peeps")
	r.Contains(res.Body.String(), "5. /users/{user_id}")
	r.Contains(res.Body.String(), "6. /car/1")
	r.Contains(res.Body.String(), "7. /car/new")
	r.Contains(res.Body.String(), "8. /car/1/edit")
	r.Contains(res.Body.String(), "9. /car/1/edit?other=12")
	r.Contains(res.Body.String(), "10. /?other=12&some=variable")
}

func Test_Resource(t *testing.T) {
	r := require.New(t)

	type trs struct {
		Method string
		Path   string
		Result string
	}

	tests := []trs{
		{
			Method: "GET",
			Path:   "",
			Result: "list",
		},
		{
			Method: "GET",
			Path:   "/new",
			Result: "new",
		},
		{
			Method: "GET",
			Path:   "/1",
			Result: "show 1",
		},
		{
			Method: "GET",
			Path:   "/1/edit",
			Result: "edit 1",
		},
		{
			Method: "POST",
			Path:   "",
			Result: "create",
		},
		{
			Method: "PUT",
			Path:   "/1",
			Result: "update 1",
		},
		{
			Method: "DELETE",
			Path:   "/1",
			Result: "destroy 1",
		},
	}

	a := Automatic(Options{})
	a.Resource("/users", &userResource{})
	a.Resource("/api/v1/users", &userResource{})

	ts := httptest.NewServer(a)
	defer ts.Close()

	c := http.Client{}
	for _, path := range []string{"/users", "/api/v1/users"} {
		for _, test := range tests {
			u := ts.URL + path + test.Path
			req, err := http.NewRequest(test.Method, u, nil)
			r.NoError(err)
			res, err := c.Do(req)
			r.NoError(err)
			b, err := ioutil.ReadAll(res.Body)
			r.NoError(err)
			r.Equal(test.Result, string(b))
		}
	}

}

type userResource struct{}

func (u *userResource) List(c Context) error {
	return c.Render(200, render.String("list"))
}

func (u *userResource) Show(c Context) error {
	return c.Render(200, render.String(`show <%=params["user_id"] %>`))
}

func (u *userResource) New(c Context) error {
	return c.Render(200, render.String("new"))
}

func (u *userResource) Create(c Context) error {
	return c.Render(200, render.String("create"))
}

func (u *userResource) Edit(c Context) error {
	return c.Render(200, render.String(`edit <%=params["user_id"] %>`))
}

func (u *userResource) Update(c Context) error {
	return c.Render(200, render.String(`update <%=params["user_id"] %>`))
}

func (u *userResource) Destroy(c Context) error {
	return c.Render(200, render.String(`destroy <%=params["user_id"] %>`))
}

func Test_buildRouteName(t *testing.T) {
	r := require.New(t)
	cases := map[string]string{
		"/":                                          "root",
		"/users":                                     "users",
		"/users/new":                                 "newUsers",
		"/users/{user_id}":                           "user",
		"/users/{user_id}/children":                  "userChildren",
		"/users/{user_id}/children/{child_id}":       "userChild",
		"/users/{user_id}/children/new":              "newUserChildren",
		"/users/{user_id}/children/{child_id}/build": "userChildBuild",
		"/admin/planes":                              "adminPlanes",
		"/admin/planes/{plane_id}":                   "adminPlane",
		"/admin/planes/{plane_id}/edit":              "editAdminPlane",
	}

	for input, result := range cases {
		fResult := buildRouteName(input)
		r.Equal(result, fResult, input)
	}
}

func Test_CatchAll_Route(t *testing.T) {
	r := require.New(t)
	rr := render.New(render.Options{})

	a := Automatic(Options{})
	a.GET("/{name:.+}", func(c Context) error {
		name := c.Param("name")
		return c.Render(200, rr.String(name))
	})

	w := willie.New(a)
	res := w.Request("/john").Get()

	r.Contains(res.Body.String(), "john")
}
<|endoftext|>


<commit_before>package wrphttp

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"github.com/Comcast/webpa-common/httperror"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/middleware"
	"github.com/Comcast/webpa-common/tracing"
	"github.com/Comcast/webpa-common/wrp"
	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	gokithttp "github.com/go-kit/kit/transport/http"
)

const (
	DefaultMethod                            = "POST"
	DefaultEndpoint                          = "http://localhost:7000/api/v2/device/send"
	DefaultMaxIdleConnsPerHost               = 20
	DefaultFanoutTimeout       time.Duration = 45 * time.Second
	DefaultClientTimeout       time.Duration = 30 * time.Second
	DefaultMaxClients          int64         = 10000
	DefaultConcurrency                       = 1000
	DefaultEncoderPoolSize                   = 100
	DefaultDecoderPoolSize                   = 100
)

// FanoutOptions describe the options available for a go-kit HTTP server that does fanout via middleware.Fanout.
type FanoutOptions struct {
	// Logger is the go-kit logger to use when creating the service fanout.  If not set, logging.DefaultLogger is used.
	Logger log.Logger `json:"-"`

	// Method is the HTTP method to use for all endpoints.  If not set, DefaultMethod is used.
	Method string `json:"method,omitempty"`

	// Endpoints are the URLs for each endpoint to fan out to.  If not set, DefaultEndpoint is used.
	Endpoints []string `json:"endpoints,omitempty"`

	// Authorization is the Basic Auth token.  There is no default for this field.
	Authorization string `json:"authorization"`

	// Transport is the http.Client transport
	Transport http.Transport `json:"transport"`

	// FanoutTimeout is the timeout for the entire fanout operation.  If not supplied, DefaultFanoutTimeout is used.
	FanoutTimeout time.Duration `json:"timeout"`

	// ClientTimeout is the http.Client Timeout.  If not set, DefaultClientTimeout is used.
	ClientTimeout time.Duration `json:"clientTimeout"`

	// MaxClients is the maximum number of concurrent clients that can be using the fanout.  This should be set to
	// something larger than the Concurrency field.
	MaxClients int64 `json:"maxClients"`

	// Concurrency is the maximum number of concurrent fanouts allowed.  This is enforced via a Concurrent middleware.
	// If this is not set, DefaultConcurrency is used.
	Concurrency int `json:"concurrency"`

	// EncoderPoolSize is the size of the WRP encoder pool.  If not set, DefaultEncoderPoolSize is used.
	EncoderPoolSize int

	// DecoderPoolSize is the size of the WRP encoder pool.  If not set, DefaultDecoderPoolSize is used.
	DecoderPoolSize int

	// Middleware is the extra Middleware to append, which can (and often is) empty
	Middleware []endpoint.Middleware `json:"-"`
}

func (f *FanoutOptions) logger() log.Logger {
	if f != nil && f.Logger != nil {
		return f.Logger
	}

	return logging.DefaultLogger()
}

func (f *FanoutOptions) method() string {
	if f != nil && len(f.Method) > 0 {
		return f.Method
	}

	return DefaultMethod
}

func (f *FanoutOptions) endpoints() []string {
	if f != nil && len(f.Endpoints) > 0 {
		return f.Endpoints
	}

	return []string{DefaultEndpoint}
}

func (f *FanoutOptions) authorization() string {
	if f != nil && len(f.Authorization) > 0 {
		return f.Authorization
	}

	return ""
}

func (f *FanoutOptions) urls() ([]*url.URL, error) {
	var urls []*url.URL
	for _, endpoint := range f.endpoints() {
		url, err := url.Parse(endpoint)
		if err != nil {
			return nil, err
		}

		urls = append(urls, url)
	}

	return urls, nil
}

func (f *FanoutOptions) transport() *http.Transport {
	transport := new(http.Transport)

	if f != nil {
		*transport = f.Transport
	}

	if transport.MaxIdleConnsPerHost < 1 {
		transport.MaxIdleConnsPerHost = DefaultMaxIdleConnsPerHost
	}

	return transport
}

func (f *FanoutOptions) fanoutTimeout() time.Duration {
	if f != nil && f.FanoutTimeout > 0 {
		return f.FanoutTimeout
	}

	return DefaultFanoutTimeout
}

func (f *FanoutOptions) clientTimeout() time.Duration {
	if f != nil && f.ClientTimeout > 0 {
		return f.ClientTimeout
	}

	return DefaultClientTimeout
}

func (f *FanoutOptions) maxClients() int64 {
	if f != nil && f.MaxClients > 0 {
		return f.MaxClients
	}

	return DefaultMaxClients
}

func (f *FanoutOptions) concurrency() int {
	if f != nil && f.Concurrency > 0 {
		return f.Concurrency
	}

	return DefaultConcurrency
}

func (f *FanoutOptions) encoderPoolSize() int {
	if f != nil && f.EncoderPoolSize > 0 {
		return f.EncoderPoolSize
	}

	return DefaultEncoderPoolSize
}

func (f *FanoutOptions) decoderPoolSize() int {
	if f != nil && f.DecoderPoolSize > 0 {
		return f.DecoderPoolSize
	}

	return DefaultDecoderPoolSize
}

func (f *FanoutOptions) middleware() []endpoint.Middleware {
	if f != nil {
		return f.Middleware
	}

	return nil
}

// NewEncoderPool creates a wrp.EncoderPool using this options, which can be nil to take defaults
func (o *FanoutOptions) NewEncoderPool(format wrp.Format) *wrp.EncoderPool {
	return wrp.NewEncoderPool(o.encoderPoolSize(), format)
}

// NewDecoderPool creates a wrp.DecoderPool using this options, which can be nil to take defaults
func (o *FanoutOptions) NewDecoderPool(format wrp.Format) *wrp.DecoderPool {
	return wrp.NewDecoderPool(o.decoderPoolSize(), format)
}

// NewFanoutEndpoint uses the supplied options to produce a go-kit HTTP server endpoint which
// fans out to the HTTP endpoints specified in the options.  The endpoint returned from this
// can be used to build one or more go-kit transport/http.Server objects.
//
// The FanoutOptions can be nil, in which case a set of defaults is used.
func NewFanoutEndpoint(o *FanoutOptions) (endpoint.Endpoint, error) {
	urls, err := o.urls()
	if err != nil {
		return nil, err
	}

	var (
		encoderPool = o.NewEncoderPool(wrp.Msgpack)
		decoderPool = o.NewDecoderPool(wrp.Msgpack)

		httpClient = &http.Client{
			Transport: o.transport(),
			Timeout:   o.clientTimeout(),
		}

		fanoutEndpoints = make(map[string]endpoint.Endpoint, len(urls))
		customHeader    = http.Header{
			"Accept": []string{"application/msgpack"},
		}
	)

	if authorization := o.authorization(); len(authorization) > 0 {
		customHeader.Set("Authorization", "Basic "+authorization)
	}

	for _, url := range urls {
		fanoutEndpoints[url.String()] =
			gokithttp.NewClient(
				o.method(),
				url,
				ClientEncodeRequestBody(encoderPool, customHeader),
				ClientDecodeResponseBody(decoderPool),
				gokithttp.SetClient(httpClient), gokithttp.ClientBefore(SetGetBodyFunc),
			).Endpoint()
	}

	var (
		middlewareChain = append(
			[]endpoint.Middleware{
				middleware.Logging,
				middleware.Busy(o.maxClients(), &httperror.E{Code: http.StatusServiceUnavailable, Text: "Server Busy"}),
				middleware.Timeout(o.fanoutTimeout()),
				middleware.Concurrent(o.concurrency(), &httperror.E{Code: http.StatusTooManyRequests, Text: "Too Many Requests"}),
			},
			o.middleware()...,
		)
	)

	return endpoint.Chain(
			middlewareChain[0],
			middlewareChain[1:]...,
		)(middleware.Fanout(tracing.NewSpanner(), fanoutEndpoints)),
		nil
}

func SetGetBodyFunc(context context.Context, request *http.Request) context.Context {
	if request == nil || request.Body == nil {
		return context
	}
	request.GetBody = func() (send io.ReadCloser, err error) {
		var keepBuffer, sendBuffer bytes.Buffer
		bodyBytes, err := ioutil.ReadAll(request.Body)
		keepBuffer.Write(bodyBytes)
		sendBuffer.Write(bodyBytes)
		send = ioutil.NopCloser(&sendBuffer)
		request.Body = ioutil.NopCloser(&keepBuffer)
		return
	}
	return context
}
<commit_msg>GetBodyFunction Inner Function Scope Fix<commit_after>package wrphttp

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"github.com/Comcast/webpa-common/httperror"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/middleware"
	"github.com/Comcast/webpa-common/tracing"
	"github.com/Comcast/webpa-common/wrp"
	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	gokithttp "github.com/go-kit/kit/transport/http"
)

const (
	DefaultMethod                            = "POST"
	DefaultEndpoint                          = "http://localhost:7000/api/v2/device/send"
	DefaultMaxIdleConnsPerHost               = 20
	DefaultFanoutTimeout       time.Duration = 45 * time.Second
	DefaultClientTimeout       time.Duration = 30 * time.Second
	DefaultMaxClients          int64         = 10000
	DefaultConcurrency                       = 1000
	DefaultEncoderPoolSize                   = 100
	DefaultDecoderPoolSize                   = 100
)

// FanoutOptions describe the options available for a go-kit HTTP server that does fanout via middleware.Fanout.
type FanoutOptions struct {
	// Logger is the go-kit logger to use when creating the service fanout.  If not set, logging.DefaultLogger is used.
	Logger log.Logger `json:"-"`

	// Method is the HTTP method to use for all endpoints.  If not set, DefaultMethod is used.
	Method string `json:"method,omitempty"`

	// Endpoints are the URLs for each endpoint to fan out to.  If not set, DefaultEndpoint is used.
	Endpoints []string `json:"endpoints,omitempty"`

	// Authorization is the Basic Auth token.  There is no default for this field.
	Authorization string `json:"authorization"`

	// Transport is the http.Client transport
	Transport http.Transport `json:"transport"`

	// FanoutTimeout is the timeout for the entire fanout operation.  If not supplied, DefaultFanoutTimeout is used.
	FanoutTimeout time.Duration `json:"timeout"`

	// ClientTimeout is the http.Client Timeout.  If not set, DefaultClientTimeout is used.
	ClientTimeout time.Duration `json:"clientTimeout"`

	// MaxClients is the maximum number of concurrent clients that can be using the fanout.  This should be set to
	// something larger than the Concurrency field.
	MaxClients int64 `json:"maxClients"`

	// Concurrency is the maximum number of concurrent fanouts allowed.  This is enforced via a Concurrent middleware.
	// If this is not set, DefaultConcurrency is used.
	Concurrency int `json:"concurrency"`

	// EncoderPoolSize is the size of the WRP encoder pool.  If not set, DefaultEncoderPoolSize is used.
	EncoderPoolSize int

	// DecoderPoolSize is the size of the WRP encoder pool.  If not set, DefaultDecoderPoolSize is used.
	DecoderPoolSize int

	// Middleware is the extra Middleware to append, which can (and often is) empty
	Middleware []endpoint.Middleware `json:"-"`
}

func (f *FanoutOptions) logger() log.Logger {
	if f != nil && f.Logger != nil {
		return f.Logger
	}

	return logging.DefaultLogger()
}

func (f *FanoutOptions) method() string {
	if f != nil && len(f.Method) > 0 {
		return f.Method
	}

	return DefaultMethod
}

func (f *FanoutOptions) endpoints() []string {
	if f != nil && len(f.Endpoints) > 0 {
		return f.Endpoints
	}

	return []string{DefaultEndpoint}
}

func (f *FanoutOptions) authorization() string {
	if f != nil && len(f.Authorization) > 0 {
		return f.Authorization
	}

	return ""
}

func (f *FanoutOptions) urls() ([]*url.URL, error) {
	var urls []*url.URL
	for _, endpoint := range f.endpoints() {
		url, err := url.Parse(endpoint)
		if err != nil {
			return nil, err
		}

		urls = append(urls, url)
	}

	return urls, nil
}

func (f *FanoutOptions) transport() *http.Transport {
	transport := new(http.Transport)

	if f != nil {
		*transport = f.Transport
	}

	if transport.MaxIdleConnsPerHost < 1 {
		transport.MaxIdleConnsPerHost = DefaultMaxIdleConnsPerHost
	}

	return transport
}

func (f *FanoutOptions) fanoutTimeout() time.Duration {
	if f != nil && f.FanoutTimeout > 0 {
		return f.FanoutTimeout
	}

	return DefaultFanoutTimeout
}

func (f *FanoutOptions) clientTimeout() time.Duration {
	if f != nil && f.ClientTimeout > 0 {
		return f.ClientTimeout
	}

	return DefaultClientTimeout
}

func (f *FanoutOptions) maxClients() int64 {
	if f != nil && f.MaxClients > 0 {
		return f.MaxClients
	}

	return DefaultMaxClients
}

func (f *FanoutOptions) concurrency() int {
	if f != nil && f.Concurrency > 0 {
		return f.Concurrency
	}

	return DefaultConcurrency
}

func (f *FanoutOptions) encoderPoolSize() int {
	if f != nil && f.EncoderPoolSize > 0 {
		return f.EncoderPoolSize
	}

	return DefaultEncoderPoolSize
}

func (f *FanoutOptions) decoderPoolSize() int {
	if f != nil && f.DecoderPoolSize > 0 {
		return f.DecoderPoolSize
	}

	return DefaultDecoderPoolSize
}

func (f *FanoutOptions) middleware() []endpoint.Middleware {
	if f != nil {
		return f.Middleware
	}

	return nil
}

// NewEncoderPool creates a wrp.EncoderPool using this options, which can be nil to take defaults
func (o *FanoutOptions) NewEncoderPool(format wrp.Format) *wrp.EncoderPool {
	return wrp.NewEncoderPool(o.encoderPoolSize(), format)
}

// NewDecoderPool creates a wrp.DecoderPool using this options, which can be nil to take defaults
func (o *FanoutOptions) NewDecoderPool(format wrp.Format) *wrp.DecoderPool {
	return wrp.NewDecoderPool(o.decoderPoolSize(), format)
}

// NewFanoutEndpoint uses the supplied options to produce a go-kit HTTP server endpoint which
// fans out to the HTTP endpoints specified in the options.  The endpoint returned from this
// can be used to build one or more go-kit transport/http.Server objects.
//
// The FanoutOptions can be nil, in which case a set of defaults is used.
func NewFanoutEndpoint(o *FanoutOptions) (endpoint.Endpoint, error) {
	urls, err := o.urls()
	if err != nil {
		return nil, err
	}

	var (
		encoderPool = o.NewEncoderPool(wrp.Msgpack)
		decoderPool = o.NewDecoderPool(wrp.Msgpack)

		httpClient = &http.Client{
			Transport: o.transport(),
			Timeout:   o.clientTimeout(),
		}

		fanoutEndpoints = make(map[string]endpoint.Endpoint, len(urls))
		customHeader    = http.Header{
			"Accept": []string{"application/msgpack"},
		}
	)

	if authorization := o.authorization(); len(authorization) > 0 {
		customHeader.Set("Authorization", "Basic "+authorization)
	}

	for _, url := range urls {
		fanoutEndpoints[url.String()] =
			gokithttp.NewClient(
				o.method(),
				url,
				ClientEncodeRequestBody(encoderPool, customHeader),
				ClientDecodeResponseBody(decoderPool),
				gokithttp.SetClient(httpClient), gokithttp.ClientBefore(SetGetBodyFunc),
			).Endpoint()
	}

	var (
		middlewareChain = append(
			[]endpoint.Middleware{
				middleware.Logging,
				middleware.Busy(o.maxClients(), &httperror.E{Code: http.StatusServiceUnavailable, Text: "Server Busy"}),
				middleware.Timeout(o.fanoutTimeout()),
				middleware.Concurrent(o.concurrency(), &httperror.E{Code: http.StatusTooManyRequests, Text: "Too Many Requests"}),
			},
			o.middleware()...,
		)
	)

	return endpoint.Chain(
			middlewareChain[0],
			middlewareChain[1:]...,
		)(middleware.Fanout(tracing.NewSpanner(), fanoutEndpoints)),
		nil
}

//SetGetBodyFunc allows reading a request's body multiple times. 307 POST redirects are part of the specific cases
//where this becomes useful
func SetGetBodyFunc(context context.Context, request *http.Request) context.Context {
	if request == nil || request.Body == nil {
		return context
	}

	if freshBodyCopy, err := ioutil.ReadAll(request.Body); err == nil { //read it once and keep a copy
		var keepBuffer bytes.Buffer
		keepBuffer.Write(freshBodyCopy)
		request.Body = ioutil.NopCloser(&keepBuffer) //Extra: Also make request.Body re-readable

		//set up function used by clients such as net/http/client
		request.GetBody = func() (send io.ReadCloser, err error) {
			var sendBuffer bytes.Buffer
			sendBuffer.Write(freshBodyCopy)
			send = ioutil.NopCloser(&sendBuffer)
			return
		}
	}
	return context
}
<|endoftext|>


<commit_before>package toolbox

import (
	"fmt"
	"strings"
	"time"
)

const (
	Now       = "now"
	Tomorrow  = "tomorrow"
	Yesterday = "yesterday"

	//TimeAtTwoHoursAgo   = "2hoursAgo"
	//TimeAtHourAhead     = "hourAhead"
	//TimeAtTwoHoursAhead = "2hoursAhead"

	DurationWeek            = "week"
	DurationDay             = "day"
	DurationHour            = "hour"
	DurationMinute          = "minute"
	DurationMinuteAbbr      = "min"
	DurationSecond          = "second"
	DurationSecondAbbr      = "sec"
	DurationMillisecond     = "millisecond"
	DurationMillisecondAbbr = "ms"
	DurationMicrosecond     = "microsecond"
	DurationMicrosecondAbbr = "us"
	DurationNanosecond      = "nanosecond"
	DurationNanosecondAbbr  = "ns"
)

//AtTime represents a time at given schedule
type AtTime struct {
	WeekDay string
	Hour    string
	Minute  string
	TZ      string
	loc *time.Location
}

func (t *AtTime) min(base time.Time) int {
	switch t.Minute {
	case "*":
		return base.Minute() + 1%59
	case "":
		return 0
	}
	candidates := strings.Split(t.Minute, ",")
	for _, candidate := range candidates {
		candidateMin := AsInt(candidate)
		if base.Minute() < candidateMin {
			return candidateMin
		}
	}
	return AsInt(candidates[0])
}

func (t *AtTime) hour(base time.Time) int {
	min := t.min(base)
	switch t.Hour {
	case "*":
		if min > base.Minute() {
			return base.Hour()
		}
		return base.Hour() + 1%23
	case "":
		return 0
	}
	candidates := strings.Split(t.Hour, ",")
	for _, candidate := range candidates {
		candidateHour := AsInt(candidate)
		if base.Hour() < candidateHour {
			return candidateHour
		}
	}
	return AsInt(candidates[0])
}

func (t *AtTime) weekday(base time.Time) int {
	hour := t.hour(base)
	min := t.min(base)
	baseWeekday := int(base.Weekday())
	isPastDue := hour > base.Hour() || (hour == base.Hour() && min > base.Minute())
	switch t.WeekDay {
	case "*":
		if isPastDue {
			return baseWeekday
		}
		return baseWeekday + 1%7
	case "":
		return 0
	}
	candidates := strings.Split(t.WeekDay, ",")
	result := AsInt(candidates[0])
	for _, candidate := range candidates {
		candidateWeekday := AsInt(candidate)
		if baseWeekday < candidateWeekday {
			result = candidateWeekday
			break
		}
	}
	if result < baseWeekday && isPastDue {
		return 7 + result
	}

	return result
}

//Init initializes tz
func (t *AtTime) Init() error {
	if t.TZ == "" {
		t.TZ = "UTC"
	}
	var err error
	t.loc, err = time.LoadLocation(t.TZ)
	return err
}

//Next returns next time schedule
func (t *AtTime) Next(base time.Time) time.Time {
	if t.loc != nil {
		base = base.In(t.loc)
	}
	min := t.min(base)
	hour := t.hour(base)
	fmt.Printf("%v -> %v\n", t.TZ, base)
	timeLiteral := base.Format("2006-01-02")
	updateTimeLiteral := fmt.Sprintf("%v %02d:%02d:00", timeLiteral, hour, min)
	weekday := t.weekday(base)
	baseWeekday := int(base.Weekday())
	weekdayDiff := 0
	if weekday >= baseWeekday {
		weekdayDiff = weekday - baseWeekday
	} else {
		weekdayDiff = 7 + weekday - baseWeekday
	}
	var result time.Time
	if t.loc != nil {
		result, _ = time.ParseInLocation("2006-01-02 15:04:05", updateTimeLiteral, t.loc)
	} else {
		result, _ = time.Parse("2006-01-02 15:04:05", updateTimeLiteral)
	}
	if weekdayDiff > 0 {
		result = result.Add(time.Hour * 24 * time.Duration(weekdayDiff))
	}
	return result
}

//Duration represents duration
type Duration struct {
	Value int
	Unit  string
}

//Duration return durations
func (d Duration) Duration() (time.Duration, error) {
	return NewDuration(d.Value, d.Unit)
}

//NewDuration returns a durationToken for supplied value and time unit, 3, "second"
func NewDuration(value int, unit string) (time.Duration, error) {
	var duration time.Duration
	switch unit {
	case DurationWeek:
		duration = time.Hour * 24 * 7
	case DurationDay:
		duration = time.Hour * 24
	case DurationHour:
		duration = time.Hour
	case DurationMinute, DurationMinuteAbbr:
		duration = time.Minute
	case DurationSecond, DurationSecondAbbr:
		duration = time.Second
	case DurationMillisecond, DurationMillisecondAbbr:
		duration = time.Millisecond
	case DurationMicrosecond, DurationMicrosecondAbbr:
		duration = time.Microsecond
	case DurationNanosecond, DurationNanosecondAbbr:
		duration = time.Nanosecond
	default:
		return 0, fmt.Errorf("unsupported unit: %v", unit)
	}
	return time.Duration(value) * duration, nil
}

const (
	eofToken     = -1
	invalidToken = iota
	timeValueToken
	nowToken
	yesterdayToken
	tomorrowToken
	whitespacesToken
	durationToken
	inTimezoneToken
	durationPluralToken
	positiveModifierToken
	negativeModifierToken
	timezoneToken
)

var timeAtExpressionMatchers = map[int]Matcher{
	timeValueToken:        NewIntMatcher(),
	whitespacesToken:      CharactersMatcher{" \n\t"},
	durationToken:         NewKeywordsMatcher(false, DurationWeek, DurationDay, DurationHour, DurationMinute, DurationMinuteAbbr, DurationSecond, DurationSecondAbbr, DurationMillisecond, DurationMillisecondAbbr, DurationMicrosecond, DurationMicrosecondAbbr, DurationNanosecond, DurationNanosecondAbbr),
	durationPluralToken:   NewKeywordsMatcher(false, "s"),
	nowToken:              NewKeywordsMatcher(false, Now),
	yesterdayToken:        NewKeywordsMatcher(false, Yesterday),
	tomorrowToken:         NewKeywordsMatcher(false, Tomorrow),
	positiveModifierToken: NewKeywordsMatcher(false, "onward", "ahead", "after", "later", "in the future", "inthefuture"),
	negativeModifierToken: NewKeywordsMatcher(false, "past", "ago", "before", "earlier", "in the past", "inthepast"),
	inTimezoneToken:       NewKeywordsMatcher(false, "in"),
	timezoneToken:         NewRemainingSequenceMatcher(),
	eofToken:              &EOFMatcher{},
}

//TimeAt returns time of now supplied offsetExpression, this function uses TimeDiff
func TimeAt(offsetExpression string) (*time.Time, error) {
	return TimeDiff(time.Now(), offsetExpression)
}

//TimeDiff returns time for supplied base time and literal, the supported literal now, yesterday, tomorrow, or the following template:
// 	- [timeValueToken]  durationToken past_or_future_modifier [IN tz]
// where time modifier can be any of the following:  "onward", "ahead", "after", "later", or "past", "ago", "before", "earlier", "in the future", "in the past") )
func TimeDiff(base time.Time, expression string) (*time.Time, error) {
	if expression == "" {
		return nil, fmt.Errorf("expression was empty")
	}
	var delta time.Duration
	var isNegative = false

	tokenizer := NewTokenizer(expression, invalidToken, eofToken, timeAtExpressionMatchers)
	var val = 1
	var isTimeExtracted = false
	token, err := ExpectToken(tokenizer, "", timeValueToken, nowToken, yesterdayToken, tomorrowToken)
	if err == nil {
		switch token.Token {
		case timeValueToken:
			val, _ = ToInt(token.Matched)
		case yesterdayToken:
			isNegative = true
			fallthrough
		case tomorrowToken:
			delta, _ = NewDuration(1, DurationDay)
			fallthrough
		case nowToken:
			isTimeExtracted = true
		}
	}

	if !isTimeExtracted {
		token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected time unit", durationToken)
		if err != nil {
			return nil, err
		}
		delta, _ = NewDuration(val, strings.ToLower(token.Matched))
		_, _ = ExpectToken(tokenizer, "", durationPluralToken)
		token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected time modifier", positiveModifierToken, negativeModifierToken)
		if err != nil {
			return nil, err
		}
		if token.Token == negativeModifierToken {
			isNegative = true
		}
	}

	if token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected in", inTimezoneToken); err == nil {
		token, err = ExpectToken(tokenizer, "epected timezone", timezoneToken)
		if err != nil {
			return nil, err
		}
		tz := strings.TrimSpace(token.Matched)
		tzLocation, err := time.LoadLocation(tz)
		if err != nil {
			return nil, fmt.Errorf("failed to load timezone tzLocation: %v, %v", tz, err)
		}
		base = base.In(tzLocation)
	}
	token, err = ExpectToken(tokenizer, "expected eofToken", eofToken)
	if err != nil {
		return nil, err
	}
	if isNegative {
		delta *= -1
	}
	base = base.Add(delta)
	return &base, nil
}

//ElapsedToday returns elapsed today time percent, it takes optionally timezone
func ElapsedToday(tz string) (float64, error) {
	if tz != "" {
		tz = "In" + tz
	}
	now, err := TimeAt("now" + tz)
	if err != nil {
		return 0, err
	}
	return ElapsedDay(*now), nil
}

//ElapsedDay returns elapsed pct for passed in day (second elapsed that day over 24 hours)
func ElapsedDay(dateTime time.Time) float64 {
	elapsedToday := time.Duration(dateTime.Hour())*time.Hour + time.Duration(dateTime.Minute())*time.Minute + time.Duration(dateTime.Second()) + time.Second
	elapsedTodayPct := float64(elapsedToday) / float64((24 * time.Hour))
	return elapsedTodayPct
}

//RemainingToday returns remaining today time percent, it takes optionally timezone
func RemainingToday(tz string) (float64, error) {
	elapsedToday, err := ElapsedToday(tz)
	if err != nil {
		return 0, err
	}
	return 1.0 - elapsedToday, nil
}

//TimeWindow represents a time window
type TimeWindow struct {
	Loopback   *Duration
	StartDate  string
	startTime  *time.Time
	EndDate    string
	endTime    *time.Time
	TimeLayout string
	TimeFormat string
	Interval   *Duration
}

//Range iterates with interval step between start and window end.
func (w *TimeWindow) Range(handler func(time time.Time) (bool, error)) error {
	start, err := w.StartTime()
	if err != nil {
		return err
	}

	end, err := w.EndTime()
	if err != nil {
		return err
	}
	if w.Interval == nil && w.Loopback != nil {
		w.Interval = w.Loopback
	}

	if w.Interval == nil {
		_, err = handler(*end)
		return err
	}
	interval, err := w.Interval.Duration()
	if err != nil {
		return err
	}
	for ts := *start; ts.Before(*end) || ts.Equal(*end); ts = ts.Add(interval) {
		if ok, err := handler(ts); err != nil || !ok {
			return err
		}
	}
	return err
}

//Layout return time layout
func (w *TimeWindow) Layout() string {
	if w.TimeLayout != "" {
		return w.TimeLayout
	}
	if w.TimeFormat != "" {
		w.TimeLayout = DateFormatToLayout(w.TimeFormat)
	}
	if w.TimeLayout == "" {
		w.TimeLayout = time.RFC3339
	}
	return w.TimeLayout
}

//StartTime returns time window start time
func (w *TimeWindow) StartTime() (*time.Time, error) {
	if w.StartDate != "" {
		if w.startTime != nil {
			return w.startTime, nil
		}
		timeLayout := w.Layout()
		startTime, err := time.Parse(timeLayout, w.StartDate)
		if err != nil {
			return nil, err
		}
		w.startTime = &startTime
		return w.startTime, nil
	}
	endDate, err := w.EndTime()
	if err != nil {
		return nil, err
	}
	if w.Loopback == nil || w.Loopback.Value == 0 {
		return endDate, nil
	}
	loopback, err := w.Loopback.Duration()
	if err != nil {
		return nil, err
	}
	startTime := endDate.Add(-loopback)
	return &startTime, nil
}

//EndTime returns time window end time
func (w *TimeWindow) EndTime() (*time.Time, error) {
	if w.EndDate != "" {
		if w.endTime != nil {
			return w.endTime, nil
		}
		timeLayout := w.Layout()
		endTime, err := time.Parse(timeLayout, w.EndDate)
		if err != nil {
			return nil, err
		}
		w.endTime = &endTime
		return w.endTime, nil
	}
	now := time.Now()
	return &now, nil
}
<commit_msg>removed debug info<commit_after>package toolbox

import (
	"fmt"
	"strings"
	"time"
)

const (
	Now       = "now"
	Tomorrow  = "tomorrow"
	Yesterday = "yesterday"

	//TimeAtTwoHoursAgo   = "2hoursAgo"
	//TimeAtHourAhead     = "hourAhead"
	//TimeAtTwoHoursAhead = "2hoursAhead"

	DurationWeek            = "week"
	DurationDay             = "day"
	DurationHour            = "hour"
	DurationMinute          = "minute"
	DurationMinuteAbbr      = "min"
	DurationSecond          = "second"
	DurationSecondAbbr      = "sec"
	DurationMillisecond     = "millisecond"
	DurationMillisecondAbbr = "ms"
	DurationMicrosecond     = "microsecond"
	DurationMicrosecondAbbr = "us"
	DurationNanosecond      = "nanosecond"
	DurationNanosecondAbbr  = "ns"
)

//AtTime represents a time at given schedule
type AtTime struct {
	WeekDay string
	Hour    string
	Minute  string
	TZ      string
	loc *time.Location
}

func (t *AtTime) min(base time.Time) int {
	switch t.Minute {
	case "*":
		return base.Minute() + 1%59
	case "":
		return 0
	}
	candidates := strings.Split(t.Minute, ",")
	for _, candidate := range candidates {
		candidateMin := AsInt(candidate)
		if base.Minute() < candidateMin {
			return candidateMin
		}
	}
	return AsInt(candidates[0])
}

func (t *AtTime) hour(base time.Time) int {
	min := t.min(base)
	switch t.Hour {
	case "*":
		if min > base.Minute() {
			return base.Hour()
		}
		return base.Hour() + 1%23
	case "":
		return 0
	}
	candidates := strings.Split(t.Hour, ",")
	for _, candidate := range candidates {
		candidateHour := AsInt(candidate)
		if base.Hour() < candidateHour {
			return candidateHour
		}
	}
	return AsInt(candidates[0])
}

func (t *AtTime) weekday(base time.Time) int {
	hour := t.hour(base)
	min := t.min(base)
	baseWeekday := int(base.Weekday())
	isPastDue := hour > base.Hour() || (hour == base.Hour() && min > base.Minute())
	switch t.WeekDay {
	case "*":
		if isPastDue {
			return baseWeekday
		}
		return baseWeekday + 1%7
	case "":
		return 0
	}
	candidates := strings.Split(t.WeekDay, ",")
	result := AsInt(candidates[0])
	for _, candidate := range candidates {
		candidateWeekday := AsInt(candidate)
		if baseWeekday < candidateWeekday {
			result = candidateWeekday
			break
		}
	}
	if result < baseWeekday && isPastDue {
		return 7 + result
	}

	return result
}

//Init initializes tz
func (t *AtTime) Init() error {
	if t.TZ == "" {
		t.TZ = "UTC"
	}
	var err error
	t.loc, err = time.LoadLocation(t.TZ)
	return err
}

//Next returns next time schedule
func (t *AtTime) Next(base time.Time) time.Time {
	if t.loc != nil {
		base = base.In(t.loc)
	}
	min := t.min(base)
	hour := t.hour(base)
	timeLiteral := base.Format("2006-01-02")
	updateTimeLiteral := fmt.Sprintf("%v %02d:%02d:00", timeLiteral, hour, min)
	weekday := t.weekday(base)
	baseWeekday := int(base.Weekday())
	weekdayDiff := 0
	if weekday >= baseWeekday {
		weekdayDiff = weekday - baseWeekday
	} else {
		weekdayDiff = 7 + weekday - baseWeekday
	}
	var result time.Time
	if t.loc != nil {
		result, _ = time.ParseInLocation("2006-01-02 15:04:05", updateTimeLiteral, t.loc)
	} else {
		result, _ = time.Parse("2006-01-02 15:04:05", updateTimeLiteral)
	}
	if weekdayDiff > 0 {
		result = result.Add(time.Hour * 24 * time.Duration(weekdayDiff))
	}
	return result
}

//Duration represents duration
type Duration struct {
	Value int
	Unit  string
}

//Duration return durations
func (d Duration) Duration() (time.Duration, error) {
	return NewDuration(d.Value, d.Unit)
}

//NewDuration returns a durationToken for supplied value and time unit, 3, "second"
func NewDuration(value int, unit string) (time.Duration, error) {
	var duration time.Duration
	switch unit {
	case DurationWeek:
		duration = time.Hour * 24 * 7
	case DurationDay:
		duration = time.Hour * 24
	case DurationHour:
		duration = time.Hour
	case DurationMinute, DurationMinuteAbbr:
		duration = time.Minute
	case DurationSecond, DurationSecondAbbr:
		duration = time.Second
	case DurationMillisecond, DurationMillisecondAbbr:
		duration = time.Millisecond
	case DurationMicrosecond, DurationMicrosecondAbbr:
		duration = time.Microsecond
	case DurationNanosecond, DurationNanosecondAbbr:
		duration = time.Nanosecond
	default:
		return 0, fmt.Errorf("unsupported unit: %v", unit)
	}
	return time.Duration(value) * duration, nil
}

const (
	eofToken     = -1
	invalidToken = iota
	timeValueToken
	nowToken
	yesterdayToken
	tomorrowToken
	whitespacesToken
	durationToken
	inTimezoneToken
	durationPluralToken
	positiveModifierToken
	negativeModifierToken
	timezoneToken
)

var timeAtExpressionMatchers = map[int]Matcher{
	timeValueToken:        NewIntMatcher(),
	whitespacesToken:      CharactersMatcher{" \n\t"},
	durationToken:         NewKeywordsMatcher(false, DurationWeek, DurationDay, DurationHour, DurationMinute, DurationMinuteAbbr, DurationSecond, DurationSecondAbbr, DurationMillisecond, DurationMillisecondAbbr, DurationMicrosecond, DurationMicrosecondAbbr, DurationNanosecond, DurationNanosecondAbbr),
	durationPluralToken:   NewKeywordsMatcher(false, "s"),
	nowToken:              NewKeywordsMatcher(false, Now),
	yesterdayToken:        NewKeywordsMatcher(false, Yesterday),
	tomorrowToken:         NewKeywordsMatcher(false, Tomorrow),
	positiveModifierToken: NewKeywordsMatcher(false, "onward", "ahead", "after", "later", "in the future", "inthefuture"),
	negativeModifierToken: NewKeywordsMatcher(false, "past", "ago", "before", "earlier", "in the past", "inthepast"),
	inTimezoneToken:       NewKeywordsMatcher(false, "in"),
	timezoneToken:         NewRemainingSequenceMatcher(),
	eofToken:              &EOFMatcher{},
}

//TimeAt returns time of now supplied offsetExpression, this function uses TimeDiff
func TimeAt(offsetExpression string) (*time.Time, error) {
	return TimeDiff(time.Now(), offsetExpression)
}

//TimeDiff returns time for supplied base time and literal, the supported literal now, yesterday, tomorrow, or the following template:
// 	- [timeValueToken]  durationToken past_or_future_modifier [IN tz]
// where time modifier can be any of the following:  "onward", "ahead", "after", "later", or "past", "ago", "before", "earlier", "in the future", "in the past") )
func TimeDiff(base time.Time, expression string) (*time.Time, error) {
	if expression == "" {
		return nil, fmt.Errorf("expression was empty")
	}
	var delta time.Duration
	var isNegative = false

	tokenizer := NewTokenizer(expression, invalidToken, eofToken, timeAtExpressionMatchers)
	var val = 1
	var isTimeExtracted = false
	token, err := ExpectToken(tokenizer, "", timeValueToken, nowToken, yesterdayToken, tomorrowToken)
	if err == nil {
		switch token.Token {
		case timeValueToken:
			val, _ = ToInt(token.Matched)
		case yesterdayToken:
			isNegative = true
			fallthrough
		case tomorrowToken:
			delta, _ = NewDuration(1, DurationDay)
			fallthrough
		case nowToken:
			isTimeExtracted = true
		}
	}

	if !isTimeExtracted {
		token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected time unit", durationToken)
		if err != nil {
			return nil, err
		}
		delta, _ = NewDuration(val, strings.ToLower(token.Matched))
		_, _ = ExpectToken(tokenizer, "", durationPluralToken)
		token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected time modifier", positiveModifierToken, negativeModifierToken)
		if err != nil {
			return nil, err
		}
		if token.Token == negativeModifierToken {
			isNegative = true
		}
	}

	if token, err = ExpectTokenOptionallyFollowedBy(tokenizer, whitespacesToken, "expected in", inTimezoneToken); err == nil {
		token, err = ExpectToken(tokenizer, "epected timezone", timezoneToken)
		if err != nil {
			return nil, err
		}
		tz := strings.TrimSpace(token.Matched)
		tzLocation, err := time.LoadLocation(tz)
		if err != nil {
			return nil, fmt.Errorf("failed to load timezone tzLocation: %v, %v", tz, err)
		}
		base = base.In(tzLocation)
	}
	token, err = ExpectToken(tokenizer, "expected eofToken", eofToken)
	if err != nil {
		return nil, err
	}
	if isNegative {
		delta *= -1
	}
	base = base.Add(delta)
	return &base, nil
}

//ElapsedToday returns elapsed today time percent, it takes optionally timezone
func ElapsedToday(tz string) (float64, error) {
	if tz != "" {
		tz = "In" + tz
	}
	now, err := TimeAt("now" + tz)
	if err != nil {
		return 0, err
	}
	return ElapsedDay(*now), nil
}

//ElapsedDay returns elapsed pct for passed in day (second elapsed that day over 24 hours)
func ElapsedDay(dateTime time.Time) float64 {
	elapsedToday := time.Duration(dateTime.Hour())*time.Hour + time.Duration(dateTime.Minute())*time.Minute + time.Duration(dateTime.Second()) + time.Second
	elapsedTodayPct := float64(elapsedToday) / float64((24 * time.Hour))
	return elapsedTodayPct
}

//RemainingToday returns remaining today time percent, it takes optionally timezone
func RemainingToday(tz string) (float64, error) {
	elapsedToday, err := ElapsedToday(tz)
	if err != nil {
		return 0, err
	}
	return 1.0 - elapsedToday, nil
}

//TimeWindow represents a time window
type TimeWindow struct {
	Loopback   *Duration
	StartDate  string
	startTime  *time.Time
	EndDate    string
	endTime    *time.Time
	TimeLayout string
	TimeFormat string
	Interval   *Duration
}

//Range iterates with interval step between start and window end.
func (w *TimeWindow) Range(handler func(time time.Time) (bool, error)) error {
	start, err := w.StartTime()
	if err != nil {
		return err
	}

	end, err := w.EndTime()
	if err != nil {
		return err
	}
	if w.Interval == nil && w.Loopback != nil {
		w.Interval = w.Loopback
	}

	if w.Interval == nil {
		_, err = handler(*end)
		return err
	}
	interval, err := w.Interval.Duration()
	if err != nil {
		return err
	}
	for ts := *start; ts.Before(*end) || ts.Equal(*end); ts = ts.Add(interval) {
		if ok, err := handler(ts); err != nil || !ok {
			return err
		}
	}
	return err
}

//Layout return time layout
func (w *TimeWindow) Layout() string {
	if w.TimeLayout != "" {
		return w.TimeLayout
	}
	if w.TimeFormat != "" {
		w.TimeLayout = DateFormatToLayout(w.TimeFormat)
	}
	if w.TimeLayout == "" {
		w.TimeLayout = time.RFC3339
	}
	return w.TimeLayout
}

//StartTime returns time window start time
func (w *TimeWindow) StartTime() (*time.Time, error) {
	if w.StartDate != "" {
		if w.startTime != nil {
			return w.startTime, nil
		}
		timeLayout := w.Layout()
		startTime, err := time.Parse(timeLayout, w.StartDate)
		if err != nil {
			return nil, err
		}
		w.startTime = &startTime
		return w.startTime, nil
	}
	endDate, err := w.EndTime()
	if err != nil {
		return nil, err
	}
	if w.Loopback == nil || w.Loopback.Value == 0 {
		return endDate, nil
	}
	loopback, err := w.Loopback.Duration()
	if err != nil {
		return nil, err
	}
	startTime := endDate.Add(-loopback)
	return &startTime, nil
}

//EndTime returns time window end time
func (w *TimeWindow) EndTime() (*time.Time, error) {
	if w.EndDate != "" {
		if w.endTime != nil {
			return w.endTime, nil
		}
		timeLayout := w.Layout()
		endTime, err := time.Parse(timeLayout, w.EndDate)
		if err != nil {
			return nil, err
		}
		w.endTime = &endTime
		return w.endTime, nil
	}
	now := time.Now()
	return &now, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package app does all of the work necessary to create a Kubernetes
// APIServer by binding together the API, master and APIServer infrastructure.
// It can be configured and called directly or via the hyperkube cache.
package app

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/pborman/uuid"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
	"k8s.io/kubernetes/pkg/admission"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apiserver/authenticator"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	"k8s.io/kubernetes/pkg/controller/informers"
	"k8s.io/kubernetes/pkg/generated/openapi"
	"k8s.io/kubernetes/pkg/genericapiserver"
	"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
	"k8s.io/kubernetes/pkg/registry/cachesize"
	"k8s.io/kubernetes/pkg/registry/generic"
	genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry"
	"k8s.io/kubernetes/pkg/routes"
	"k8s.io/kubernetes/pkg/runtime/schema"
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/version"
)

// NewAPIServerCommand creates a *cobra.Command object with default parameters
func NewAPIServerCommand() *cobra.Command {
	s := options.NewServerRunOptions()
	s.AddFlags(pflag.CommandLine)
	cmd := &cobra.Command{
		Use: "federation-apiserver",
		Long: `The Kubernetes federation API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
		Run: func(cmd *cobra.Command, args []string) {
		},
	}
	return cmd
}

// Run runs the specified APIServer.  This should never exit.
func Run(s *options.ServerRunOptions) error {
	if errs := s.Etcd.Validate(); len(errs) > 0 {
		utilerrors.NewAggregate(errs)
	}
	if err := s.GenericServerRunOptions.DefaultExternalAddress(s.SecureServing, s.InsecureServing); err != nil {
		return err
	}

	if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
		return fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
	genericConfig, err := genericapiserver.NewConfig(). // create the new config
								ApplyOptions(s.GenericServerRunOptions). // apply the options selected
								ApplyInsecureServingOptions(s.InsecureServing).
								ApplyAuthenticationOptions(s.Authentication).
								ApplySecureServingOptions(s.SecureServing)
	if err != nil {
		return fmt.Errorf("failed to configure https: %s", err)
	}

	// TODO: register cluster federation resources here.
	resourceConfig := genericapiserver.NewResourceConfig()

	if s.Etcd.StorageConfig.DeserializationCacheSize == 0 {
		// When size of cache is not explicitly set, set it to 50000
		s.Etcd.StorageConfig.DeserializationCacheSize = 50000
	}
	storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
	if err != nil {
		glog.Fatalf("error generating storage version map: %s", err)
	}
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
		[]schema.GroupVersionResource{}, resourceConfig, s.GenericServerRunOptions.RuntimeConfig)
	if err != nil {
		glog.Fatalf("error in initializing storage factory: %s", err)
	}

	for _, override := range s.Etcd.EtcdServersOverrides {
		tokens := strings.Split(override, "#")
		if len(tokens) != 2 {
			glog.Errorf("invalid value of etcd server overrides: %s", override)
			continue
		}

		apiresource := strings.Split(tokens[0], "/")
		if len(apiresource) != 2 {
			glog.Errorf("invalid resource definition: %s", tokens[0])
			continue
		}
		group := apiresource[0]
		resource := apiresource[1]
		groupResource := schema.GroupResource{Group: group, Resource: resource}

		servers := strings.Split(tokens[1], ";")
		storageFactory.SetEtcdLocation(groupResource, servers)
	}

	apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA))
	if err != nil {
		glog.Fatalf("Invalid Authentication Config: %v", err)
	}

	privilegedLoopbackToken := uuid.NewRandom().String()
	selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken)
	if err != nil {
		glog.Fatalf("Failed to create clientset: %v", err)
	}
	client, err := internalclientset.NewForConfig(selfClientConfig)
	if err != nil {
		glog.Errorf("Failed to create clientset: %v", err)
	}
	sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)

	authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
	apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig)
	if err != nil {
		glog.Fatalf("Invalid Authorization Config: %v", err)
	}

	admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
	pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
	admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
	if err != nil {
		glog.Fatalf("Failed to initialize plugins: %v", err)
	}

	kubeVersion := version.Get()
	genericConfig.Version = &kubeVersion
	genericConfig.LoopbackClientConfig = selfClientConfig
	genericConfig.Authenticator = apiAuthenticator
	genericConfig.Authorizer = apiAuthorizer
	genericConfig.AdmissionControl = admissionController
	genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
	genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
	genericConfig.EnableOpenAPISupport = true
	genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions

	// TODO: Move this to generic api server (Need to move the command line flag).
	if s.GenericServerRunOptions.EnableWatchCache {
		cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
		cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
	}

	m, err := genericConfig.Complete().New()
	if err != nil {
		return err
	}

	routes.UIRedirect{}.Install(m.HandlerContainer)
	routes.Logs{}.Install(m.HandlerContainer)

	// TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here.
	restOptionsFactory := restOptionsFactory{
		storageFactory:          storageFactory,
		enableGarbageCollection: s.GenericServerRunOptions.EnableGarbageCollection,
		deleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers,
	}
	if s.GenericServerRunOptions.EnableWatchCache {
		restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher
	} else {
		restOptionsFactory.storageDecorator = generic.UndecoratedStorage
	}

	installFederationAPIs(m, restOptionsFactory)
	installCoreAPIs(s, m, restOptionsFactory)
	installExtensionsAPIs(m, restOptionsFactory)

	sharedInformers.Start(wait.NeverStop)
	m.PrepareRun().Run(wait.NeverStop)
	return nil
}

type restOptionsFactory struct {
	storageFactory          genericapiserver.StorageFactory
	storageDecorator        generic.StorageDecorator
	deleteCollectionWorkers int
	enableGarbageCollection bool
}

func (f restOptionsFactory) NewFor(resource schema.GroupResource) generic.RESTOptions {
	config, err := f.storageFactory.NewConfig(resource)
	if err != nil {
		glog.Fatalf("Unable to find storage config for %v, due to %v", resource, err.Error())
	}
	return generic.RESTOptions{
		StorageConfig:           config,
		Decorator:               f.storageDecorator,
		DeleteCollectionWorkers: f.deleteCollectionWorkers,
		EnableGarbageCollection: f.enableGarbageCollection,
		ResourcePrefix:          f.storageFactory.ResourcePrefix(resource),
	}
}
<commit_msg>move APIResourceConfigSource to master<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package app does all of the work necessary to create a Kubernetes
// APIServer by binding together the API, master and APIServer infrastructure.
// It can be configured and called directly or via the hyperkube cache.
package app

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/pborman/uuid"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
	"k8s.io/kubernetes/pkg/admission"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apiserver/authenticator"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	"k8s.io/kubernetes/pkg/controller/informers"
	"k8s.io/kubernetes/pkg/generated/openapi"
	"k8s.io/kubernetes/pkg/genericapiserver"
	"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
	"k8s.io/kubernetes/pkg/registry/cachesize"
	"k8s.io/kubernetes/pkg/registry/generic"
	genericregistry "k8s.io/kubernetes/pkg/registry/generic/registry"
	"k8s.io/kubernetes/pkg/routes"
	"k8s.io/kubernetes/pkg/runtime/schema"
	utilerrors "k8s.io/kubernetes/pkg/util/errors"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/version"
)

// NewAPIServerCommand creates a *cobra.Command object with default parameters
func NewAPIServerCommand() *cobra.Command {
	s := options.NewServerRunOptions()
	s.AddFlags(pflag.CommandLine)
	cmd := &cobra.Command{
		Use: "federation-apiserver",
		Long: `The Kubernetes federation API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
		Run: func(cmd *cobra.Command, args []string) {
		},
	}
	return cmd
}

// Run runs the specified APIServer.  This should never exit.
func Run(s *options.ServerRunOptions) error {
	if errs := s.Etcd.Validate(); len(errs) > 0 {
		utilerrors.NewAggregate(errs)
	}
	if err := s.GenericServerRunOptions.DefaultExternalAddress(s.SecureServing, s.InsecureServing); err != nil {
		return err
	}

	if err := s.SecureServing.MaybeDefaultWithSelfSignedCerts(s.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
		return fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
	genericConfig, err := genericapiserver.NewConfig(). // create the new config
								ApplyOptions(s.GenericServerRunOptions). // apply the options selected
								ApplyInsecureServingOptions(s.InsecureServing).
								ApplyAuthenticationOptions(s.Authentication).
								ApplySecureServingOptions(s.SecureServing)
	if err != nil {
		return fmt.Errorf("failed to configure https: %s", err)
	}

	// TODO: register cluster federation resources here.
	resourceConfig := genericapiserver.NewResourceConfig()

	if s.Etcd.StorageConfig.DeserializationCacheSize == 0 {
		// When size of cache is not explicitly set, set it to 50000
		s.Etcd.StorageConfig.DeserializationCacheSize = 50000
	}
	storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
	if err != nil {
		glog.Fatalf("error generating storage version map: %s", err)
	}
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
		[]schema.GroupVersionResource{}, resourceConfig, s.GenericServerRunOptions.RuntimeConfig)
	if err != nil {
		glog.Fatalf("error in initializing storage factory: %s", err)
	}

	for _, override := range s.Etcd.EtcdServersOverrides {
		tokens := strings.Split(override, "#")
		if len(tokens) != 2 {
			glog.Errorf("invalid value of etcd server overrides: %s", override)
			continue
		}

		apiresource := strings.Split(tokens[0], "/")
		if len(apiresource) != 2 {
			glog.Errorf("invalid resource definition: %s", tokens[0])
			continue
		}
		group := apiresource[0]
		resource := apiresource[1]
		groupResource := schema.GroupResource{Group: group, Resource: resource}

		servers := strings.Split(tokens[1], ";")
		storageFactory.SetEtcdLocation(groupResource, servers)
	}

	apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA))
	if err != nil {
		glog.Fatalf("Invalid Authentication Config: %v", err)
	}

	privilegedLoopbackToken := uuid.NewRandom().String()
	selfClientConfig, err := genericapiserver.NewSelfClientConfig(genericConfig.SecureServingInfo, genericConfig.InsecureServingInfo, privilegedLoopbackToken)
	if err != nil {
		glog.Fatalf("Failed to create clientset: %v", err)
	}
	client, err := internalclientset.NewForConfig(selfClientConfig)
	if err != nil {
		glog.Errorf("Failed to create clientset: %v", err)
	}
	sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)

	authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
	apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig)
	if err != nil {
		glog.Fatalf("Invalid Authorization Config: %v", err)
	}

	admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
	pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
	admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
	if err != nil {
		glog.Fatalf("Failed to initialize plugins: %v", err)
	}

	kubeVersion := version.Get()
	genericConfig.Version = &kubeVersion
	genericConfig.LoopbackClientConfig = selfClientConfig
	genericConfig.Authenticator = apiAuthenticator
	genericConfig.Authorizer = apiAuthorizer
	genericConfig.AdmissionControl = admissionController
	genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
	genericConfig.EnableOpenAPISupport = true
	genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions

	// TODO: Move this to generic api server (Need to move the command line flag).
	if s.GenericServerRunOptions.EnableWatchCache {
		cachesize.InitializeWatchCacheSizes(s.GenericServerRunOptions.TargetRAMMB)
		cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
	}

	m, err := genericConfig.Complete().New()
	if err != nil {
		return err
	}

	routes.UIRedirect{}.Install(m.HandlerContainer)
	routes.Logs{}.Install(m.HandlerContainer)

	// TODO: Refactor this code to share it with kube-apiserver rather than duplicating it here.
	restOptionsFactory := restOptionsFactory{
		storageFactory:          storageFactory,
		enableGarbageCollection: s.GenericServerRunOptions.EnableGarbageCollection,
		deleteCollectionWorkers: s.GenericServerRunOptions.DeleteCollectionWorkers,
	}
	if s.GenericServerRunOptions.EnableWatchCache {
		restOptionsFactory.storageDecorator = genericregistry.StorageWithCacher
	} else {
		restOptionsFactory.storageDecorator = generic.UndecoratedStorage
	}

	installFederationAPIs(m, restOptionsFactory)
	installCoreAPIs(s, m, restOptionsFactory)
	installExtensionsAPIs(m, restOptionsFactory)

	sharedInformers.Start(wait.NeverStop)
	m.PrepareRun().Run(wait.NeverStop)
	return nil
}

type restOptionsFactory struct {
	storageFactory          genericapiserver.StorageFactory
	storageDecorator        generic.StorageDecorator
	deleteCollectionWorkers int
	enableGarbageCollection bool
}

func (f restOptionsFactory) NewFor(resource schema.GroupResource) generic.RESTOptions {
	config, err := f.storageFactory.NewConfig(resource)
	if err != nil {
		glog.Fatalf("Unable to find storage config for %v, due to %v", resource, err.Error())
	}
	return generic.RESTOptions{
		StorageConfig:           config,
		Decorator:               f.storageDecorator,
		DeleteCollectionWorkers: f.deleteCollectionWorkers,
		EnableGarbageCollection: f.enableGarbageCollection,
		ResourcePrefix:          f.storageFactory.ResourcePrefix(resource),
	}
}
<|endoftext|>


<commit_before>package tmo

import (
	"image"
	"image/color"
	"math"
	"sync"

	colorful "github.com/lucasb-eyer/go-colorful"
	"github.com/mdouchement/hdr"
	"github.com/mdouchement/hdr/util"
)

// A Drago03 is an adaptive TMO implementation based on Frederic Drago's 2003 white paper.
//
// Reference:
// http://resources.mpi-inf.mpg.de/tmo/logmap/
type Drago03 struct {
	HDRImage hdr.Image
	Bias     float64
	lumOnce  sync.Once
	maxLum   float64
	avgLum   float64
	divider  float64
	biasP    float64
}

// NewDefaultDrago03 instanciates a new Drago03 TMO with default parameters.
func NewDefaultDrago03(m hdr.Image) *Drago03 {
	return NewDrago03(m, 0.5)
}

// NewDrago03 instanciates a new Drago03 TMO.
func NewDrago03(m hdr.Image, bias float64) *Drago03 {
	return &Drago03{
		HDRImage: m,
		// Bias is included in [0, 1] with 0.01 increment step.
		Bias: bias,
	}
}

// Perform runs the TMO mapping.
func (t *Drago03) Perform() image.Image {
	img := image.NewRGBA64(t.HDRImage.Bounds())

	t.biasP = math.Log10(t.Bias) / math.Log(0.5)

	t.lumOnce.Do(t.luminance)
	t.tonemap(img)

	return img
}

func (t *Drago03) luminance() {
	avgCh := make(chan float64)
	maxCh := make(chan float64)

	completed := util.ParallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		var avg float64
		var max float64

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				_, lum, _, _ := pixel.HDRXYZA()

				avg += math.Log(lum + 1e-4)
				max = math.Max(t.maxLum, lum)
			}
		}

		avgCh <- avg
		maxCh <- max
	})

	for {
		select {
		case <-completed:
			goto NEXT
		case avg := <-avgCh:
			t.avgLum += avg
		case max := <-maxCh:
			t.maxLum = math.Max(t.maxLum, max)
		}
	}
NEXT:

	t.avgLum = math.Exp(t.avgLum / float64(t.HDRImage.Size()))
	// Normalize
	t.maxLum = t.maxLum / t.avgLum
	// Set divider
	t.divider = math.Log10(t.maxLum + 1.0)
}

func (t *Drago03) tonemap(img *image.RGBA64) {
	completed := util.ParallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		var lumAvgRatio float64
		var newLum float64

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				xx, yy, zz, _ := pixel.HDRXYZA()

				// Core Drago Equation
				lumAvgRatio = yy / t.avgLum
				newLum = (math.Log(lumAvgRatio+1.0) / math.Log(2.0+math.Pow(lumAvgRatio/t.maxLum, t.biasP)*8.0)) / t.divider

				// Re-scale to new luminance
				scale := newLum / yy
				xx *= scale
				yy *= scale
				zz *= scale

				// XYZ color-space to RGB conversion
				r, g, b := colorful.XyzToLinearRgb(xx, yy, zz)
				img.SetRGBA64(x, y, color.RGBA64{
					R: t.normalize(r),
					G: t.normalize(g),
					B: t.normalize(b),
					A: RangeMax,
				})
			}
		}
	})

	<-completed
}

func (t *Drago03) normalize(channel float64) uint16 {
	// Inverse pixel mapping
	channel = LinearInversePixelMapping(channel, LumPixFloor, LumSize)

	// Clamp to solid black and solid white
	channel = Clamp(channel)

	return uint16(channel)
}
<commit_msg>Fix Drago03 max luminance search<commit_after>package tmo

import (
	"image"
	"image/color"
	"math"
	"sync"

	colorful "github.com/lucasb-eyer/go-colorful"
	"github.com/mdouchement/hdr"
	"github.com/mdouchement/hdr/util"
)

// A Drago03 is an adaptive TMO implementation based on Frederic Drago's 2003 white paper.
//
// Reference:
// http://resources.mpi-inf.mpg.de/tmo/logmap/
type Drago03 struct {
	HDRImage hdr.Image
	Bias     float64
	lumOnce  sync.Once
	maxLum   float64
	avgLum   float64
	divider  float64
	biasP    float64
}

// NewDefaultDrago03 instanciates a new Drago03 TMO with default parameters.
func NewDefaultDrago03(m hdr.Image) *Drago03 {
	return NewDrago03(m, 0.5)
}

// NewDrago03 instanciates a new Drago03 TMO.
func NewDrago03(m hdr.Image, bias float64) *Drago03 {
	return &Drago03{
		HDRImage: m,
		// Bias is included in [0, 1] with 0.01 increment step.
		Bias: bias,
	}
}

// Perform runs the TMO mapping.
func (t *Drago03) Perform() image.Image {
	img := image.NewRGBA64(t.HDRImage.Bounds())

	t.biasP = math.Log10(t.Bias) / math.Log(0.5)

	t.lumOnce.Do(t.luminance)
	t.tonemap(img)

	return img
}

func (t *Drago03) luminance() {
	avgCh := make(chan float64)
	maxCh := make(chan float64)

	completed := util.ParallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		var avg float64
		var max float64

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				_, lum, _, _ := pixel.HDRXYZA()

				avg += math.Log(lum + 1e-4)
				max = math.Max(max, lum)
			}
		}

		avgCh <- avg
		maxCh <- max
	})

	for {
		select {
		case <-completed:
			goto NEXT
		case avg := <-avgCh:
			t.avgLum += avg
		case max := <-maxCh:
			t.maxLum = math.Max(t.maxLum, max)
		}
	}
NEXT:

	t.avgLum = math.Exp(t.avgLum / float64(t.HDRImage.Size()))
	// Normalize
	t.maxLum = t.maxLum / t.avgLum
	// Set divider
	t.divider = math.Log10(t.maxLum + 1.0)
}

func (t *Drago03) tonemap(img *image.RGBA64) {
	completed := util.ParallelR(t.HDRImage.Bounds(), func(x1, y1, x2, y2 int) {
		var lumAvgRatio float64
		var newLum float64

		for y := y1; y < y2; y++ {
			for x := x1; x < x2; x++ {
				pixel := t.HDRImage.HDRAt(x, y)
				xx, yy, zz, _ := pixel.HDRXYZA()

				// Core Drago Equation
				lumAvgRatio = yy / t.avgLum
				newLum = (math.Log(lumAvgRatio+1.0) / math.Log(2.0+math.Pow(lumAvgRatio/t.maxLum, t.biasP)*8.0)) / t.divider

				// Re-scale to new luminance
				scale := newLum / yy
				xx *= scale
				yy *= scale
				zz *= scale

				// XYZ color-space to RGB conversion
				r, g, b := colorful.XyzToLinearRgb(xx, yy, zz)
				img.SetRGBA64(x, y, color.RGBA64{
					R: t.normalize(r),
					G: t.normalize(g),
					B: t.normalize(b),
					A: RangeMax,
				})
			}
		}
	})

	<-completed
}

func (t *Drago03) normalize(channel float64) uint16 {
	// Inverse pixel mapping
	channel = LinearInversePixelMapping(channel, LumPixFloor, LumSize)

	// Clamp to solid black and solid white
	channel = Clamp(channel)

	return uint16(channel)
}
<|endoftext|>


<commit_before>package todo

import (
	"encoding/json"
	"time"

	"github.com/antlinker/go-mqtt/client"
	"github.com/antlinker/sdk/asapi"
	"github.com/satori/go.uuid"
)

// NewHandle 创建待办事项处理
func NewHandle(auh *asapi.AuthorizeHandle, mqcli client.MqttClienter) *Handle {
	return &Handle{
		auh:   auh,
		mqcli: mqcli,
	}
}

// Handle 待办事项处理
type Handle struct {
	auh   *asapi.AuthorizeHandle
	mqcli client.MqttClienter
}

// AddRequest 增加待办事项请求参数
type AddRequest struct {
	UIDs         []string
	BuID         string
	TodoType     string
	ContentValue map[string]string
	URIValue     map[string]string
	PushValue    map[string]string
	PubTime      time.Time
	EndTime      time.Time
	Status       int
}

// Add 增加待办事项
func (h *Handle) Add(req *AddRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UIDs...)
	if ar != nil {
		err = ar
		return
	}

	mreq := map[string]interface{}{
		"MT":           "ADDTODO",
		"AID":          uuid.NewV4().String(),
		"UIDs":         auids,
		"TodoType":     req.TodoType,
		"ContentValue": req.ContentValue,
		"URIValue":     req.URIValue,
		"PushValue":    req.PushValue,
		"Status":       req.Status,
		"BuID":         req.BuID,
	}

	if !req.PubTime.IsZero() {
		mreq["PubTime"] = req.PubTime.Format("20060102150405")
	}

	if !req.EndTime.IsZero() {
		mreq["EndTime"] = req.EndTime.Format("20060102150405")
	}

	err = h.publish(mreq)
	return
}

// DoneRequest 完成待办事项请求参数
type DoneRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Done 完成待办事项
func (h *Handle) Done(req *DoneRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DONETODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

// DelRequest 删除待办事项请求参数
type DelRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Del 删除待办事项
func (h *Handle) Del(req *DelRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DELTODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

func (h *Handle) publish(data interface{}) (err error) {
	buf, err := json.Marshal(data)
	if err != nil {
		return
	}

	_, err = h.mqcli.Publish("S/TODO", client.QoS1, false, buf)
	return
}
<commit_msg>update todo<commit_after>package todo

import (
	"encoding/json"
	"time"

	"github.com/antlinker/go-mqtt/client"
	"github.com/antlinker/sdk/asapi"
	"github.com/satori/go.uuid"
)

// NewHandle 创建待办事项处理
func NewHandle(auh *asapi.AuthorizeHandle, mqcli client.MqttClienter) *Handle {
	return &Handle{
		auh:   auh,
		mqcli: mqcli,
	}
}

// Handle 待办事项处理
type Handle struct {
	auh   *asapi.AuthorizeHandle
	mqcli client.MqttClienter
}

// AddRequest 增加待办事项请求参数
type AddRequest struct {
	UIDs         []string
	BuID         string
	TodoType     string
	ContentValue map[string]string
	URIValue     map[string]string
	PushValue    map[string]string
	PubTime      time.Time
	EndTime      time.Time
	Status       int
	Service      string
}

// Add 增加待办事项
func (h *Handle) Add(req *AddRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList(req.Service, req.UIDs...)
	if ar != nil {
		err = ar
		return
	}

	mreq := map[string]interface{}{
		"MT":           "ADDTODO",
		"AID":          uuid.NewV4().String(),
		"UIDs":         auids,
		"TodoType":     req.TodoType,
		"ContentValue": req.ContentValue,
		"URIValue":     req.URIValue,
		"PushValue":    req.PushValue,
		"Status":       req.Status,
		"BuID":         req.BuID,
	}

	if !req.PubTime.IsZero() {
		mreq["PubTime"] = req.PubTime.Format("20060102150405")
	}

	if !req.EndTime.IsZero() {
		mreq["EndTime"] = req.EndTime.Format("20060102150405")
	}

	err = h.publish(mreq)
	return
}

// DoneRequest 完成待办事项请求参数
type DoneRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Done 完成待办事项
func (h *Handle) Done(req *DoneRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DONETODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

// DelRequest 删除待办事项请求参数
type DelRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Del 删除待办事项
func (h *Handle) Del(req *DelRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DELTODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

func (h *Handle) publish(data interface{}) (err error) {
	buf, err := json.Marshal(data)
	if err != nil {
		return
	}

	_, err = h.mqcli.Publish("S/TODO", client.QoS1, false, buf)
	return
}
<|endoftext|>


<commit_before>package token

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"sync"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

const (
	// TokenTimeout is the period of time in seconds that a token is valid for.
	// If the timestamp for token issue is not within the last hour, APNs
	// rejects subsequent push messages. This is set to under an hour so that
	// we generate a new token before the existing one expires.
	TokenTimeout = 3000
)

// Possible errors when parsing a .p8 file.
var (
	ErrAuthKeyNotPem   = errors.New("token: AuthKey must be a valid .p8 PEM file")
	ErrAuthKeyNotECDSA = errors.New("token: AuthKey must be of type ecdsa.PrivateKey")
	ErrAuthKeyNil      = errors.New("token: AuthKey was nil")
)

// Token represents an Apple Provider Authentication Token (JSON Web Token).
type Token struct {
	sync.Mutex
	AuthKey  *ecdsa.PrivateKey
	KeyID    string
	TeamID   string
	IssuedAt int64
	Bearer   string
}

// AuthKeyFromFile loads a .p8 certificate from a local file and returns a
// *ecdsa.PrivateKey.
func AuthKeyFromFile(filename string) (*ecdsa.PrivateKey, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return AuthKeyFromBytes(bytes)
}

// AuthKeyFromBytes loads a .p8 certificate from an in memory byte array and
// returns an *ecdsa.PrivateKey.
func AuthKeyFromBytes(bytes []byte) (*ecdsa.PrivateKey, error) {
	block, _ := pem.Decode(bytes)
	if block == nil {
		return nil, ErrAuthKeyNotPem
	}
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	switch pk := key.(type) {
	case *ecdsa.PrivateKey:
		return pk, nil
	default:
		return nil, ErrAuthKeyNotECDSA
	}
}

// GenerateIfExpired checks to see if the token is about to expire and
// generates a new token.
func (t *Token) GenerateIfExpired() (bearer string) {
	t.Lock()
	defer t.Unlock()
	if t.Expired() {
		t.Generate()
	}
	return t.Bearer
}

// Expired checks to see if the token has expired.
func (t *Token) Expired() bool {
	return time.Now().Unix() >= (t.IssuedAt + TokenTimeout)
}

// Generate creates a new token.
func (t *Token) Generate() (bool, error) {
	if t.AuthKey == nil {
		return false, ErrAuthKeyNil
	}
	issuedAt := time.Now().Unix()
	jwtToken := &jwt.Token{
		Header: map[string]interface{}{
			"alg": "ES256",
			"kid": t.KeyID,
		},
		Claims: jwt.MapClaims{
			"iss": t.TeamID,
			"iat": issuedAt,
		},
		Method: jwt.SigningMethodES256,
	}
	bearer, err := jwtToken.SignedString(t.AuthKey)
	if err != nil {
		return false, err
	}
	t.IssuedAt = issuedAt
	t.Bearer = bearer
	return true, nil
}
<commit_msg>Use if type conditional (#198)<commit_after>package token

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"sync"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

const (
	// TokenTimeout is the period of time in seconds that a token is valid for.
	// If the timestamp for token issue is not within the last hour, APNs
	// rejects subsequent push messages. This is set to under an hour so that
	// we generate a new token before the existing one expires.
	TokenTimeout = 3000
)

// Possible errors when parsing a .p8 file.
var (
	ErrAuthKeyNotPem   = errors.New("token: AuthKey must be a valid .p8 PEM file")
	ErrAuthKeyNotECDSA = errors.New("token: AuthKey must be of type ecdsa.PrivateKey")
	ErrAuthKeyNil      = errors.New("token: AuthKey was nil")
)

// Token represents an Apple Provider Authentication Token (JSON Web Token).
type Token struct {
	sync.Mutex
	AuthKey  *ecdsa.PrivateKey
	KeyID    string
	TeamID   string
	IssuedAt int64
	Bearer   string
}

// AuthKeyFromFile loads a .p8 certificate from a local file and returns a
// *ecdsa.PrivateKey.
func AuthKeyFromFile(filename string) (*ecdsa.PrivateKey, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return AuthKeyFromBytes(bytes)
}

// AuthKeyFromBytes loads a .p8 certificate from an in memory byte array and
// returns an *ecdsa.PrivateKey.
func AuthKeyFromBytes(bytes []byte) (*ecdsa.PrivateKey, error) {
	block, _ := pem.Decode(bytes)
	if block == nil {
		return nil, ErrAuthKeyNotPem
	}
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	if pk, ok := key.(*ecdsa.PrivateKey); ok {
		return pk, nil
	}
	return nil, ErrAuthKeyNotECDSA
}

// GenerateIfExpired checks to see if the token is about to expire and
// generates a new token.
func (t *Token) GenerateIfExpired() (bearer string) {
	t.Lock()
	defer t.Unlock()
	if t.Expired() {
		t.Generate()
	}
	return t.Bearer
}

// Expired checks to see if the token has expired.
func (t *Token) Expired() bool {
	return time.Now().Unix() >= (t.IssuedAt + TokenTimeout)
}

// Generate creates a new token.
func (t *Token) Generate() (bool, error) {
	if t.AuthKey == nil {
		return false, ErrAuthKeyNil
	}
	issuedAt := time.Now().Unix()
	jwtToken := &jwt.Token{
		Header: map[string]interface{}{
			"alg": "ES256",
			"kid": t.KeyID,
		},
		Claims: jwt.MapClaims{
			"iss": t.TeamID,
			"iat": issuedAt,
		},
		Method: jwt.SigningMethodES256,
	}
	bearer, err := jwtToken.SignedString(t.AuthKey)
	if err != nil {
		return false, err
	}
	t.IssuedAt = issuedAt
	t.Bearer = bearer
	return true, nil
}
<|endoftext|>


<commit_before>/*
 * Human-friendly token generator
 *     Copyright (c) 2017, Christian Muehlhaeuser <muesli@gmail.com>
 *
 *   For license see LICENSE
 */

package toktok

import (
	"testing"
)

var ()

func TestCodeGen(t *testing.T) {
	length := uint(8)
	bucket, err := NewBucket(length)
	if err != nil {
		t.Error("Error creating new token bucket:", err)
	}

	tok := bucket.NewToken(4)
	if len(tok.Code) != int(length) {
		t.Errorf("Wrong token length, expected %d, got %d", length, len(tok.Code))
	}
}
<commit_msg>Removed empty var set<commit_after>/*
 * Human-friendly token generator
 *     Copyright (c) 2017, Christian Muehlhaeuser <muesli@gmail.com>
 *
 *   For license see LICENSE
 */

package toktok

import (
	"testing"
)

func TestCodeGen(t *testing.T) {
	length := uint(8)
	bucket, err := NewBucket(length)
	if err != nil {
		t.Error("Error creating new token bucket:", err)
	}

	tok := bucket.NewToken(4)
	if len(tok.Code) != int(length) {
		t.Errorf("Wrong token length, expected %d, got %d", length, len(tok.Code))
	}
}
<|endoftext|>


<commit_before>package main

import "bytes"
import "fmt"
import "io"
import "testing"

type TestPrinter struct {
	buffer io.Writer
	reset  bool
}

func (t *TestPrinter) Print(line string) (n int, err error) {
	return fmt.Fprint(t.buffer, line)
}

func (t *TestPrinter) Reset() {
	t.reset = true
}

type TestPipe struct {
	*bytes.Buffer
}

func (t *TestPipe) Close() (err error) {
	return
}

var testInput []byte = []byte{'f', 'o', 'o'}

func TestStreamOutput(t *testing.T) {
	pipe := &TestPipe{bytes.NewBufferString("foo\nbar\n")}
	runner := &Runner{}

	output := make([]string, 0)
	ch := runner.streamOutput(pipe)
	for line := range ch {
		output = append(output, line)
	}

	if len(output) != 2 {
		t.Errorf("streamed output length wrong. expected: %d, actual: %d", 2, len(output))
	}

	if output[0] != "foo\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "foo\n", output[0])
	}

	if output[1] != "bar\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "bar\n", output[0])
	}
}

func TestStreamOutputWithoutTrailingNewline(t *testing.T) {
	pipe := &TestPipe{bytes.NewBufferString("foo\nbar")}
	runner := &Runner{}

	output := make([]string, 0)
	ch := runner.streamOutput(pipe)
	for line := range ch {
		output = append(output, line)
	}

	if len(output) != 2 {
		t.Errorf("streamed output length wrong. expected: %d, actual: %d", 2, len(output))
	}

	if output[0] != "foo\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "foo\n", output[0])
	}

	if output[1] != "bar" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "bar", output[0])
	}
}

func TestErrorPrinting(t *testing.T) {
	buf := new(bytes.Buffer)

	runner := &Runner{
		template:    []string{"cat", "{{}}"},
		placeholder: "{{}}",
	}

	runner.runWithInput([]byte{'d', 'o', 'e', 's', 'n', 'o', 't'})
	output := buf.String()
	if output != "cat: doesnot: No such file or directory\n" {
		t.Errorf("unexpected output: %q", output)
	}
}

// func TestOutputBuffering(t *testing.T) {
// 	buf := new(bytes.Buffer)
// 	testPrinter := &TestPrinter{
// 		buffer: buf,
// 		reset:  false,
// 	}
// 	outbuf := new(bytes.Buffer)
//
// 	runner := &Runner{
// 		template:    []string{"echo", "{{}}", "bar"},
// 		placeholder: "{{}}",
// 	}
//
// 	n, err := runner.writeCmdStdout(outbuf)
// 	if n != 0 {
// 		t.Errorf("writeCmdStdout with empty buffer wrote wrong number of bytes: %d", n)
// 	}
// 	if err != nil {
// 		t.Errorf("writeCmdStdout with empty buffer failed. error: %s", err)
// 	}
//
// 	runner.runWithInput(testInput)
//
// 	printedOutput := buf.String()
// 	if printedOutput != "foo bar\n" {
// 		t.Errorf("unexpected printedOutput: %v", printedOutput)
// 	}
//
// 	_, err = runner.writeCmdStdout(outbuf)
// 	if err != nil {
// 		t.Errorf("writeCmdStdout failed. error: %s", err)
// 	}
//
// 	currentOutput := outbuf.String()
// 	if currentOutput != printedOutput {
// 		t.Errorf("unexpected output: %v", currentOutput)
// 	}
// }
//
func TestStdin(t *testing.T) {
	buf := new(bytes.Buffer)

	stdinbuf := new(bytes.Buffer)
	stdinbuf.WriteString("foo\nbar")

	runner := &Runner{
		template:    []string{"grep", "{{}}"},
		placeholder: "{{}}",
		stdinbuf:    *stdinbuf,
	}

	runner.runWithInput(testInput)
	// Run it two times to see that the stdin is the same every time
	runner.runWithInput(testInput)

	printedOutput := buf.String()
	if printedOutput != "foo\nfoo\n" {
		t.Errorf("unexpected printedOutput: %q", printedOutput)
	}
}
<commit_msg>Remove or fix runner tests<commit_after>package main

import "bytes"
import "sync"
import "testing"

type TestPipe struct {
	*bytes.Buffer
}

func (t *TestPipe) Close() (err error) {
	return
}

var testInput []byte = []byte{'f', 'o', 'o'}

func TestStreamOutput(t *testing.T) {
	pipe := &TestPipe{bytes.NewBufferString("foo\nbar\n")}
	wg := &sync.WaitGroup{}
	runner := &Runner{}

	output := make([]string, 0)
	wg.Add(1)
	ch := runner.streamOutput(pipe, wg)
	for line := range ch {
		output = append(output, line)
	}
	wg.Wait()

	if len(output) != 2 {
		t.Errorf("streamed output length wrong. expected: %d, actual: %d", 2, len(output))
	}

	if output[0] != "foo\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "foo\n", output[0])
	}

	if output[1] != "bar\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "bar\n", output[0])
	}
}

func TestStreamOutputWithoutTrailingNewline(t *testing.T) {
	pipe := &TestPipe{bytes.NewBufferString("foo\nbar")}
	wg := &sync.WaitGroup{}
	runner := &Runner{}

	output := make([]string, 0)
	wg.Add(1)
	ch := runner.streamOutput(pipe, wg)

	for line := range ch {
		output = append(output, line)
	}
	wg.Wait()

	if len(output) != 2 {
		t.Errorf("streamed output length wrong. expected: %d, actual: %d", 2, len(output))
	}

	if output[0] != "foo\n" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "foo\n", output[0])
	}

	if output[1] != "bar" {
		t.Errorf("streamed output wrong. expected: %q, actual: %q", "bar", output[0])
	}
}
<|endoftext|>