<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		//return newCharmstore()
		store, err := newCharmstore()
		if err != nil {
			return nil, errors.Trace(err)
		}
		return &charmstore{store}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})
}

func newCharmstore() (charmrepo.Interface, error) {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	store := charmrepo.NewCharmStore(args)
	return store, nil
}

// TODO(ericsnow) Get rid of charmstore one charmrepo.Interface grows the methods.

type charmstore struct {
	charmrepo.Interface
}

func (charmstore) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	// TODO(ericsnow) finish!
	return nil, errors.Errorf("not implemented")
}

func (charmstore) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)

	return client.NewClient(caller, apiCaller), nil
}
<commit_msg>charmstore -> charmstoreClient<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		client := newCharmstoreClient()
		return &charmstoreClient{client}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})
}

func newCharmstoreClient() charmrepo.Interface {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	client := charmrepo.NewCharmStore(args)
	return client
}

// TODO(ericsnow) Get rid of charmstoreClient one charmrepo.Interface grows the methods.

type charmstoreClient struct {
	charmrepo.Interface
}

func (charmstoreClient) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	// TODO(ericsnow) finish!
	return nil, errors.Errorf("not implemented")
}

func (charmstoreClient) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)

	return client.NewClient(caller, apiCaller), nil
}
<|endoftext|>


<commit_before>package composition

import (
	"crypto/tls"
	"errors"
	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

func Test_CompositionHandler_PositiveCase(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def: NewFetchDefinition("/foo"),
				Content: &MemoryContent{
					body: map[string]Fragment{
						"": StringFragment("Hello World\n"),
					},
				},
			},
		}
	}
	ch := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	ch.ServeHTTP(resp, r)

	expected := `<!DOCTYPE html>
<html>
  <head>

  </head>
  <body>
    Hello World

  </body>
</html>
`
	a.Equal(expected, string(resp.Body.Bytes()))
	a.Equal(200, resp.Code)
}

func Test_CompositionHandler_CorrectHeaderAndStatusCodeReturned(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def: NewFetchDefinition("/foo"),
				Content: &MemoryContent{
					body: map[string]Fragment{
						"": StringFragment(""),
					},
					httpHeader: http.Header{
						"Transfer-Encoding": {"gzip"}, // removed
						"Location":          {"/look/somewhere"},
						"Set-Cookie": {
							"cookie-content 1",
							"cookie-content 2",
						},
					},
					httpStatusCode: 302,
				},
			},
			&FetchResult{
				Def:     NewFetchDefinition("..."),
				Content: &MemoryContent{},
			},
		}
	}
	ch := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	ch.ServeHTTP(resp, r)

	a.Equal(302, resp.Code)
	a.Equal(2, len(resp.Header()))
	a.Equal("/look/somewhere", resp.Header().Get("Location"))
	a.Equal("", resp.Header().Get("Transfer-Encoding"))
	a.Contains(resp.Header()["Set-Cookie"], "cookie-content 1")
	a.Contains(resp.Header()["Set-Cookie"], "cookie-content 2")
}

func Test_CompositionHandler_ReturnStream(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentWithFragment := &MemoryContent{
		body: map[string]Fragment{
			"": StringFragment("Hello World\n"),
		},
	}

	contentWithReader := &MemoryContent{
		reader:         ioutil.NopCloser(strings.NewReader("bar")),
		httpHeader:     http.Header{"Content-Type": {"text/plain"}},
		httpStatusCode: 201,
	}

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/fragment"),
				Content: contentWithFragment,
			},
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: contentWithReader,
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("bar", string(resp.Body.Bytes()))
	a.Equal("text/plain", resp.Header().Get("Content-Type"))
	a.Equal(201, resp.Code)
}

func Test_CompositionHandler_ErrorInMerging(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: &MemoryContent{},
				Err:     nil,
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))
	aggregator.contentMergerFactory = func(jsonData map[string]interface{}) ContentMerger {
		merger := NewMockContentMerger(ctrl)
		merger.EXPECT().AddContent(gomock.Any())
		merger.EXPECT().GetHtml().Return(nil, errors.New("an error"))
		return merger
	}

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("Internal Server Error: an error\n", string(resp.Body.Bytes()))
	a.Equal(500, resp.Code)
}

func Test_CompositionHandler_ErrorInFetching(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	errorString := "some error while fetching"
	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: &MemoryContent{httpStatusCode: 502},
				Err:     errors.New(errorString),
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("Error: "+errorString+"\n", string(resp.Body.Bytes()))
	a.Equal(502, resp.Code)
}

func Test_metadataForRequest(t *testing.T) {
	a := assert.New(t)
	r, _ := http.NewRequest("GET", "https://example.com/nothing?foo=bar", nil)

	m := MetadataForRequest(r)
	a.Equal("http://example.com", m["base_url"])
	a.Equal("example.com", m["host"])
	a.Equal("bar", m["params"].(url.Values).Get("foo"))
}

func Test_getBaseUrlFromRequest(t *testing.T) {
	a := assert.New(t)

	tests := []struct {
		rURL         string
		headers      http.Header
		tls          bool
		expectedURL  string
		expectedHost string
	}{
		{
			rURL:         "http://example.com/nothing?foo=bar",
			expectedURL:  "http://example.com",
			expectedHost: "example.com",
		},
		{
			rURL:         "http://example.com:8080/sdcsd",
			expectedURL:  "http://example.com:8080",
			expectedHost: "example.com:8080",
		},
		{
			rURL:         "http://example.com/nothing?foo=bar",
			tls:          true,
			expectedURL:  "https://example.com",
			expectedHost: "example.com",
		},
		{
			rURL: "http://example.com/nothing?foo=bar",
			headers: http.Header{"X-Forwarded-For": {"other.com"},
				"X-Forwarded-Proto": {"https"}},
			expectedURL:  "https://other.com",
			expectedHost: "other.com",
		},
		{
			rURL: "http://example.com/nothing?foo=bar",
			headers: http.Header{"X-Forwarded-For": {"other.com, xyz"},
				"X-Forwarded-Proto": {"https, xyz"}},
			expectedURL:  "https://other.com",
			expectedHost: "other.com",
		},
	}
	for _, test := range tests {
		r, _ := http.NewRequest("GET", test.rURL, nil)
		if test.tls {
			r.TLS = &tls.ConnectionState{}
		}
		if test.headers != nil {
			r.Header = test.headers
		}
		url := getBaseUrlFromRequest(r)
		a.Equal(test.expectedURL, url)
		host := getHostFromRequest(r)
		a.Equal(test.expectedHost, host)
	}
}

type MockFetchResultSupplier []*FetchResult

func (m MockFetchResultSupplier) WaitForResults() []*FetchResult {
	return []*FetchResult(m)
}

func (m MockFetchResultSupplier) MetaJSON() map[string]interface{} {
	return nil
}

func (m MockFetchResultSupplier) Empty() bool {
	return false
}

<commit_msg>TOOM-200: test coverage<commit_after>package composition

import (
	"crypto/tls"
	"errors"
	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

func Test_CompositionHandler_PositiveCase(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def: NewFetchDefinition("/foo"),
				Content: &MemoryContent{
					body: map[string]Fragment{
						"": StringFragment("Hello World\n"),
					},
				},
			},
		}
	}
	ch := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	ch.ServeHTTP(resp, r)

	expected := `<!DOCTYPE html>
<html>
  <head>

  </head>
  <body>
    Hello World

  </body>
</html>
`
	a.Equal(expected, string(resp.Body.Bytes()))
	a.Equal(200, resp.Code)
}

func Test_CompositionHandler_CorrectHeaderAndStatusCodeReturned(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def: NewFetchDefinition("/foo"),
				Content: &MemoryContent{
					body: map[string]Fragment{
						"": StringFragment(""),
					},
					httpHeader: http.Header{
						"Transfer-Encoding": {"gzip"}, // removed
						"Location":          {"/look/somewhere"},
						"Set-Cookie": {
							"cookie-content 1",
							"cookie-content 2",
						},
					},
					httpStatusCode: 302,
				},
			},
			&FetchResult{
				Def:     NewFetchDefinition("..."),
				Content: &MemoryContent{},
			},
		}
	}
	ch := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	ch.ServeHTTP(resp, r)

	a.Equal(302, resp.Code)
	a.Equal(2, len(resp.Header()))
	a.Equal("/look/somewhere", resp.Header().Get("Location"))
	a.Equal("", resp.Header().Get("Transfer-Encoding"))
	a.Contains(resp.Header()["Set-Cookie"], "cookie-content 1")
	a.Contains(resp.Header()["Set-Cookie"], "cookie-content 2")
}

func Test_CompositionHandler_ReturnStream(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentWithFragment := &MemoryContent{
		body: map[string]Fragment{
			"": StringFragment("Hello World\n"),
		},
	}

	contentWithReader := &MemoryContent{
		reader:         ioutil.NopCloser(strings.NewReader("bar")),
		httpHeader:     http.Header{"Content-Type": {"text/plain"}},
		httpStatusCode: 201,
	}

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/fragment"),
				Content: contentWithFragment,
			},
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: contentWithReader,
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("bar", string(resp.Body.Bytes()))
	a.Equal("text/plain", resp.Header().Get("Content-Type"))
	a.Equal(201, resp.Code)
}

func Test_CompositionHandler_ErrorInMerging(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: &MemoryContent{},
				Err:     nil,
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))
	aggregator.contentMergerFactory = func(jsonData map[string]interface{}) ContentMerger {
		merger := NewMockContentMerger(ctrl)
		merger.EXPECT().AddContent(gomock.Any())
		merger.EXPECT().GetHtml().Return(nil, errors.New("an error"))
		return merger
	}

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("Internal Server Error: an error\n", string(resp.Body.Bytes()))
	a.Equal(500, resp.Code)
}

func Test_CompositionHandler_ErrorInFetching(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	errorString := "some error while fetching"
	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{
			&FetchResult{
				Def:     NewFetchDefinition("/foo"),
				Content: &MemoryContent{httpStatusCode: 502},
				Err:     errors.New(errorString),
			},
		}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("Error: "+errorString+"\n", string(resp.Body.Bytes()))
	a.Equal(502, resp.Code)
}

func Test_CompositionHandler_ErrorEmptyFetchersList(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	a := assert.New(t)

	contentFetcherFactory := func(r *http.Request) FetchResultSupplier {
		return MockFetchResultSupplier{}
	}
	aggregator := NewCompositionHandler(ContentFetcherFactory(contentFetcherFactory))

	resp := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "http://example.com", nil)
	aggregator.ServeHTTP(resp, r)

	a.Equal("Internal server error", string(resp.Body.Bytes()))
	a.Equal(500, resp.Code)
}

func Test_metadataForRequest(t *testing.T) {
	a := assert.New(t)
	r, _ := http.NewRequest("GET", "https://example.com/nothing?foo=bar", nil)

	m := MetadataForRequest(r)
	a.Equal("http://example.com", m["base_url"])
	a.Equal("example.com", m["host"])
	a.Equal("bar", m["params"].(url.Values).Get("foo"))
}

func Test_getBaseUrlFromRequest(t *testing.T) {
	a := assert.New(t)

	tests := []struct {
		rURL         string
		headers      http.Header
		tls          bool
		expectedURL  string
		expectedHost string
	}{
		{
			rURL:         "http://example.com/nothing?foo=bar",
			expectedURL:  "http://example.com",
			expectedHost: "example.com",
		},
		{
			rURL:         "http://example.com:8080/sdcsd",
			expectedURL:  "http://example.com:8080",
			expectedHost: "example.com:8080",
		},
		{
			rURL:         "http://example.com/nothing?foo=bar",
			tls:          true,
			expectedURL:  "https://example.com",
			expectedHost: "example.com",
		},
		{
			rURL: "http://example.com/nothing?foo=bar",
			headers: http.Header{"X-Forwarded-For": {"other.com"},
				"X-Forwarded-Proto": {"https"}},
			expectedURL:  "https://other.com",
			expectedHost: "other.com",
		},
		{
			rURL: "http://example.com/nothing?foo=bar",
			headers: http.Header{"X-Forwarded-For": {"other.com, xyz"},
				"X-Forwarded-Proto": {"https, xyz"}},
			expectedURL:  "https://other.com",
			expectedHost: "other.com",
		},
	}
	for _, test := range tests {
		r, _ := http.NewRequest("GET", test.rURL, nil)
		if test.tls {
			r.TLS = &tls.ConnectionState{}
		}
		if test.headers != nil {
			r.Header = test.headers
		}
		url := getBaseUrlFromRequest(r)
		a.Equal(test.expectedURL, url)
		host := getHostFromRequest(r)
		a.Equal(test.expectedHost, host)
	}
}

type MockFetchResultSupplier []*FetchResult

func (m MockFetchResultSupplier) WaitForResults() []*FetchResult {
	return []*FetchResult(m)
}

func (m MockFetchResultSupplier) MetaJSON() map[string]interface{} {
	return nil
}

func (m MockFetchResultSupplier) Empty() bool {
	return len([]*FetchResult(m)) == 0
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"errors"
	"fmt"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/extract"
	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// Join handler for tournament.
func Join(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Join Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	if err := tournament.Join(c, u); err != nil {
		log.Errorf(c, "%s error on Join tournament: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	if updatedUser, err := mdl.UserById(c, u.Id); err != nil {
		log.Errorf(c, "User not found %v", u.Id)
	} else {
		updatedUser.Publish(c, "tournament", "joined tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("You joined tournament %s.", tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// Leave handler for tournament relationships
func Leave(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Leave Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	if err := tournament.Leave(c, u); err != nil {
		log.Errorf(c, "%s error on Leave team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	// return the left tournament
	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	if updatedUser, err := mdl.UserById(c, u.Id); err != nil {
		log.Errorf(c, "User not found %v", u.Id)
	} else {
		updatedUser.Publish(c, "tournament", "left tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("You left tournament %s.", tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}
	return templateshlp.RenderJson(w, c, data)
}

// Join as Team handler for tournament teams realtionship.
func JoinAsTeam(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Join as a Team Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	var teamId int64
	if teamId, err = extract.TeamId(); err != nil {
		return err
	}

	var team *mdl.Team
	if team, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "%s team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}

	if err = tournament.TeamJoin(c, team); err != nil {
		log.Errorf(c, "%s error when trying to join team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	var updatedteam *mdl.Team
	if updatedteam, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "%s team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}
	updatedteam.Publish(c, "tournament", "joined tournament", tournament.Entity(), mdl.ActivityEntity{})

	msg := fmt.Sprintf("Team %s joined tournament %s.", team.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// JSON Leave as Team handler for tournament teams realtionship.
func LeaveAsTeam(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Leave as a Team Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	var teamId int64
	if teamId, err = extract.TeamId(); err != nil {
		return err
	}

	var team *mdl.Team
	if team, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}
	// leave team
	if err = tournament.TeamLeave(c, team); err != nil {
		log.Errorf(c, "%s error when trying to leave team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}
	// return the left tournament

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	if updatedUser, err := mdl.UserById(c, u.Id); err != nil {
		log.Errorf(c, "User not found %v", u.Id)
	} else {
		updatedUser.Publish(c, "tournament", "left tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("Team %s left tournament %s.", team.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}
<commit_msg>set team as actor of the activity<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"errors"
	"fmt"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/extract"
	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// Join handler for tournament.
func Join(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Join Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	if err := tournament.Join(c, u); err != nil {
		log.Errorf(c, "%s error on Join tournament: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	if updatedUser, err := mdl.UserById(c, u.Id); err != nil {
		log.Errorf(c, "User not found %v", u.Id)
	} else {
		updatedUser.Publish(c, "tournament", "joined tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("You joined tournament %s.", tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// Leave handler for tournament relationships
func Leave(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Leave Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	if err := tournament.Leave(c, u); err != nil {
		log.Errorf(c, "%s error on Leave team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	// return the left tournament
	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	if updatedUser, err := mdl.UserById(c, u.Id); err != nil {
		log.Errorf(c, "User not found %v", u.Id)
	} else {
		updatedUser.Publish(c, "tournament", "left tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("You left tournament %s.", tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}
	return templateshlp.RenderJson(w, c, data)
}

// Join as Team handler for tournament teams realtionship.
func JoinAsTeam(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Join as a Team Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	var teamId int64
	if teamId, err = extract.TeamId(); err != nil {
		return err
	}

	var team *mdl.Team
	if team, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "%s team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}

	if err = tournament.TeamJoin(c, team); err != nil {
		log.Errorf(c, "%s error when trying to join team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	var updatedTeam *mdl.Team
	if updatedTeam, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "%s team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}
	updatedTeam.Publish(c, "tournament", "joined tournament", tournament.Entity(), mdl.ActivityEntity{})

	msg := fmt.Sprintf("Team %s joined tournament %s.", team.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}

// JSON Leave as Team handler for tournament teams realtionship.
func LeaveAsTeam(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "POST" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Tournament Leave as a Team Handler:"
	extract := extract.NewContext(c, desc, r)

	var err error
	var tournament *mdl.Tournament

	if tournament, err = extract.Tournament(); err != nil {
		return err
	}

	var teamId int64
	if teamId, err = extract.TeamId(); err != nil {
		return err
	}

	var team *mdl.Team
	if team, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	}
	// leave team
	if err = tournament.TeamLeave(c, team); err != nil {
		log.Errorf(c, "%s error when trying to leave team: %v", desc, err)
		return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeInternal)}
	}
	// return the left tournament

	var tJson mdl.TournamentJson
	fieldsToKeep := []string{"Id", "Name"}
	helpers.InitPointerStructure(tournament, &tJson, fieldsToKeep)

	// publish new activity
	var updatedTeam *mdl.Team
	if updatedTeam, err = mdl.TeamById(c, teamId); err != nil {
		log.Errorf(c, "%s team not found: %v", desc, err)
		return &helpers.NotFound{Err: errors.New(helpers.ErrorCodeTeamNotFound)}
	} else {
		updatedTeam.Publish(c, "tournament", "left tournament", tournament.Entity(), mdl.ActivityEntity{})
	}

	msg := fmt.Sprintf("Team %s left tournament %s.", team.Name, tournament.Name)
	data := struct {
		MessageInfo string `json:",omitempty"`
		Tournament  mdl.TournamentJson
	}{
		msg,
		tJson,
	}

	return templateshlp.RenderJson(w, c, data)
}
<|endoftext|>


<commit_before>package main

import (
// "fmt"
// //"github.com/imosquera/uploadthis"
// "launchpad.net/goamz/aws"
// "launchpad.net/goamz/s3"
)

func main() {
	// ACCESS := "x"
	// SECRET := "y"
	// REGION := aws.USEast
	// BUCKET := "myBucket"
	// FILENAME := "myPath"

	// auth := aws.Auth{ACCESS, SECRET}
	// s3Conn := s3.New(auth, REGION)
	// fmt.Println(s3Conn)
	//fmt.Println(uploadthis.UploadBuffer(s3Conn, BUCKET, FILENAME, []byte{'t', 'e', 's', 't'}))
	//fmt.Println(uploadthis.DownloadBuffer(s3Conn, BUCKET, FILENAME))
}
<commit_msg>removing s3 test file, this should be redone as a script or as specific test<commit_after><|endoftext|>


<commit_before>package scamp

import (
	"errors"
	"net"
	"crypto/tls"
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	// "encoding/json"
	"fmt"
	"bytes"
	"io/ioutil"
	"time"
    "strconv"
	"sync"
	"sync/atomic"
)

// Two minute timeout on clients
var msgTimeout = time.Second * 120

type ServiceActionFunc func(*Message, *Client)
type ServiceAction struct {
	callback ServiceActionFunc
	crudTags string
	version  int
}

type Service struct {
	serviceSpec   string
	sector        string
	name          string
	humanName     string

	listener      net.Listener
	listenerIP    net.IP
	listenerPort  int

	actions       map[string]*ServiceAction
	isRunning     bool

	clientsM      sync.Mutex
	clients       []*Client

	// requests      ClientChan

	cert          tls.Certificate
	pemCert       []byte // just a copy of what was read off disk at tls cert load time

	// stats
	statsCloseChan chan bool
	connectionsAccepted uint64
}

func NewService(sector string, serviceSpec string, humanName string) (serv *Service, err error){
	if len(humanName) > 18 {
		err = fmt.Errorf("name `%s` is too long, must be less than 18 bytes", humanName)
		return
	}

	serv = new(Service)
	serv.sector = sector
	serv.serviceSpec = serviceSpec
	serv.humanName = humanName
	serv.generateRandomName()

	serv.actions = make(map[string]*ServiceAction)

	crtPath := defaultConfig.ServiceCertPath(serv.humanName)
	keyPath := defaultConfig.ServiceKeyPath(serv.humanName)

	if crtPath == nil || keyPath == nil {
		err = fmt.Errorf( "could not find valid crt/key pair for service %s (`%s`,`%s`)", serv.humanName, crtPath, keyPath )
		return
	}

	// Load keypair for tls socket library to use
	serv.cert, err = tls.LoadX509KeyPair( string(crtPath), string(keyPath) )
	if err != nil {
		return
	}

	// Load cert in to memory for announce packet writing
	serv.pemCert, err = ioutil.ReadFile(string(crtPath))
	if err != nil {
		return
	}
	serv.pemCert = bytes.TrimSpace(serv.pemCert)

	// Finally, get ready for incoming requests
	err = serv.listen()
	if err != nil {
		return
	}

	serv.statsCloseChan = make(chan bool)
	// go PrintStatsLoop(serv, time.Duration(15)*time.Second, serv.statsCloseChan)

	Trace.Printf("done initializing service")

	return
}

// TODO: port discovery and interface/IP discovery should happen here
// important to set values so announce packets are correct
func (serv *Service)listen() (err error) {
	config := &tls.Config{
		Certificates: []tls.Certificate{ serv.cert },
	}

	Info.Printf("starting service on %s", serv.serviceSpec)
	serv.listener,err = tls.Listen("tcp", serv.serviceSpec, config)
	if err != nil {
		return err
	}
	addr := serv.listener.Addr()
	Info.Printf("service now listening to %s", addr.String())

  // TODO: get listenerIP to return 127.0.0.1 or something other than '::'/nil
  // serv.listenerIP = serv.listener.Addr().(*net.TCPAddr).IP
  serv.listenerIP, err = IPForAnnouncePacket()
  Trace.Printf("serv.listenerIP: `%s`", serv.listenerIP)

  if err != nil {
  	return
  }

	serv.listenerPort = serv.listener.Addr().(*net.TCPAddr).Port

	return
}

func (serv *Service)Register(name string, callback ServiceActionFunc) (err error) {
	if serv.isRunning {
		err = errors.New("cannot register handlers while server is running")
		return
	}

	serv.actions[name] = &ServiceAction {
		callback: callback,
		version: 1,
	}
	return
}

func (serv *Service)Run() {

	forLoop:
	for {
		netConn,err := serv.listener.Accept()
		if err != nil {
			Info.Printf("exiting service service Run(): `%s`", err)
			break forLoop
		}
		Trace.Printf("accepted new connection...")

		var tlsConn (*tls.Conn) = (netConn).(*tls.Conn)
		if tlsConn == nil {
			Error.Fatalf("could not create tlsConn")
			break forLoop
		}

		conn := NewConnection(tlsConn,"service")
		client := NewClient(conn)

		serv.clientsM.Lock()
		serv.clients = append(serv.clients, client)
		serv.clientsM.Unlock()

		go serv.Handle(client)

		atomic.AddUint64(&serv.connectionsAccepted, 1)
	}

	Info.Printf("closing all registered objects")

	serv.clientsM.Lock()
	defer serv.clientsM.Unlock()
	for _,client := range serv.clients {
		client.Close()
	}

	serv.statsCloseChan <- true
}

func (serv *Service)Handle(client *Client) {
	var action *ServiceAction

	HandlerLoop:
	for {
		select {
		case msg,ok := <-client.Incoming():
			if !ok {
				break HandlerLoop
			}
			action = serv.actions[msg.Action]

			if action != nil{
				// yay
				action.callback(msg, client)
			} else {
				Error.Printf("do not know how to handle action `%s`", msg.Action)

				reply := NewMessage()
		    reply.SetMessageType(MESSAGE_TYPE_REPLY)
		    reply.SetEnvelope(ENVELOPE_JSON)
		    reply.SetRequestId(msg.RequestId)
		    reply.Write([]byte(`{"error": "no such action"}`))
				_,err := client.Send(reply)
				if err != nil {
					client.Close()
					break HandlerLoop
				}

			}
		case <- time.After(msgTimeout):
            // reqIDString := strconv.Itoa(msg.RequestId)
			// Error.Printf("\n%s - %s timeout... dying!", msg.Action, reqIDString) //TODO: include msg ID or # so that we can debug
            Error.Printf("imeout... dying!")
			break HandlerLoop
		}
	}

	client.Close()
	serv.RemoveClient(client)

	Trace.Printf("done handling client")

}

func (serv *Service)RemoveClient(client *Client) (err error){
	serv.clientsM.Lock()
	defer serv.clientsM.Unlock()

	index := -1
	for i,entry := range serv.clients {
		if client == entry {
			index = i
			break
		}
	}

	if index == -1 {
		Error.Printf("tried removing client that wasn't being tracked")
		return fmt.Errorf("unknown client") // TODO can I get the client's IP?
	}

	client.Close()
	serv.clients = append(serv.clients[:index], serv.clients[index+1:]...)

	return nil
}

func (serv *Service)Stop(){
	// Sometimes we Stop() before service after service has been init but before it is started
	// The usual case is a bad config in another plugin
	if serv.listener != nil {
		serv.listener.Close()
	}
}

func (serv *Service)MarshalText() (b []byte, err error){
	var buf bytes.Buffer

	serviceProxy := ServiceAsServiceProxy(serv)

	classRecord,err := serviceProxy.MarshalJSON()//json.Marshal(&serviceProxy) //Marshal is mangling service actions
	if err != nil {
		return
	}
	sig, err := SignSHA256(classRecord, serv.cert.PrivateKey.(*rsa.PrivateKey))
	if err != nil {
		return
	}
	sigParts := stringToRows(sig, 76)

	buf.Write(classRecord)
	buf.WriteString("\n\n")
	buf.Write(serv.pemCert)
	buf.WriteString("\n\n")
	// buf.WriteString(sig)
	// buf.WriteString("\n\n")
	for _,part := range sigParts {
		buf.WriteString(part)
		buf.WriteString("\n")
	}
	buf.WriteString("\n")

	b = buf.Bytes()
	return
}

func stringToRows(input string, rowlen int) (output []string) {
	output = make([]string,0)

	if len(input) <= 76 {
		output = append(output, input)
	} else {
		substr := input[:]
		var row string
		var done bool = false
		for {
			if len(substr) > 76 {
				row = substr[0:76]
				substr = substr[76:]
			} else {
				row = substr[:]
				done = true
			}
			output = append(output,row)
			if done {
				break
			}
		}
	}

	return
}

func (serv *Service)generateRandomName() {
	randBytes := make([]byte, 18, 18)
	read,err := rand.Read(randBytes)
	if err != nil {
		err = fmt.Errorf("could not generate all rand bytes needed. only read %d of 18", read)
		return
	}
	base64RandBytes := base64.StdEncoding.EncodeToString(randBytes)

	var buffer bytes.Buffer
	buffer.WriteString(serv.humanName)
	buffer.WriteString("-")
	buffer.WriteString(base64RandBytes[0:])
	serv.name = string(buffer.Bytes())
}
<commit_msg>removed import<commit_after>package scamp

import (
	"errors"
	"net"
	"crypto/tls"
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	// "encoding/json"
	"fmt"
	"bytes"
	"io/ioutil"
	"time"
    // "strconv"
	"sync"
	"sync/atomic"
)

// Two minute timeout on clients
var msgTimeout = time.Second * 120

type ServiceActionFunc func(*Message, *Client)
type ServiceAction struct {
	callback ServiceActionFunc
	crudTags string
	version  int
}

type Service struct {
	serviceSpec   string
	sector        string
	name          string
	humanName     string

	listener      net.Listener
	listenerIP    net.IP
	listenerPort  int

	actions       map[string]*ServiceAction
	isRunning     bool

	clientsM      sync.Mutex
	clients       []*Client

	// requests      ClientChan

	cert          tls.Certificate
	pemCert       []byte // just a copy of what was read off disk at tls cert load time

	// stats
	statsCloseChan chan bool
	connectionsAccepted uint64
}

func NewService(sector string, serviceSpec string, humanName string) (serv *Service, err error){
	if len(humanName) > 18 {
		err = fmt.Errorf("name `%s` is too long, must be less than 18 bytes", humanName)
		return
	}

	serv = new(Service)
	serv.sector = sector
	serv.serviceSpec = serviceSpec
	serv.humanName = humanName
	serv.generateRandomName()

	serv.actions = make(map[string]*ServiceAction)

	crtPath := defaultConfig.ServiceCertPath(serv.humanName)
	keyPath := defaultConfig.ServiceKeyPath(serv.humanName)

	if crtPath == nil || keyPath == nil {
		err = fmt.Errorf( "could not find valid crt/key pair for service %s (`%s`,`%s`)", serv.humanName, crtPath, keyPath )
		return
	}

	// Load keypair for tls socket library to use
	serv.cert, err = tls.LoadX509KeyPair( string(crtPath), string(keyPath) )
	if err != nil {
		return
	}

	// Load cert in to memory for announce packet writing
	serv.pemCert, err = ioutil.ReadFile(string(crtPath))
	if err != nil {
		return
	}
	serv.pemCert = bytes.TrimSpace(serv.pemCert)

	// Finally, get ready for incoming requests
	err = serv.listen()
	if err != nil {
		return
	}

	serv.statsCloseChan = make(chan bool)
	// go PrintStatsLoop(serv, time.Duration(15)*time.Second, serv.statsCloseChan)

	Trace.Printf("done initializing service")

	return
}

// TODO: port discovery and interface/IP discovery should happen here
// important to set values so announce packets are correct
func (serv *Service)listen() (err error) {
	config := &tls.Config{
		Certificates: []tls.Certificate{ serv.cert },
	}

	Info.Printf("starting service on %s", serv.serviceSpec)
	serv.listener,err = tls.Listen("tcp", serv.serviceSpec, config)
	if err != nil {
		return err
	}
	addr := serv.listener.Addr()
	Info.Printf("service now listening to %s", addr.String())

  // TODO: get listenerIP to return 127.0.0.1 or something other than '::'/nil
  // serv.listenerIP = serv.listener.Addr().(*net.TCPAddr).IP
  serv.listenerIP, err = IPForAnnouncePacket()
  Trace.Printf("serv.listenerIP: `%s`", serv.listenerIP)

  if err != nil {
  	return
  }

	serv.listenerPort = serv.listener.Addr().(*net.TCPAddr).Port

	return
}

func (serv *Service)Register(name string, callback ServiceActionFunc) (err error) {
	if serv.isRunning {
		err = errors.New("cannot register handlers while server is running")
		return
	}

	serv.actions[name] = &ServiceAction {
		callback: callback,
		version: 1,
	}
	return
}

func (serv *Service)Run() {

	forLoop:
	for {
		netConn,err := serv.listener.Accept()
		if err != nil {
			Info.Printf("exiting service service Run(): `%s`", err)
			break forLoop
		}
		Trace.Printf("accepted new connection...")

		var tlsConn (*tls.Conn) = (netConn).(*tls.Conn)
		if tlsConn == nil {
			Error.Fatalf("could not create tlsConn")
			break forLoop
		}

		conn := NewConnection(tlsConn,"service")
		client := NewClient(conn)

		serv.clientsM.Lock()
		serv.clients = append(serv.clients, client)
		serv.clientsM.Unlock()

		go serv.Handle(client)

		atomic.AddUint64(&serv.connectionsAccepted, 1)
	}

	Info.Printf("closing all registered objects")

	serv.clientsM.Lock()
	defer serv.clientsM.Unlock()
	for _,client := range serv.clients {
		client.Close()
	}

	serv.statsCloseChan <- true
}

func (serv *Service)Handle(client *Client) {
	var action *ServiceAction

	HandlerLoop:
	for {
		select {
		case msg,ok := <-client.Incoming():
			if !ok {
				break HandlerLoop
			}
			action = serv.actions[msg.Action]

			if action != nil{
				// yay
				action.callback(msg, client)
			} else {
				Error.Printf("do not know how to handle action `%s`", msg.Action)

				reply := NewMessage()
		    reply.SetMessageType(MESSAGE_TYPE_REPLY)
		    reply.SetEnvelope(ENVELOPE_JSON)
		    reply.SetRequestId(msg.RequestId)
		    reply.Write([]byte(`{"error": "no such action"}`))
				_,err := client.Send(reply)
				if err != nil {
					client.Close()
					break HandlerLoop
				}

			}
		case <- time.After(msgTimeout):
            // reqIDString := strconv.Itoa(msg.RequestId)
			// Error.Printf("\n%s - %s timeout... dying!", msg.Action, reqIDString) //TODO: include msg ID or # so that we can debug
            Error.Printf("imeout... dying!")
			break HandlerLoop
		}
	}

	client.Close()
	serv.RemoveClient(client)

	Trace.Printf("done handling client")

}

func (serv *Service)RemoveClient(client *Client) (err error){
	serv.clientsM.Lock()
	defer serv.clientsM.Unlock()

	index := -1
	for i,entry := range serv.clients {
		if client == entry {
			index = i
			break
		}
	}

	if index == -1 {
		Error.Printf("tried removing client that wasn't being tracked")
		return fmt.Errorf("unknown client") // TODO can I get the client's IP?
	}

	client.Close()
	serv.clients = append(serv.clients[:index], serv.clients[index+1:]...)

	return nil
}

func (serv *Service)Stop(){
	// Sometimes we Stop() before service after service has been init but before it is started
	// The usual case is a bad config in another plugin
	if serv.listener != nil {
		serv.listener.Close()
	}
}

func (serv *Service)MarshalText() (b []byte, err error){
	var buf bytes.Buffer

	serviceProxy := ServiceAsServiceProxy(serv)

	classRecord,err := serviceProxy.MarshalJSON()//json.Marshal(&serviceProxy) //Marshal is mangling service actions
	if err != nil {
		return
	}
	sig, err := SignSHA256(classRecord, serv.cert.PrivateKey.(*rsa.PrivateKey))
	if err != nil {
		return
	}
	sigParts := stringToRows(sig, 76)

	buf.Write(classRecord)
	buf.WriteString("\n\n")
	buf.Write(serv.pemCert)
	buf.WriteString("\n\n")
	// buf.WriteString(sig)
	// buf.WriteString("\n\n")
	for _,part := range sigParts {
		buf.WriteString(part)
		buf.WriteString("\n")
	}
	buf.WriteString("\n")

	b = buf.Bytes()
	return
}

func stringToRows(input string, rowlen int) (output []string) {
	output = make([]string,0)

	if len(input) <= 76 {
		output = append(output, input)
	} else {
		substr := input[:]
		var row string
		var done bool = false
		for {
			if len(substr) > 76 {
				row = substr[0:76]
				substr = substr[76:]
			} else {
				row = substr[:]
				done = true
			}
			output = append(output,row)
			if done {
				break
			}
		}
	}

	return
}

func (serv *Service)generateRandomName() {
	randBytes := make([]byte, 18, 18)
	read,err := rand.Read(randBytes)
	if err != nil {
		err = fmt.Errorf("could not generate all rand bytes needed. only read %d of 18", read)
		return
	}
	base64RandBytes := base64.StdEncoding.EncodeToString(randBytes)

	var buffer bytes.Buffer
	buffer.WriteString(serv.humanName)
	buffer.WriteString("-")
	buffer.WriteString(base64RandBytes[0:])
	serv.name = string(buffer.Bytes())
}
<|endoftext|>


<commit_before>package schema

import (
	"encoding/json"
	//	"fmt"
)

// DefaultSchema returns an empty schema ready to be populated
func DefaultSchema() *Schema {
	tables := make(map[string]*Table)
	sch := &Schema{Tables: tables, TableAliases: nil}

	return sch
}

// ToJSON converts a schema into a JSON string.
func (s *Schema) ToJSON() (string, error) {
	buf, err := s.ToJSONBytes()
	if err != nil {
		return "", err
	}
	return string(buf), err
}

// ToJSONBytes converts a schema into a JSON byte array.
func (s *Schema) ToJSONBytes() ([]byte, error) {
	buf, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

// FromJSON unmarshals a JSON string into a Schema object.
func FromJSON(jsonStr string) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal([]byte(jsonStr), &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// FromJSONBytes unmarshals a JSON byte array into a Schema object.
func FromJSONBytes(jsonBytes []byte) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal(jsonBytes, &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// GetTable returns the correct table in a potentially aliased environment.
func (s *Schema) GetTable(n string) *Table {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			//fmt.Println("Returning ", n)
			return s.Tables[n]
		}
		//fmt.Println("Returning ", realName)
		return s.Tables[realName]
	}
	//fmt.Println("Returning ", n)
	return s.Tables[n]
}

// GetField returns the correct field in a potentially aliased environment.
func (t *Table) GetField(n string) *Field {
	if t.FieldAliases != nil {
		realName, ok := t.FieldAliases[n]
		if !ok {
			// Perhaps it is not an alias
			//fmt.Println("Returning ", n)
			return t.Fields[n]
		}
		//fmt.Println("Returning ", realName)
		return t.Fields[realName]
	}
	//fmt.Println("Returning ", n)
	return t.Fields[n]
}

// DefaultTable returns an empty table ready to be populated
func DefaultTable() *Table {
	fieldsMap := make(map[string]*Field)
	childrenMap := make(map[string]*ChildTable)

	tbl := &Table{
		MultiKey:        false,
		Primary:         "",
		Fields:          fieldsMap,
		EssentialFields: nil,
		Children:        childrenMap,
	}
	return tbl
}

// DefaultField returns an empty field struct ready to be populated
func DefaultField() *Field {
	fld := &Field{
		Name:         "",
		AllowNull:    false,
		DefaultValue: "",
		IsNumber:     false,
		DBType:       "",
		IsIdentity:   false,
		Source:       "",
	}
	return fld
}

// DefaultChildTable returns an empty child table ready to be populated
func DefaultChildTable() *ChildTable {
	chld := &ChildTable{
		ParentTable:  "",
		MultiKey:     false,
		LocalField:   "",
		ForeignField: "",

		LocalFields:   nil,
		ForeignFields: nil,
	}
	return chld
}
<commit_msg>add GetFieldName<commit_after>package schema

import (
	"encoding/json"
	//	"fmt"
)

// DefaultSchema returns an empty schema ready to be populated
func DefaultSchema() *Schema {
	tables := make(map[string]*Table)
	sch := &Schema{Tables: tables, TableAliases: nil}

	return sch
}

// ToJSON converts a schema into a JSON string.
func (s *Schema) ToJSON() (string, error) {
	buf, err := s.ToJSONBytes()
	if err != nil {
		return "", err
	}
	return string(buf), err
}

// ToJSONBytes converts a schema into a JSON byte array.
func (s *Schema) ToJSONBytes() ([]byte, error) {
	buf, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

// FromJSON unmarshals a JSON string into a Schema object.
func FromJSON(jsonStr string) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal([]byte(jsonStr), &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// FromJSONBytes unmarshals a JSON byte array into a Schema object.
func FromJSONBytes(jsonBytes []byte) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal(jsonBytes, &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// GetTable returns the correct table in a potentially aliased environment.
func (s *Schema) GetTable(n string) *Table {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			//fmt.Println("Returning ", n)
			return s.Tables[n]
		}
		//fmt.Println("Returning ", realName)
		return s.Tables[realName]
	}
	//fmt.Println("Returning ", n)
	return s.Tables[n]
}

// GetFieldName returns the correct field name in a potentially aliased environment.
// This is useful in situations where you aren't sure what the 'real' key name
// may potentially be.
func (t * Table) GetFieldName(n string) string {
	if t.FieldAliases != nil {
		realName, ok := t.FieldAliases[n]
		if !ok {
			// Perhaps it is not an alias
			//fmt.Println("Returning ", n)
			return n
		}
		//fmt.Println("Returning ", realName)
		return realName
	}
	//fmt.Println("Returning ", n)
	return n
}

// GetField returns the correct field in a potentially aliased environment.
func (t *Table) GetField(n string) *Field {
	if t.FieldAliases != nil {
		realName, ok := t.FieldAliases[n]
		if !ok {
			// Perhaps it is not an alias
			//fmt.Println("Returning ", n)
			return t.Fields[n]
		}
		//fmt.Println("Returning ", realName)
		return t.Fields[realName]
	}
	//fmt.Println("Returning ", n)
	return t.Fields[n]
}

// DefaultTable returns an empty table ready to be populated
func DefaultTable() *Table {
	fieldsMap := make(map[string]*Field)
	childrenMap := make(map[string]*ChildTable)

	tbl := &Table{
		MultiKey:        false,
		Primary:         "",
		Fields:          fieldsMap,
		EssentialFields: nil,
		Children:        childrenMap,
	}
	return tbl
}

// DefaultField returns an empty field struct ready to be populated
func DefaultField() *Field {
	fld := &Field{
		Name:         "",
		AllowNull:    false,
		DefaultValue: "",
		IsNumber:     false,
		DBType:       "",
		IsIdentity:   false,
		Source:       "",
	}
	return fld
}

// DefaultChildTable returns an empty child table ready to be populated
func DefaultChildTable() *ChildTable {
	chld := &ChildTable{
		ParentTable:  "",
		MultiKey:     false,
		LocalField:   "",
		ForeignField: "",

		LocalFields:   nil,
		ForeignFields: nil,
	}
	return chld
}
<|endoftext|>


<commit_before>package composition

//go:generate go get github.com/golang/mock/mockgen
//go:generate mockgen -self_package composition -package composition -destination interface_mocks_test.go lib-ui-service/composition Fragment,ContentLoader,Content,ContentMerger,ContentParser,ResponseProcessor
//go:generate sed -ie "s/composition .lib-ui-service\\/composition.//g;s/composition\\.//g" interface_mocks_test.go
import (
	"io"
	"net/http"
)

type Fragment interface {
	Execute(w io.Writer, data map[string]interface{}, executeNestedFragment func(nestedFragmentName string) error) error
}

type ContentLoader interface {
	// Load synchronously loads a content.
	// The loader has to ensure to return the call withing the supplied timeout.
	Load(fd *FetchDefinition) (Content, error)
}

type ContentParser interface {
	// Parse parses the input stream into a Content Object
	Parse(*MemoryContent, io.Reader) error
}

type FetchResultSupplier interface {
	// WaitForResults returns all results of a fetch job in a blocking manger.
	WaitForResults() []*FetchResult

	// MetaJSON returns the composed meta JSON object
	MetaJSON() map[string]interface{}
}

// Vontent is the abstration over includable data.
// Content may be parsed of it may contain a stream represented by a non nil Reader(), not both.
type Content interface {

	// The URL, from where the content was loaded
	URL() string

	// RequiredContent returns a list of Content Elements to load
	RequiredContent() []*FetchDefinition

	// Meta returns a data structure to add to the global
	// data context.
	Meta() map[string]interface{}

	// Head returns a partial which should be
	// inserted to the html head
	Head() Fragment

	// Body returns a map of partials,
	// the named body partials, where the keys are partial names.
	Body() map[string]Fragment

	// Tail returns a partial which should be inserted at the end of the page.
	// e.g. a script to load after rendering.
	Tail() Fragment

	// The attributes for the body element
	BodyAttributes() Fragment

	// Reader returns the stream with the content, of any.
	// If Reader() == nil, no stream is available an it contains parsed data, only.
	Reader() io.ReadCloser

	// HttpHeader() returns the http headers of the fetch job
	HttpHeader() http.Header

	// HttpStatusCode() returns the http statuc code of the fetch job
	HttpStatusCode() int
}

type ContentMerger interface {
	// Add content to the meger
	AddContent(fetchResult *FetchResult)

	// Merge and write all content supplied writer
	WriteHtml(w io.Writer) error
}

type ResponseProcessor interface {
	// Process html from responsebody before composition is triggered
	Process(*http.Response, string) error
}<commit_msg>Added comment for ResponseReader-Interface<commit_after>package composition

//go:generate go get github.com/golang/mock/mockgen
//go:generate mockgen -self_package composition -package composition -destination interface_mocks_test.go lib-ui-service/composition Fragment,ContentLoader,Content,ContentMerger,ContentParser,ResponseProcessor
//go:generate sed -ie "s/composition .lib-ui-service\\/composition.//g;s/composition\\.//g" interface_mocks_test.go
import (
	"io"
	"net/http"
)

type Fragment interface {
	Execute(w io.Writer, data map[string]interface{}, executeNestedFragment func(nestedFragmentName string) error) error
}

type ContentLoader interface {
	// Load synchronously loads a content.
	// The loader has to ensure to return the call withing the supplied timeout.
	Load(fd *FetchDefinition) (Content, error)
}

type ContentParser interface {
	// Parse parses the input stream into a Content Object
	Parse(*MemoryContent, io.Reader) error
}

type FetchResultSupplier interface {
	// WaitForResults returns all results of a fetch job in a blocking manger.
	WaitForResults() []*FetchResult

	// MetaJSON returns the composed meta JSON object
	MetaJSON() map[string]interface{}
}

// Vontent is the abstration over includable data.
// Content may be parsed of it may contain a stream represented by a non nil Reader(), not both.
type Content interface {

	// The URL, from where the content was loaded
	URL() string

	// RequiredContent returns a list of Content Elements to load
	RequiredContent() []*FetchDefinition

	// Meta returns a data structure to add to the global
	// data context.
	Meta() map[string]interface{}

	// Head returns a partial which should be
	// inserted to the html head
	Head() Fragment

	// Body returns a map of partials,
	// the named body partials, where the keys are partial names.
	Body() map[string]Fragment

	// Tail returns a partial which should be inserted at the end of the page.
	// e.g. a script to load after rendering.
	Tail() Fragment

	// The attributes for the body element
	BodyAttributes() Fragment

	// Reader returns the stream with the content, of any.
	// If Reader() == nil, no stream is available an it contains parsed data, only.
	Reader() io.ReadCloser

	// HttpHeader() returns the http headers of the fetch job
	HttpHeader() http.Header

	// HttpStatusCode() returns the http statuc code of the fetch job
	HttpStatusCode() int
}

type ContentMerger interface {
	// Add content to the meger
	AddContent(fetchResult *FetchResult)

	// Merge and write all content supplied writer
	WriteHtml(w io.Writer) error
}

type ResponseProcessor interface {
	// Process html from responsebody before composition is triggered
	// May create a new Reader inside the ResponseBody
	Process(*http.Response, string) error
}<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"sync"
)

func main() {
	log.SetFlags(log.Lshortfile)
	files := make(chan string, 1000)

	// spawn four worker goroutines
	var wg sync.WaitGroup
	defer wg.Wait()

	defer close(files)
	for i := 0; i < 50; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for name := range files {
				file, err := os.Open(name)
				if err != nil {
					log.Print(err)
				}
				defer file.Close()

				resp, err := http.Post("http://"+os.Args[2]+"/file/"+name, "application/text", file)
				if err != nil {
					log.Print(err)
				}
				resp.Body.Close()
			}
		}()
	}

	dir, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer dir.Close()

	counter := 0
	var names []string
	for names, err = dir.Readdirnames(1000); err == nil; names, err = dir.Readdirnames(1000) {
		for _, name := range names {
			files <- path.Join(os.Args[1], name)
		}
		counter += len(names)
		log.Printf("Sent %d so far.", counter)
	}
	if err != io.EOF {
		log.Fatal(err)
	}

}
<commit_msg>A few improvements to cp.<commit_after>package main

import (
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"sync"
)

func main() {
	log.SetFlags(log.Lshortfile)
	files := make(chan string)

	// spawn four worker goroutines
	var wg sync.WaitGroup
	defer wg.Wait()

	defer close(files)
	for i := 0; i < 75; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for name := range files {
				file, err := os.Open(name)
				if err != nil {
					log.Print(err)
				}
				defer file.Close()

				resp, err := http.Post("http://"+os.Args[2]+"/file/"+name, "application/text", file)
				if err != nil {
					log.Print(err)
				}
				resp.Body.Close()
			}
		}()
	}

	dir, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer dir.Close()

	counter := 0
	var names []string
	for names, err = dir.Readdirnames(1000); err == nil; names, err = dir.Readdirnames(1000) {
		for _, name := range names {
			files <- path.Join(os.Args[1], name)
		}
		counter += len(names)
		log.Printf("Sent %d so far.", counter)
	}
	if err != io.EOF {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// +build x11 OR linux

package sdl

/*
#include <X11/Xlib.h>
*/
import "C"
import "unsafe"

// X11Msg contains X Window System window information.
type X11Msg struct {
	Event C.XEvent
}

// X11() returns X Window System message.
func (msg *SysWMmsg) X11() *X11Msg {
	return (*X11Msg)(unsafe.Pointer(&msg.data[0]))
}
<commit_msg>Build syswm_x11.go only if actually using X11 (#415)<commit_after>// +build x11

package sdl

/*
#include <X11/Xlib.h>
*/
import "C"
import "unsafe"

// X11Msg contains X Window System window information.
type X11Msg struct {
	Event C.XEvent
}

// X11() returns X Window System message.
func (msg *SysWMmsg) X11() *X11Msg {
	return (*X11Msg)(unsafe.Pointer(&msg.data[0]))
}
<|endoftext|>


<commit_before>package semver

import (
	"fmt"
	"strconv"
	"strings"
)

const maxInt = int(^uint(0) >> 1)

var typeMap map[string]int = map[string]int{
	"a":  1,
	"b":  2,
	"rc": 3,
	"":   4,
}

type SemanticVersion struct {
	Major, Minor, Patch, PreRelease, DevCount int
	PreReleaseType                            string
}

func (s SemanticVersion) Keys() [7]int {
	k := [7]int{}
	k[0], k[1], k[2] = s.Major, s.Minor, s.Patch
	if s.DevCount != 0 && s.PreReleaseType == "" {
		k[3] = 0
	} else {
		k[3] = 1
	}
	k[4] = typeMap[s.PreReleaseType]
	k[5] = s.PreRelease
	if s.DevCount != 0 {
		k[6] = s.DevCount
	} else {
		k[6] = maxInt
	}
	return k
}

func New(v string) (*SemanticVersion, error) {
	s := new(SemanticVersion)
	parsed := strings.Split(strings.ToLower(strings.TrimSpace(v)), ".")
	if len(parsed) < 3 {
		return nil, fmt.Errorf("Invalid semantic version: %v\n", v)
	}

	part, parsed := pop(parsed)
	if major, err := strconv.Atoi(part); err == nil {
		s.Major = major
	} else {
		return nil, fmt.Errorf("Invalid major version: %v\n", v)
	}

	part, parsed = pop(parsed)
	if minor, err := strconv.Atoi(part); err == nil {
		s.Minor = minor
	} else {
		return nil, fmt.Errorf("Invalid minor version: %v\n", v)
	}

	part, parsed = pop(parsed)
	if patch, err := strconv.Atoi(part); err == nil {
		s.Patch = patch
	} else {
		return nil, fmt.Errorf("Invalid patch version: %v\n", v)
	}

	if len(parsed) > 0 {
		if parsed[0][0] == 'a' || parsed[0][0] == 'b' || parsed[0][0] == 'r' {
			// pre-release
			part, parsed = pop(parsed)
			if preReleaseType, preRelease, err := parsePreRelease(part); err == nil {
				s.PreReleaseType, s.PreRelease = preReleaseType, preRelease
			} else {
				return nil, fmt.Errorf("Invalid pre-release version: %v\n", v)
			}
		}
		if part, parsed = pop(parsed); part != "" {
			// dev part
			if len(part) < 4 || part[:3] != "dev" {
				return nil, fmt.Errorf("Invalid dev version: %v\n", v)
			}
			if devCount, err := strconv.Atoi(part[3:]); err == nil {
				s.DevCount = devCount
			} else {
				return nil, fmt.Errorf("Invalid dev version: %v\n", v)
			}
		}
	}
	return s, nil
}

func Vercmp(a, b *SemanticVersion) int {
	b_keys := b.Keys()
	for idx, a_key := range a.Keys() {
		b_key := b_keys[idx]
		if a_key != b_key {
			return a_key - b_key
		}
	}
	return 0
}

func parseBuffer(b string) interface{} {
	if r, err := strconv.Atoi(b); err == nil {
		return r
	} else {
		return b
	}
}

func parsePreRelease(s string) (string, int, error) {
	var preReleaseType string

	if s[0] == 'r' {
		preReleaseType, s = s[:2], s[2:]
	} else {
		preReleaseType, s = string(s[0]), s[1:]
	}
	if preRelease, err := strconv.Atoi(s); err == nil {
		return preReleaseType, preRelease, err
	} else {
		return "", 0, err
	}
}

func pop(s []string) (string, []string) {
	n := len(s)
	if n > 1 {
		return s[0], s[1:]
	} else if n == 1 {
		return s[0], []string{}
	} else {
		return "", s
	}
}
<commit_msg>Add Stirng method to semantic versions<commit_after>package semver

import (
	"fmt"
	"strconv"
	"strings"
)

const maxInt = int(^uint(0) >> 1)

var typeMap map[string]int = map[string]int{
	"a":  1,
	"b":  2,
	"rc": 3,
	"":   4,
}

type SemanticVersion struct {
	Major, Minor, Patch, PreRelease, DevCount int
	PreReleaseType                            string
}

func (s SemanticVersion) Keys() [7]int {
	k := [7]int{}
	k[0], k[1], k[2] = s.Major, s.Minor, s.Patch
	if s.DevCount != 0 && s.PreReleaseType == "" {
		k[3] = 0
	} else {
		k[3] = 1
	}
	k[4] = typeMap[s.PreReleaseType]
	k[5] = s.PreRelease
	if s.DevCount != 0 {
		k[6] = s.DevCount
	} else {
		k[6] = maxInt
	}
	return k
}

func (s SemanticVersion) String() string {
	str := fmt.Sprintf("%d.%d.%d", s.Major, s.Minor, s.Patch)
	if s.PreReleaseType != "" {
		str = str + fmt.Sprintf(".%s%d", s.PreReleaseType, s.PreRelease)
	}
	if s.DevCount != 0 {
		str = str + fmt.Sprintf(".dev%d", s.DevCount)
	}
	return str
}

func New(v string) (*SemanticVersion, error) {
	s := new(SemanticVersion)
	parsed := strings.Split(strings.ToLower(strings.TrimSpace(v)), ".")
	if len(parsed) < 3 {
		return nil, fmt.Errorf("Invalid semantic version: %v\n", v)
	}

	part, parsed := pop(parsed)
	if major, err := strconv.Atoi(part); err == nil {
		s.Major = major
	} else {
		return nil, fmt.Errorf("Invalid major version: %v\n", v)
	}

	part, parsed = pop(parsed)
	if minor, err := strconv.Atoi(part); err == nil {
		s.Minor = minor
	} else {
		return nil, fmt.Errorf("Invalid minor version: %v\n", v)
	}

	part, parsed = pop(parsed)
	if patch, err := strconv.Atoi(part); err == nil {
		s.Patch = patch
	} else {
		return nil, fmt.Errorf("Invalid patch version: %v\n", v)
	}

	if len(parsed) > 0 {
		if parsed[0][0] == 'a' || parsed[0][0] == 'b' || parsed[0][0] == 'r' {
			// pre-release
			part, parsed = pop(parsed)
			if preReleaseType, preRelease, err := parsePreRelease(part); err == nil {
				s.PreReleaseType, s.PreRelease = preReleaseType, preRelease
			} else {
				return nil, fmt.Errorf("Invalid pre-release version: %v\n", v)
			}
		}
		if part, parsed = pop(parsed); part != "" {
			// dev part
			if len(part) < 4 || part[:3] != "dev" {
				return nil, fmt.Errorf("Invalid dev version: %v\n", v)
			}
			if devCount, err := strconv.Atoi(part[3:]); err == nil {
				s.DevCount = devCount
			} else {
				return nil, fmt.Errorf("Invalid dev version: %v\n", v)
			}
		}
	}
	return s, nil
}

func Vercmp(a, b *SemanticVersion) int {
	b_keys := b.Keys()
	for idx, a_key := range a.Keys() {
		b_key := b_keys[idx]
		if a_key != b_key {
			return a_key - b_key
		}
	}
	return 0
}

func parseBuffer(b string) interface{} {
	if r, err := strconv.Atoi(b); err == nil {
		return r
	} else {
		return b
	}
}

func parsePreRelease(s string) (string, int, error) {
	var preReleaseType string

	if s[0] == 'r' {
		preReleaseType, s = s[:2], s[2:]
	} else {
		preReleaseType, s = string(s[0]), s[1:]
	}
	if preRelease, err := strconv.Atoi(s); err == nil {
		return preReleaseType, preRelease, err
	} else {
		return "", 0, err
	}
}

func pop(s []string) (string, []string) {
	n := len(s)
	if n > 1 {
		return s[0], s[1:]
	} else if n == 1 {
		return s[0], []string{}
	} else {
		return "", s
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"reflect"
	"sync"
	"time"

	"buildblast/lib/coords"
	"buildblast/lib/game"
	"buildblast/lib/mapgen"
)

type Client struct {
	*ClientConn

	name string

	// Send the client the right chunks.
	cm             *ChunkManager
	blockSendQueue chan *MsgBlock
	chunksOnce     sync.Once

	player *game.Player
}

func NewClient(name string) *Client {
	c := new(Client)
	c.ClientConn = NewClientConn(name)

	c.name = name

	c.cm = NewChunkManager()
	c.blockSendQueue = make(chan *MsgBlock, 10)

	return c
}

func (c *Client) Tick(g *Game, w *game.World) {
	for {
		select {
		case m := <-c.recvQueue:
			c.handleMessage(g, w, m)
		default:
			return
		}
	}
}

func (c *Client) handleMessage(g *Game, w *game.World, m Message) {
	switch m.(type) {
	case *MsgBlock:
		m := m.(*MsgBlock)
		c.handleBlock(g, w, m)

	case *MsgControlsState:
		m := m.(*MsgControlsState)
		m.Controls.Timestamp = m.Timestamp
		c.handleControlState(g, w, m)

	case *MsgChat:
		g.Chat(c.name, m.(*MsgChat).Message)

	case *MsgInventoryState:
		m := m.(*MsgInventoryState)
		c.player.Inventory().SetActiveItems(m.ItemLeft, m.ItemRight)

	case *MsgInventoryMove:
		m := m.(*MsgInventoryMove)
		c.player.Inventory().MoveItems(m.From, m.To)

		c.Send(&MsgInventoryState{
			Items: c.player.Inventory().ItemsToString(),
		})

	default:
		c.Errors <- fmt.Errorf("unknown message recieved from client: %s", reflect.TypeOf(m))
	}
}

func (c *Client) handleBlock(g *Game, w *game.World, m *MsgBlock) {
	// Eventually we should simulate block placement/removal entirely
	// on the server side, but for now, this works fairly well.
	inv := c.player.Inventory()
	curBlock := w.Block(m.Pos)

	if curBlock == mapgen.BLOCK_AIR {
		// Placing a block
		item := game.ItemFromBlock(m.Type)
		if inv.RemoveItem(item) {
			w.ChangeBlock(m.Pos, m.Type)
		} else {
			c.sendBlockChanged(m.Pos, curBlock)
		}
	} else {
		// Removing a block
		item := game.ItemFromBlock(curBlock)
		inv.AddItem(item)
		w.ChangeBlock(m.Pos, m.Type)
	}

	c.Send(&MsgInventoryState{
		Items: c.player.Inventory().ItemsToString(),
	})
}

func (c *Client) handleControlState(g *Game, w *game.World, m *MsgControlsState) {
	pos, vy, hp, hitPos := c.player.ClientTick(m.Controls)

	c.cm.QueueChunksNearby(w, pos)

	c.Send(&MsgPlayerState{
		Pos:       pos,
		VelocityY: vy,
		Timestamp: m.Timestamp,
		Hp:        hp,
	})

	if hitPos != nil {
		g.Broadcast(&MsgDebugRay{
			Pos: *hitPos,
		})
	}
}

func (c *Client) Connected(g *Game, w *game.World) {
	p := game.NewPlayer(w, c.name)

	for _, id := range w.GetEntityIDs() {
		c.Send(&MsgEntityCreate{
			ID: id,
		})
	}

	w.AddEntity(p)
	w.AddBlockListener(c)
	w.AddEntityListener(c)

	c.player = p
	c.Send(&MsgInventoryState{
		Items: c.player.Inventory().ItemsToString(),
	})
}

func (c *Client) Disconnected(g *Game, w *game.World) {
	w.RemoveEntity(c.player)
	w.RemoveBlockListener(c)
	w.RemoveEntityListener(c)
}

func (c *Client) BlockChanged(bc coords.Block, old mapgen.Block, new mapgen.Block) {
	c.sendBlockChanged(bc, new)
}

func (c *Client) EntityCreated(id string) {
	c.Send(&MsgEntityCreate{
		ID: id,
	})
}

func (c *Client) EntityUpdate(id string, pos coords.World, health int) {
	if id == c.name {
		return
	}
	c.SendLossy(&MsgEntityPosition{
		ID:  id,
		Pos: pos,
		Health: health,
	})
}

func (c *Client) EntityDied(id string, killer string) {}

func (c *Client) EntityRemoved(id string) {
	if id == c.name {
		return
	}
	c.Send(&MsgEntityRemove{
		ID: id,
	})
}

func (c *Client) sendBlockChanged(bc coords.Block, b mapgen.Block) {
	m := &MsgBlock{
		Pos:  bc,
		Type: b,
	}
	select {
	case c.blockSendQueue <- m:
	default:
		c.Errors <- fmt.Errorf("unable to send block update to player %s (server overloaded?)", c.name)
	}
}

// WARNING: This runs on a seperate thread from everything
// else in client!
func (c *Client) RunChunks(conn *Conn) {
	// This prevents multiple clients from attempting to connect to
	// the same client's RunChunks, which could cause strange
	// race conditions and other problems.
	action := func() {
		c.internalRunChunks(conn)
	}
	c.chunksOnce.Do(action)
}

func (c *Client) internalRunChunks(conn *Conn) {
	for {
		select {
		case m := <-c.blockSendQueue:
			if !c.cm.ApplyBlockChange(m.Pos, m.Type) {
				conn.Send(m)
			}
		default:
			cc, chunk := c.cm.Top()
			if chunk != nil {
				m := &MsgChunk{
					CCPos: cc,
					Size:  coords.ChunkSize,
					Data:  chunk.Flatten(),
				}
				conn.Send(m)
			}
			<-time.After(time.Second / 100)
		}
	}
}
<commit_msg>More changes that should have been in previous commit.<commit_after>package main

import (
	"fmt"
	"reflect"
	"sync"
	"time"

	"buildblast/lib/coords"
	"buildblast/lib/game"
	"buildblast/lib/mapgen"
)

type Client struct {
	*ClientConn

	name string

	// Send the client the right chunks.
	cm             *ChunkManager
	blockSendQueue chan *MsgBlock
	chunksOnce     sync.Once

	player *game.Player
}

func NewClient(name string) *Client {
	c := new(Client)
	c.ClientConn = NewClientConn(name)

	c.name = name

	c.cm = NewChunkManager()
	c.blockSendQueue = make(chan *MsgBlock, 10)

	return c
}

func (c *Client) Tick(g *Game, w *game.World) {
	for {
		select {
		case m := <-c.recvQueue:
			c.handleMessage(g, w, m)
		default:
			return
		}
	}
}

func (c *Client) handleMessage(g *Game, w *game.World, m Message) {
	switch m.(type) {
	case *MsgBlock:
		m := m.(*MsgBlock)
		c.handleBlock(g, w, m)

	case *MsgControlsState:
		m := m.(*MsgControlsState)
		m.Controls.Timestamp = m.Timestamp
		c.handleControlState(g, w, m)

	case *MsgChat:
		g.Chat(c.name, m.(*MsgChat).Message)

	case *MsgInventoryState:
		m := m.(*MsgInventoryState)
		c.player.Inventory().SetActiveItems(m.ItemLeft, m.ItemRight)

	case *MsgInventoryMove:
		m := m.(*MsgInventoryMove)
		c.player.Inventory().MoveItems(m.From, m.To)

		c.Send(&MsgInventoryState{
			Items: c.player.Inventory().ItemsToString(),
		})

	default:
		c.Errors <- fmt.Errorf("unknown message recieved from client: %s", reflect.TypeOf(m))
	}
}

func (c *Client) handleBlock(g *Game, w *game.World, m *MsgBlock) {
	// Eventually we should simulate block placement/removal entirely
	// on the server side, but for now, this works fairly well.
	inv := c.player.Inventory()
	curBlock := w.Block(m.Pos)

	if curBlock == mapgen.BLOCK_AIR {
		// Placing a block
		item := game.ItemFromBlock(m.Type)
		if inv.RemoveItem(item) {
			w.ChangeBlock(m.Pos, m.Type)
		} else {
			c.sendBlockChanged(m.Pos, curBlock)
		}
	} else {
		// Removing a block
		item := game.ItemFromBlock(curBlock)
		inv.AddItem(item)
		w.ChangeBlock(m.Pos, m.Type)
	}

	c.Send(&MsgInventoryState{
		Items: c.player.Inventory().ItemsToString(),
	})
}

func (c *Client) handleControlState(g *Game, w *game.World, m *MsgControlsState) {
	pos, vy, hp, hitPos := c.player.ClientTick(m.Controls)

	c.cm.QueueChunksNearby(w, pos)

	c.Send(&MsgPlayerState{
		Pos:       pos,
		VelocityY: vy,
		Timestamp: m.Timestamp,
		Hp:        hp,
	})

	if hitPos != nil {
		g.Broadcast(&MsgDebugRay{
			Pos: *hitPos,
		})
	}
}

func (c *Client) Connected(g *Game, w *game.World) {
	p := game.NewPlayer(w, c.name)

	for _, id := range w.GetEntityIDs() {
		c.Send(&MsgEntityCreate{
			ID: id,
		})
	}

	w.AddEntity(p)
	w.AddBlockListener(c)
	w.AddEntityListener(c)

	c.player = p
	c.Send(&MsgInventoryState{
		Items: c.player.Inventory().ItemsToString(),
	})
}

func (c *Client) Disconnected(g *Game, w *game.World) {
	w.RemoveEntity(c.player)
	w.RemoveBlockListener(c)
	w.RemoveEntityListener(c)
}

func (c *Client) BlockChanged(bc coords.Block, old mapgen.Block, new mapgen.Block) {
	c.sendBlockChanged(bc, new)
}

func (c *Client) EntityCreated(id string) {
	c.Send(&MsgEntityCreate{
		ID: id,
	})
}

func (c *Client) EntityUpdate(id string, pos coords.World, health int) {
	c.SendLossy(&MsgEntityPosition{
		ID:  id,
		Pos: pos,
		Health: health,
	})
}

func (c *Client) EntityDied(id string, killer string) {}

func (c *Client) EntityRemoved(id string) {
	c.Send(&MsgEntityRemove{
		ID: id,
	})
}

func (c *Client) sendBlockChanged(bc coords.Block, b mapgen.Block) {
	m := &MsgBlock{
		Pos:  bc,
		Type: b,
	}
	select {
	case c.blockSendQueue <- m:
	default:
		c.Errors <- fmt.Errorf("unable to send block update to player %s (server overloaded?)", c.name)
	}
}

// WARNING: This runs on a seperate thread from everything
// else in client!
func (c *Client) RunChunks(conn *Conn) {
	// This prevents multiple clients from attempting to connect to
	// the same client's RunChunks, which could cause strange
	// race conditions and other problems.
	action := func() {
		c.internalRunChunks(conn)
	}
	c.chunksOnce.Do(action)
}

func (c *Client) internalRunChunks(conn *Conn) {
	for {
		select {
		case m := <-c.blockSendQueue:
			if !c.cm.ApplyBlockChange(m.Pos, m.Type) {
				conn.Send(m)
			}
		default:
			cc, chunk := c.cm.Top()
			if chunk != nil {
				m := &MsgChunk{
					CCPos: cc,
					Size:  coords.ChunkSize,
					Data:  chunk.Flatten(),
				}
				conn.Send(m)
			}
			<-time.After(time.Second / 100)
		}
	}
}
<|endoftext|>


<commit_before>package server

import (
	"strings"

	"github.com/labstack/echo"
)

func AbsoluteURL(c echo.Context, resource string) string {
	if len(resource) > 0 && resource[0] != '/' {
		resource = "/" + resource
	}
	scheme := c.Scheme()
	if c.Request().Header.Get(echo.HeaderXForwardedProto) == "https" {
		scheme = "https"
	}
	return scheme + "://" + c.Request().Host + resource
}

func SubdomainURL(c echo.Context, subdomain string) string {
	scheme := c.Scheme()
	if c.Request().Header.Get(echo.HeaderXForwardedProto) == "https" {
		scheme = "https"
	}
	locale := LocaleForRequest(c.Request())
	host := strings.TrimPrefix(c.Request().Host, "www.")
	host = strings.TrimPrefix(c.Request().Host, locale.Subdomain+".")
	if subdomain != "" {
		host = subdomain + "." + host
	}
	return scheme + "://" + host
}
<commit_msg>fix extra www fix (#41)<commit_after>package server

import (
	"strings"

	"github.com/labstack/echo"
)

func AbsoluteURL(c echo.Context, resource string) string {
	if len(resource) > 0 && resource[0] != '/' {
		resource = "/" + resource
	}
	scheme := c.Scheme()
	if c.Request().Header.Get(echo.HeaderXForwardedProto) == "https" {
		scheme = "https"
	}
	return scheme + "://" + c.Request().Host + resource
}

func SubdomainURL(c echo.Context, subdomain string) string {
	scheme := c.Scheme()
	if c.Request().Header.Get(echo.HeaderXForwardedProto) == "https" {
		scheme = "https"
	}
	locale := LocaleForRequest(c.Request())
	host := strings.TrimPrefix(c.Request().Host, "www.")
	host = strings.TrimPrefix(host, locale.Subdomain+".")
	if subdomain != "" {
		host = subdomain + "." + host
	}
	return scheme + "://" + host
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func NewEngine() *echo.Echo {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// add custom error formatter
	e.HTTPErrorHandler = HTTPErrorHandler

	// Add html templates with go template syntax
	renderer := NewTemplateRenderer("../templates/layouts/*.html", "../templates/*.html")
	e.Renderer = renderer

	// add controllers
	userCtrl := new(User)
	feedCtrl := new(Feed)
	importCtrl := new(Importer)

	// add routes
	e.GET("/:id", userCtrl.GetUser)
	e.GET("/:id/details", userCtrl.GetUserDetails)
	e.POST("/import", importCtrl.ImportUser)

	// add api endpoints
	g := e.Group("/api")
	g.GET("/:id", userCtrl.GetUserJSON)

	// add feed
	e.GET("/feed", feedCtrl.GetFeed)

	// add static files
	e.Static("/", "assets")

	return e
}
<commit_msg>add debug mode<commit_after>package server

import (
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/starptech/go-web/config"
)

func NewEngine() *echo.Echo {
	c := config.GetConfig()
	e := echo.New()
	e.Debug = !c.IsProduction
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// add custom error formatter
	e.HTTPErrorHandler = HTTPErrorHandler

	// Add html templates with go template syntax
	renderer := NewTemplateRenderer("../templates/layouts/*.html", "../templates/*.html")
	e.Renderer = renderer

	// add controllers
	userCtrl := new(User)
	feedCtrl := new(Feed)
	importCtrl := new(Importer)

	// add routes
	e.GET("/:id", userCtrl.GetUser)
	e.GET("/:id/details", userCtrl.GetUserDetails)
	e.POST("/import", importCtrl.ImportUser)

	// add api endpoints
	g := e.Group("/api")
	g.GET("/:id", userCtrl.GetUserJSON)

	// add feed
	e.GET("/feed", feedCtrl.GetFeed)

	// add static files
	e.Static("/", "assets")

	return e
}
<|endoftext|>


<commit_before>package server

import (
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

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

//GridfsStorage will be made private
type GridfsStorage struct {
	Connection *mgo.Session
}

//Storage interface can be implemented
//to use the image server with any backend you like
type Storage interface {
	StoreChildImage(database, imageFormat string, imageData io.Reader, imageWidth, imageHeight int, original Cacheable, entry *Entry) (Cacheable, error)
	FindImageByParentID(namespace, id string, entry *Entry) (Cacheable, error)
	FindImageByParentFilename(namespace, filename string, entry *Entry) (Cacheable, error)
	IsValidID(id string) bool
}

//NewGridfsStorage returns a new gridfs storage provider
func NewGridfsStorage(con *mgo.Session) (Storage, error) {
	if con == nil {
		return nil, errors.New("mgo.Session must be set")
	}

	return &GridfsStorage{Connection: con}, nil
}

//Cacheable is an interface for caching
type Cacheable interface {
	CacheIdentifier() string
	LastModified() time.Time
	Data() ReadSeekCloser
	Name() string
}

//ReadSeekCloser implements io.ReadCloser and io.Seeker
type ReadSeekCloser interface {
	io.ReadCloser
	io.Seeker
}

//MetaContainer is an optional interface that can be implemented
//to return optional metadata
type MetaContainer interface {
	Meta() map[string]interface{}
}

//Identity returns a unique identifer for its implementor
type Identity interface {
	ID() interface{}
}

type gridFileCacheable struct {
	mf *mgo.GridFile
}

func (gfc gridFileCacheable) LastModified() time.Time {
	return gfc.mf.UploadDate()
}

func (gfc gridFileCacheable) CacheIdentifier() string {
	return gfc.mf.MD5()
}

func (gfc gridFileCacheable) Name() string {
	return gfc.mf.Name()
}

func (gfc gridFileCacheable) Data() ReadSeekCloser {
	return gfc.mf
}

func (gfc gridFileCacheable) Meta() map[string]interface{} {
	originalMetadata := bson.M{}
	if err := gfc.mf.GetMeta(&originalMetadata); err != nil {
		return map[string]interface{}{}
	}

	return originalMetadata
}

//implement `Identity` interface
func (gfc gridFileCacheable) ID() interface{} {
	return gfc.mf.Id()
}

//IsValidID will return true if id is a valid bson object id
func (g GridfsStorage) IsValidID(id string) bool {
	return bson.IsObjectIdHex(id)
}

//FindImageByParentID returns either the resized image that actually exists, or the original if entry is nil
func (g GridfsStorage) FindImageByParentID(namespace, id string, entry *Entry) (Cacheable, error) {
	gridfs := g.Connection.DB(namespace).GridFS("fs")
	var fp *mgo.GridFile
	var query bson.M

	if entry == nil {
		query = bson.M{"_id": bson.ObjectIdHex(id)}
	} else {
		query = bson.M{
			"metadata.original.$id": bson.ObjectIdHex(id),
			"metadata.size":         fmt.Sprintf("%dx%d", entry.Width, entry.Height),
			"metadata.resizeType":   entry.Type}
	}

	iter := gridfs.Find(query).Iter()
	gridfs.OpenNext(iter, &fp)

	if fp == nil {
		return gridFileCacheable{mf: &mgo.GridFile{}}, fmt.Errorf("no image found for id %s", id)
	}

	return &gridFileCacheable{mf: fp}, nil

}

// FindImageByParentFilename returns either the resized image that actually exists, or the original if entry is nil
func (g GridfsStorage) FindImageByParentFilename(namespace, filename string, entry *Entry) (Cacheable, error) {
	gridfs := g.Connection.DB(namespace).GridFS("fs")
	var fp *mgo.GridFile
	var query bson.M

	if entry == nil {
		query = bson.M{"filename": filename}
	} else {
		query = bson.M{
			"metadata.originalFilename": filename,
			"metadata.size":             fmt.Sprintf("%dx%d", entry.Width, entry.Height),
			"metadata.resizeType":       entry.Type}
	}

	iter := gridfs.Find(query).Iter()
	gridfs.OpenNext(iter, &fp)
	if fp == nil {
		return nil, fmt.Errorf("no image found for filename %s", filename)
	}

	return &gridFileCacheable{mf: fp}, nil
}

func getRandomFilename(extension string) string {
	hash := sha256.New()
	hash.Write([]byte(fmt.Sprintf("%s", time.Now().Nanosecond())))
	md := hash.Sum(nil)
	mdStr := hex.EncodeToString(md)

	return fmt.Sprintf("%s.%s", mdStr, extension)
}

//StoreChildImage will create a new image from source
func (g GridfsStorage) StoreChildImage(
	database,
	imageFormat string,
	reader io.Reader,
	imageWidth,
	imageHeight int,
	original Cacheable,
	entry *Entry,
) (Cacheable, error) {
	con := g.Connection.Copy()
	defer con.Close()
	con.EnsureSafe(&mgo.Safe{W: 1, J: true})

	gridfs := con.DB(database).GridFS("fs")
	targetfile, err := gridfs.Create(getRandomFilename(imageFormat))

	if err != nil {
		return nil, err
	}

	defer targetfile.Close()

	_, err = io.Copy(targetfile, reader)

	if err != nil {
		log.Printf("Could not write file completely, cleaning %s\n", targetfile.Name())
		targetfile.Abort()
		return nil, err
	}

	metadata := bson.M{
		"width":            imageWidth,
		"height":           imageHeight,
		"originalFilename": original.Name(),
		"resizeType":       entry.Type,
		"size":             fmt.Sprintf("%dx%d", entry.Width, entry.Height)}

	if identifier, ok := original.(Identity); ok {
		metadata["original"] = mgo.DBRef{Collection: "fs.files", Id: identifier.ID()}
	}

	if metaContainer, ok := original.(MetaContainer); ok {
		parentMeta := metaContainer.Meta()
		for k, v := range parentMeta {
			if _, exists := metadata[k]; !exists {
				metadata[k] = v
			}
		}
	}

	targetfile.SetContentType("image/" + imageFormat)
	targetfile.SetMeta(metadata)

	return &gridFileCacheable{mf: targetfile}, nil
}
<commit_msg>Improve logging<commit_after>package server

import (
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"log"
	"time"

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

//GridfsStorage will be made private
type GridfsStorage struct {
	Connection *mgo.Session
}

//Storage interface can be implemented
//to use the image server with any backend you like
type Storage interface {
	StoreChildImage(database, imageFormat string, imageData io.Reader, imageWidth, imageHeight int, original Cacheable, entry *Entry) (Cacheable, error)
	FindImageByParentID(namespace, id string, entry *Entry) (Cacheable, error)
	FindImageByParentFilename(namespace, filename string, entry *Entry) (Cacheable, error)
	IsValidID(id string) bool
}

//NewGridfsStorage returns a new gridfs storage provider
func NewGridfsStorage(con *mgo.Session) (Storage, error) {
	if con == nil {
		return nil, errors.New("mgo.Session must be set")
	}

	return &GridfsStorage{Connection: con}, nil
}

//Cacheable is an interface for caching
type Cacheable interface {
	CacheIdentifier() string
	LastModified() time.Time
	Data() ReadSeekCloser
	Name() string
}

//ReadSeekCloser implements io.ReadCloser and io.Seeker
type ReadSeekCloser interface {
	io.ReadCloser
	io.Seeker
}

//MetaContainer is an optional interface that can be implemented
//to return optional metadata
type MetaContainer interface {
	Meta() map[string]interface{}
}

//Identity returns a unique identifer for its implementor
type Identity interface {
	ID() interface{}
}

type gridFileCacheable struct {
	mf *mgo.GridFile
}

func (gfc gridFileCacheable) LastModified() time.Time {
	return gfc.mf.UploadDate()
}

func (gfc gridFileCacheable) CacheIdentifier() string {
	return gfc.mf.MD5()
}

func (gfc gridFileCacheable) Name() string {
	return gfc.mf.Name()
}

func (gfc gridFileCacheable) Data() ReadSeekCloser {
	return gfc.mf
}

func (gfc gridFileCacheable) Meta() map[string]interface{} {
	originalMetadata := bson.M{}
	if err := gfc.mf.GetMeta(&originalMetadata); err != nil {
		return map[string]interface{}{}
	}

	return originalMetadata
}

//implement `Identity` interface
func (gfc gridFileCacheable) ID() interface{} {
	return gfc.mf.Id()
}

//IsValidID will return true if id is a valid bson object id
func (g GridfsStorage) IsValidID(id string) bool {
	return bson.IsObjectIdHex(id)
}

//FindImageByParentID returns either the resized image that actually exists, or the original if entry is nil
func (g GridfsStorage) FindImageByParentID(namespace, id string, entry *Entry) (Cacheable, error) {
	gridfs := g.Connection.DB(namespace).GridFS("fs")
	var fp *mgo.GridFile
	var query bson.M

	if entry == nil {
		query = bson.M{"_id": bson.ObjectIdHex(id)}
	} else {
		query = bson.M{
			"metadata.original.$id": bson.ObjectIdHex(id),
			"metadata.size":         fmt.Sprintf("%dx%d", entry.Width, entry.Height),
			"metadata.resizeType":   entry.Type}
	}

	iter := gridfs.Find(query).Iter()
	gridfs.OpenNext(iter, &fp)

	if fp == nil {
		return gridFileCacheable{mf: &mgo.GridFile{}}, fmt.Errorf("no image found for id %s", id)
	}

	return &gridFileCacheable{mf: fp}, nil

}

// FindImageByParentFilename returns either the resized image that actually exists, or the original if entry is nil
func (g GridfsStorage) FindImageByParentFilename(namespace, filename string, entry *Entry) (Cacheable, error) {
	gridfs := g.Connection.DB(namespace).GridFS("fs")
	var fp *mgo.GridFile
	var query bson.M

	if entry == nil {
		query = bson.M{"filename": filename}
	} else {
		query = bson.M{
			"metadata.originalFilename": filename,
			"metadata.size":             fmt.Sprintf("%dx%d", entry.Width, entry.Height),
			"metadata.resizeType":       entry.Type}
	}

	iter := gridfs.Find(query).Iter()
	gridfs.OpenNext(iter, &fp)
	if fp == nil {
		return nil, fmt.Errorf("no image found for filename %s", filename)
	}

	return &gridFileCacheable{mf: fp}, nil
}

func getRandomFilename(extension string) string {
	hash := sha256.New()
	hash.Write([]byte(fmt.Sprintf("%s", time.Now().Nanosecond())))
	md := hash.Sum(nil)
	mdStr := hex.EncodeToString(md)

	return fmt.Sprintf("%s.%s", mdStr, extension)
}

//StoreChildImage will create a new image from source
func (g GridfsStorage) StoreChildImage(
	database,
	imageFormat string,
	reader io.Reader,
	imageWidth,
	imageHeight int,
	original Cacheable,
	entry *Entry,
) (Cacheable, error) {
	con := g.Connection.Copy()
	defer con.Close()
	con.EnsureSafe(&mgo.Safe{W: 1, J: true})

	gridfs := con.DB(database).GridFS("fs")
	targetfile, err := gridfs.Create(getRandomFilename(imageFormat))

	if err != nil {
		return nil, err
	}

	defer targetfile.Close()

	_, err = io.Copy(targetfile, reader)

	if err != nil {
		log.Printf("Error for filename %s with size %dx%d\n", original.Name(), entry.Width, entry.Height)
		log.Printf("Could not write file completely, cleaning %s\n", targetfile.Name())
		targetfile.Abort()
		return nil, err
	}

	metadata := bson.M{
		"width":            imageWidth,
		"height":           imageHeight,
		"originalFilename": original.Name(),
		"resizeType":       entry.Type,
		"size":             fmt.Sprintf("%dx%d", entry.Width, entry.Height)}

	if identifier, ok := original.(Identity); ok {
		metadata["original"] = mgo.DBRef{Collection: "fs.files", Id: identifier.ID()}
	}

	if metaContainer, ok := original.(MetaContainer); ok {
		parentMeta := metaContainer.Meta()
		for k, v := range parentMeta {
			if _, exists := metadata[k]; !exists {
				metadata[k] = v
			}
		}
	}

	targetfile.SetContentType("image/" + imageFormat)
	targetfile.SetMeta(metadata)

	return &gridFileCacheable{mf: targetfile}, nil
}
<|endoftext|>