<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metric

import (
	"context"
	"log"
	"net"
	"os"
	"testing"

	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client     monitoring.MetricServiceClient
	conn       *grpc.ClientConn
	ctx        context.Context
	grpcServer *grpc.Server
	lis        *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{
		Name: "test create time series request",
	}
	want := &empty.Empty{}
	response, err := client.CreateTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{
		Name: "test list time series request",
	}
	want := &monitoring.ListTimeSeriesResponse{
		TimeSeries:      []*monitoring.TimeSeries{},
		NextPageToken:   "",
		ExecutionErrors: []*status.Status{},
	}

	response, err := client.ListTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{
		Name: "test get metric monitored resource descriptor",
	}
	want := &monitoredres.MonitoredResourceDescriptor{}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{
		Name: "test list monitored resource descriptors",
	}
	want := &monitoring.ListMonitoredResourceDescriptorsResponse{
		ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
	}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{
		Name: "test get metric descriptor",
	}
	want := &metric.MetricDescriptor{}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMetricDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMetricDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{
		Name:             "test create metric descriptor",
		MetricDescriptor: &metric.MetricDescriptor{},
	}
	want := &metric.MetricDescriptor{}

	response, err := client.CreateMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{
		Name: "test create metric descriptor",
	}
	want := &empty.Empty{}

	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{
		Name: "test list metric decriptors request",
	}
	want := &monitoring.ListMetricDescriptorsResponse{
		MetricDescriptors: []*metric.MetricDescriptor{},
	}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMetricDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMetricDescriptors(%q) == %q, want %q", in, response, want)
	}
}
<commit_msg>add error test for getmetricdescriptor rpc<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metric

import (
	"context"
	"log"
	"net"
	"os"
	"testing"
	"strings"

	"google.golang.org/genproto/googleapis/rpc/errdetails"
	sts "google.golang.org/grpc/status"
	"github.com/googleinterns/cloud-operations-api-mock/validation"
	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client     monitoring.MetricServiceClient
	conn       *grpc.ClientConn
	ctx        context.Context
	grpcServer *grpc.Server
	lis        *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{
		Name: "test create time series request",
	}
	want := &empty.Empty{}
	response, err := client.CreateTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{
		Name: "test list time series request",
	}
	want := &monitoring.ListTimeSeriesResponse{
		TimeSeries:      []*monitoring.TimeSeries{},
		NextPageToken:   "",
		ExecutionErrors: []*status.Status{},
	}

	response, err := client.ListTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{
		Name: "test get metric monitored resource descriptor",
	}
	want := &monitoredres.MonitoredResourceDescriptor{}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{
		Name: "test list monitored resource descriptors",
	}
	want := &monitoring.ListMonitoredResourceDescriptorsResponse{
		ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
	}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{
		Name: "test get metric descriptor",
	}
	want := &metric.MetricDescriptor{}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMetricDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMetricDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptorError(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{}
	want := validation.MissingFieldError.Err()
	missingField := map[string]struct{}{"Name": {}}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("CreateSpan(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("GetMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validateErrDetails(err, missingField); !valid {
		t.Errorf("Expected missing fields %q", missingField)
	}
}

func validateErrDetails(err error, missingFields map[string]struct{}) bool {
	st := sts.Convert(err)
	for _, detail := range st.Details() {
		switch t := detail.(type) {
		case *errdetails.BadRequest:
			for _, violation := range t.GetFieldViolations() {
				if _, ok := missingFields[violation.GetField()]; !ok {
					return false
				}
			}
		}
	}
	return true
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{
		Name:             "test create metric descriptor",
		MetricDescriptor: &metric.MetricDescriptor{},
	}
	want := &metric.MetricDescriptor{}

	response, err := client.CreateMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{
		Name: "test create metric descriptor",
	}
	want := &empty.Empty{}

	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{
		Name: "test list metric decriptors request",
	}
	want := &monitoring.ListMetricDescriptorsResponse{
		MetricDescriptors: []*metric.MetricDescriptor{},
	}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMetricDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMetricDescriptors(%q) == %q, want %q", in, response, want)
	}
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"fmt"
	"net/http"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/oauth2"
)

// AuthorizedToken extracts the token and validates; if valid the next handler
// will be run.  The principal will be sent to the next handler via the request's
// Context.  It is up to the next handler to determine if the principal has access.
// On failure, will return http.StatusForbidden.
func AuthorizedToken(auth oauth2.Authenticator, logger chronograf.Logger, next http.Handler) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log := logger.
			WithField("component", "auth").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL)

		ctx := r.Context()
		// We do not check the authorization of the principal.  Those
		// served further down the chain should do so.
		principal, err := auth.Validate(ctx, r)
		if err != nil {
			log.Error("Invalid principal")
			w.WriteHeader(http.StatusForbidden)
			return
		}

		// If the principal is valid we will extend its lifespan
		// into the future
		principal, err = auth.Extend(ctx, w, principal)
		if err != nil {
			log.Error("Unable to extend principal")
			w.WriteHeader(http.StatusForbidden)
			return
		}

		// Send the principal to the next handler
		ctx = context.WithValue(ctx, oauth2.PrincipalKey, principal)
		next.ServeHTTP(w, r.WithContext(ctx))
		return
	})
}

func AuthorizedUser(store chronograf.UsersStore, useAuth bool, role string, logger chronograf.Logger, next http.HandlerFunc) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if !useAuth {
			next(w, r)
			return
		}

		log := logger.
			WithField("component", "role_auth").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL)

		ctx := r.Context()

		username, err := getUsername(ctx)
		if err != nil {
			log.Error("Failed to retrieve username from context")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User is not authorized"), logger)
			return
		}
		provider, err := getProvider(ctx)
		if err != nil {
			log.Error("Failed to retrieve provider from context")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
			return
		}

		u, err := getUserBy(store, ctx, username, provider)
		if err != nil {
			log.Error("Error to retrieving user")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
			return
		}

		if u == nil {
			log.Error("User not found")
			Error(w, http.StatusNotFound, fmt.Sprintf("User with name %s and provider %s not found", username, provider), logger)
			return
		}

		if hasPrivelege(u, role) {
			next(w, r)
			return
		}

		Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
		return

	})
}

func hasPrivelege(u *chronograf.User, role string) bool {
	if u == nil {
		return false
	}

	switch role {
	case ViewerRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case ViewerRoleName, EditorRoleName, AdminRoleName:
				return true
			default:
				return false
			}
		}
	case EditorRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case EditorRoleName, AdminRoleName:
				return true
			default:
				return false
			}
		}
	case AdminRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case AdminRoleName:
				return true
			default:
				return false
			}
		}
	default:
		return false
	}

	return false
}
<commit_msg>Add comment to AuthorizedUser<commit_after>package server

import (
	"context"
	"fmt"
	"net/http"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/oauth2"
)

// AuthorizedToken extracts the token and validates; if valid the next handler
// will be run.  The principal will be sent to the next handler via the request's
// Context.  It is up to the next handler to determine if the principal has access.
// On failure, will return http.StatusForbidden.
func AuthorizedToken(auth oauth2.Authenticator, logger chronograf.Logger, next http.Handler) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log := logger.
			WithField("component", "auth").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL)

		ctx := r.Context()
		// We do not check the authorization of the principal.  Those
		// served further down the chain should do so.
		principal, err := auth.Validate(ctx, r)
		if err != nil {
			log.Error("Invalid principal")
			w.WriteHeader(http.StatusForbidden)
			return
		}

		// If the principal is valid we will extend its lifespan
		// into the future
		principal, err = auth.Extend(ctx, w, principal)
		if err != nil {
			log.Error("Unable to extend principal")
			w.WriteHeader(http.StatusForbidden)
			return
		}

		// Send the principal to the next handler
		ctx = context.WithValue(ctx, oauth2.PrincipalKey, principal)
		next.ServeHTTP(w, r.WithContext(ctx))
		return
	})
}

// AuthorizedUser extracts the user name and provider from context. If the user and provider can be found on the
// context, we look up the user by their name and provider. If the user is found, we verify that the user has at
// at least the role supplied.
func AuthorizedUser(store chronograf.UsersStore, useAuth bool, role string, logger chronograf.Logger, next http.HandlerFunc) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if !useAuth {
			next(w, r)
			return
		}

		log := logger.
			WithField("component", "role_auth").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL)

		ctx := r.Context()

		username, err := getUsername(ctx)
		if err != nil {
			log.Error("Failed to retrieve username from context")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User is not authorized"), logger)
			return
		}
		provider, err := getProvider(ctx)
		if err != nil {
			log.Error("Failed to retrieve provider from context")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
			return
		}

		u, err := getUserBy(store, ctx, username, provider)
		if err != nil {
			log.Error("Error to retrieving user")
			Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
			return
		}

		if u == nil {
			log.Error("User not found")
			Error(w, http.StatusNotFound, fmt.Sprintf("User with name %s and provider %s not found", username, provider), logger)
			return
		}

		if hasPrivelege(u, role) {
			next(w, r)
			return
		}

		Error(w, http.StatusUnauthorized, fmt.Sprintf("User %s is not authorized", username), logger)
		return

	})
}

func hasPrivelege(u *chronograf.User, role string) bool {
	if u == nil {
		return false
	}

	switch role {
	case ViewerRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case ViewerRoleName, EditorRoleName, AdminRoleName:
				return true
			default:
				return false
			}
		}
	case EditorRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case EditorRoleName, AdminRoleName:
				return true
			default:
				return false
			}
		}
	case AdminRoleName:
		for _, r := range u.Roles {
			switch r.Name {
			case AdminRoleName:
				return true
			default:
				return false
			}
		}
	default:
		return false
	}

	return false
}
<|endoftext|>


<commit_before>package server

import (
	"crypto/tls"
	"net"
	"sync"

	"github.com/emersion/go-imap/common"
	"github.com/emersion/go-imap/backend"
)

type Conn struct {
	*common.Conn

	isTLS bool
	continues chan bool
	silent bool
	locker sync.Locker

	// This connection's server.
	Server *Server
	// This connection's current state.
	State common.ConnState
	// If the client is logged in, the user.
	User backend.User
	// If the client has selected a mailbox, the mailbox.
	Mailbox backend.Mailbox
	// True if the currently selected mailbox has been opened in read-only mode.
	MailboxReadOnly bool
}

// Write a response to this connection.
func (c *Conn) WriteResp(res common.WriterTo) error {
	c.locker.Lock()
	defer c.locker.Unlock()

	if err := res.WriteTo(c.Writer); err != nil {
		return err
	}

	return c.Writer.Flush()
}

// Close this connection.
func (c *Conn) Close() error {
	if c.User != nil {
		c.User.Logout()
	}

	if err := c.Conn.Close(); err != nil {
		return err
	}

	close(c.continues)

	c.State = common.LogoutState
	return nil
}

func (c *Conn) getCaps() (caps []string) {
	caps = []string{"IMAP4rev1"}

	if c.State == common.NotAuthenticatedState {
		if !c.IsTLS() && c.Server.TLSConfig != nil {
			caps = append(caps, "STARTTLS")
		}

		if !c.CanAuth() {
			caps = append(caps, "LOGINDISABLED")
		} else {
			caps = append(caps, "AUTH=PLAIN")
		}
	}

	caps = append(caps, c.Server.getCaps(c.State)...)
	return
}

func (c *Conn) sendContinuationReqs() {
	for range c.continues {
		cont := &common.ContinuationResp{Info: "send literal"}
		cont.WriteTo(c.Writer)
	}
}

func (c *Conn) greet() error {
	caps := c.getCaps()
	args := make([]interface{}, len(caps))
	for i, cap := range caps {
		args[i] = cap
	}

	greeting := &common.StatusResp{
		Tag: "*",
		Type: common.OK,
		Code: common.Capability,
		Arguments: args,
		Info: "IMAP4rev1 Service Ready",
	}

	return c.WriteResp(greeting)
}

// Check if this connection is encrypted.
func (c *Conn) IsTLS() bool {
	return c.isTLS
}

// Check if the client can use plain text authentication.
func (c *Conn) CanAuth() bool {
	return c.IsTLS() || c.Server.AllowInsecureAuth
}

func newConn(s *Server, c net.Conn) *Conn {
	continues := make(chan bool)
	r := common.NewServerReader(nil, continues)
	w := common.NewWriter(nil)

	_, isTLS := c.(*tls.Conn)

	conn := &Conn{
		Conn: common.NewConn(c, r, w),

		isTLS: isTLS,
		continues: continues,
		locker: &sync.Mutex{},

		Server: s,
		State: common.NotAuthenticatedState,
	}

	go conn.sendContinuationReqs()

	return conn
}
<commit_msg>server: fixes conn not flushed after writing continuation requests<commit_after>package server

import (
	"crypto/tls"
	"log"
	"net"
	"sync"

	"github.com/emersion/go-imap/common"
	"github.com/emersion/go-imap/backend"
)

type Conn struct {
	*common.Conn

	isTLS bool
	continues chan bool
	silent bool
	locker sync.Locker

	// This connection's server.
	Server *Server
	// This connection's current state.
	State common.ConnState
	// If the client is logged in, the user.
	User backend.User
	// If the client has selected a mailbox, the mailbox.
	Mailbox backend.Mailbox
	// True if the currently selected mailbox has been opened in read-only mode.
	MailboxReadOnly bool
}

// Write a response to this connection.
func (c *Conn) WriteResp(res common.WriterTo) error {
	c.locker.Lock()
	defer c.locker.Unlock()

	if err := res.WriteTo(c.Writer); err != nil {
		return err
	}

	return c.Writer.Flush()
}

// Close this connection.
func (c *Conn) Close() error {
	if c.User != nil {
		c.User.Logout()
	}

	if err := c.Conn.Close(); err != nil {
		return err
	}

	close(c.continues)

	c.State = common.LogoutState
	return nil
}

func (c *Conn) getCaps() (caps []string) {
	caps = []string{"IMAP4rev1"}

	if c.State == common.NotAuthenticatedState {
		if !c.IsTLS() && c.Server.TLSConfig != nil {
			caps = append(caps, "STARTTLS")
		}

		if !c.CanAuth() {
			caps = append(caps, "LOGINDISABLED")
		} else {
			caps = append(caps, "AUTH=PLAIN")
		}
	}

	caps = append(caps, c.Server.getCaps(c.State)...)
	return
}

func (c *Conn) sendContinuationReqs() {
	for range c.continues {
		cont := &common.ContinuationResp{Info: "send literal"}
		if err := c.WriteResp(cont); err != nil {
			log.Println("WARN: cannot send continuation request:", err)
		}
	}
}

func (c *Conn) greet() error {
	caps := c.getCaps()
	args := make([]interface{}, len(caps))
	for i, cap := range caps {
		args[i] = cap
	}

	greeting := &common.StatusResp{
		Tag: "*",
		Type: common.OK,
		Code: common.Capability,
		Arguments: args,
		Info: "IMAP4rev1 Service Ready",
	}

	return c.WriteResp(greeting)
}

// Check if this connection is encrypted.
func (c *Conn) IsTLS() bool {
	return c.isTLS
}

// Check if the client can use plain text authentication.
func (c *Conn) CanAuth() bool {
	return c.IsTLS() || c.Server.AllowInsecureAuth
}

func newConn(s *Server, c net.Conn) *Conn {
	continues := make(chan bool)
	r := common.NewServerReader(nil, continues)
	w := common.NewWriter(nil)

	_, isTLS := c.(*tls.Conn)

	conn := &Conn{
		Conn: common.NewConn(c, r, w),

		isTLS: isTLS,
		continues: continues,
		locker: &sync.Mutex{},

		Server: s,
		State: common.NotAuthenticatedState,
	}

	go conn.sendContinuationReqs()

	return conn
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"github.com/albertyw/devops-reactions-index/tumblr"
	"io/ioutil"
	"net/http"
	"os"
)

const dataURLPath = "/data.json"

var templateDir = os.Getenv("SERVER_TEMPLATES")
var indexPath = fmt.Sprintf("%s/index.htm", templateDir)
var uRLFilePaths = map[string]func() (string, error){}
var posts []tumblr.Post

func readFile(p string) func(http.ResponseWriter, *http.Request) {
	path := p
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return
		}
		html := string(data)
		fmt.Fprintf(w, html)
	}
}

func dataURLHandler(w http.ResponseWriter, r *http.Request) {
	html := tumblr.PostsToJSON(posts)
	fmt.Fprintf(w, html)
}

// Run starts up the HTTP server
func Run(p []tumblr.Post) {
	posts = p
	address := ":" + os.Getenv("PORT")
	fmt.Println("server listening on", address)
	http.HandleFunc("/", readFile(indexPath))
	http.HandleFunc(dataURLPath, dataURLHandler)
	http.ListenAndServe(address, nil)
}
<commit_msg>Fix go http being too lenient with url pattern matching<commit_after>package server

import (
	"fmt"
	"github.com/albertyw/devops-reactions-index/tumblr"
	"io/ioutil"
	"net/http"
	"os"
)

const dataURLPath = "/data.json"

var templateDir = os.Getenv("SERVER_TEMPLATES")
var indexPath = fmt.Sprintf("%s/index.htm", templateDir)
var uRLFilePaths = map[string]func() (string, error){}
var posts []tumblr.Post

func exactURL(
	targetFunc func(http.ResponseWriter, *http.Request),
	requestedPath string,
) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != requestedPath {
			http.NotFound(w, r)
			return
		}
		targetFunc(w, r)
		return
	}
}

func readFile(p string) func(http.ResponseWriter, *http.Request) {
	path := p
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return
		}
		html := string(data)
		fmt.Fprintf(w, html)
	}
}

func dataURLHandler(w http.ResponseWriter, r *http.Request) {
	html := tumblr.PostsToJSON(posts)
	fmt.Fprintf(w, html)
}

// Run starts up the HTTP server
func Run(p []tumblr.Post) {
	posts = p
	address := ":" + os.Getenv("PORT")
	fmt.Println("server listening on", address)
	http.HandleFunc("/", exactURL(readFile(indexPath), "/"))
	http.HandleFunc(dataURLPath, dataURLHandler)
	http.ListenAndServe(address, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"code.google.com/p/go.net/websocket"
	"github.com/sbinet/liner"
)

var globalGame = NewGame()

func handler(w http.ResponseWriter, r *http.Request) {
	//A hack because either my version of go or chrome is messing of the content type (probably go).
	if strings.HasSuffix(r.URL.Path, ".css") {
		w.Header().Set("Content-Type", "text/css")
	}
	http.ServeFile(w, r, "."+r.URL.Path)
}

func getClientName(config *websocket.Config) string {
	path := config.Location.Path
	bits := strings.Split(path, "/")
	if len(bits) < 4 {
		return ""
	}
	return bits[3]
}

func mainSocketHandler(ws *websocket.Conn) {
	conn := NewConn(ws)

	msg, err := conn.Recv()
	if err != nil {
		log.Println("Error connecting client, unable to read handshake message: ", err)
		return
	}

	baseName := msg.(*MsgHandshakeInit).DesiredName
	if baseName == "" {
		baseName = "guest"
	}

	name := baseName
	nameNumber := 1
	var client *Client
	for {
		var isNew bool
		client, isNew = globalGame.clientWithID(name)
		if isNew {
			break
		}
		name = fmt.Sprintf("%s-%d", baseName, nameNumber)
		nameNumber++
	}

	conn.Send(&MsgHandshakeReply{
		ServerTime: float64(time.Now().UnixNano()) / 1e6,
		ClientID:   name,
	})

	client.Run(conn)
}

func chunkSocketHandler(ws *websocket.Conn) {
	name := getClientName(ws.Config())

	client, isNew := globalGame.clientWithID(name)
	if isNew {
		log.Println("Warning: Attempt to connect to chunk socket for client '" + name + "' who is not connected on main socket!")
		globalGame.Disconnect(name, "invalid connection")
		return
	}
	client.RunChunks(NewConn(ws))
}

func doProfile() {
	f, err := os.Create("cpuprofile")
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)

	go func() {
		cycles := 4
		for i := 0; i < cycles; i++ {
			log.Print((cycles-i)*30, " seconds left")
			<-time.After(30 * time.Second)
		}
		pprof.StopCPUProfile()
		log.Print("Done! Exiting...")
		os.Exit(1)
	}()
}

func setupPrompt() {
	quit := make(chan bool)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	state := liner.NewLiner()
	go promptLoop(quit, state)

	go func() {
		<-c
		fmt.Println()
		quit <- true
	}()

	go func() {
		<-quit
		state.Close()
		os.Exit(0)
	}()
}

func promptLoop(quit chan bool, state *liner.State) {
	for {
		cmd, err := state.Prompt(" >>> ")
		state.AppendHistory(cmd)
		if err != nil {
			fmt.Println()
			log.Println("ERROR:", err)
			quit <- true
			return
		}
		if cmd == "exit" {
			quit <- true
			return
		}
	}
}

func main() {
	// 	setupPrompt()

	runtime.GOMAXPROCS(runtime.NumCPU())
	go globalGame.Run()
	// 	go doProfile()

	http.HandleFunc("/", handler)
	http.Handle("/sockets/main/", websocket.Handler(mainSocketHandler))
	http.Handle("/sockets/chunk/", websocket.Handler(chunkSocketHandler))

	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}
<commit_msg>Personalize comment.<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"code.google.com/p/go.net/websocket"
	"github.com/sbinet/liner"
)

var globalGame = NewGame()

func handler(w http.ResponseWriter, r *http.Request) {
	// Workaround for Quentin's system configuration.
	// For some reason, css files are getting served
	// without a content-type...
	if strings.HasSuffix(r.URL.Path, ".css") {
		w.Header().Set("Content-Type", "text/css")
	}
	http.ServeFile(w, r, "."+r.URL.Path)
}

func getClientName(config *websocket.Config) string {
	path := config.Location.Path
	bits := strings.Split(path, "/")
	if len(bits) < 4 {
		return ""
	}
	return bits[3]
}

func mainSocketHandler(ws *websocket.Conn) {
	conn := NewConn(ws)

	msg, err := conn.Recv()
	if err != nil {
		log.Println("Error connecting client, unable to read handshake message: ", err)
		return
	}

	baseName := msg.(*MsgHandshakeInit).DesiredName
	if baseName == "" {
		baseName = "guest"
	}

	name := baseName
	nameNumber := 1
	var client *Client
	for {
		var isNew bool
		client, isNew = globalGame.clientWithID(name)
		if isNew {
			break
		}
		name = fmt.Sprintf("%s-%d", baseName, nameNumber)
		nameNumber++
	}

	conn.Send(&MsgHandshakeReply{
		ServerTime: float64(time.Now().UnixNano()) / 1e6,
		ClientID:   name,
	})

	client.Run(conn)
}

func chunkSocketHandler(ws *websocket.Conn) {
	name := getClientName(ws.Config())

	client, isNew := globalGame.clientWithID(name)
	if isNew {
		log.Println("Warning: Attempt to connect to chunk socket for client '" + name + "' who is not connected on main socket!")
		globalGame.Disconnect(name, "invalid connection")
		return
	}
	client.RunChunks(NewConn(ws))
}

func doProfile() {
	f, err := os.Create("cpuprofile")
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)

	go func() {
		cycles := 4
		for i := 0; i < cycles; i++ {
			log.Print((cycles-i)*30, " seconds left")
			<-time.After(30 * time.Second)
		}
		pprof.StopCPUProfile()
		log.Print("Done! Exiting...")
		os.Exit(1)
	}()
}

func setupPrompt() {
	quit := make(chan bool)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	state := liner.NewLiner()
	go promptLoop(quit, state)

	go func() {
		<-c
		fmt.Println()
		quit <- true
	}()

	go func() {
		<-quit
		state.Close()
		os.Exit(0)
	}()
}

func promptLoop(quit chan bool, state *liner.State) {
	for {
		cmd, err := state.Prompt(" >>> ")
		state.AppendHistory(cmd)
		if err != nil {
			fmt.Println()
			log.Println("ERROR:", err)
			quit <- true
			return
		}
		if cmd == "exit" {
			quit <- true
			return
		}
	}
}

func main() {
	// 	setupPrompt()

	runtime.GOMAXPROCS(runtime.NumCPU())
	go globalGame.Run()
	// 	go doProfile()

	http.HandleFunc("/", handler)
	http.Handle("/sockets/main/", websocket.Handler(mainSocketHandler))
	http.Handle("/sockets/chunk/", websocket.Handler(chunkSocketHandler))

	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}
<|endoftext|>


<commit_before>/*
 Contains various general helper functions
*/

package server

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
)

// Wrapper type for compund errors errors
type wrapError struct {
	text  string
	inner error
}

func (e wrapError) Error() string {
	text := e.text
	if e.inner != nil {
		text += ": " + e.inner.Error()
	}
	return text
}

// throw panics, if there is an error. Rob Pike must never know.
func throw(err error) {
	if err != nil {
		panic(err)
	}
}

// checkAuth checks if the suplied Ident is priveledged to perform an action
func checkAuth(action string, ident Ident) bool {
	if class, ok := config.Staff.Classes[ident.Auth]; ok {
		return class.Rights[action]
	}
	return false
}

// Determine access rights of an IP
func lookUpIdent(ip string) Ident {
	ident := Ident{IP: ip}

	// TODO: BANS

	return ident
}

// Confirm client has rights to access board
func canAccessBoard(board string, ident Ident) bool {
	var isBoard bool
	if board == "all" {
		isBoard = true
	} else {
		for _, b := range config.Boards.Enabled {
			if board == b {
				isBoard = true
				break
			}
		}
	}
	return isBoard && !ident.Banned
}

// Compute a truncated MD5 hash from a buffer
func hashBuffer(buf []byte) string {
	hasher := md5.New()
	_, err := hasher.Write(buf)
	throw(err)
	return hex.EncodeToString(hasher.Sum(nil))[:16]
}

// Shorthand for marshaling JSON and handling the error
func marshalJSON(input interface{}) []byte {
	data, err := json.Marshal(input)
	throw(err)
	return data
}

// Shorthand for unmarshalling JSON
func unmarshalJSON(data []byte, store interface{}) {
	throw(json.Unmarshal(data, store))
}

// copyFile reads a file from disk and copies it into the writer
func copyFile(path string, writer io.Writer) {
	file, err := os.Open(path)
	throw(err)
	defer file.Close()
	_, err = io.Copy(writer, file)
	throw(err)
}

// Shorthand for converting a post ID to a string for JSON keys
func idToString(id uint64) string {
	return strconv.FormatUint(id, 10)
}

// chooseLang selects the language to use in responses to the client, by
// checking the language setting of the request's cookies and verifying it
// against the available selection on the server. Defaults to the server's
// default language.
func chooseLang(req *http.Request) string {
	cookie, err := req.Cookie("lang")
	if err == http.ErrNoCookie { // Only possible error
		return config.Lang.Default
	}
	for _, lang := range config.Lang.Enabled {
		if cookie.Value == lang {
			return lang
		}
	}
	return config.Lang.Default
}

// Log an error with its stack trace
func logError(req *http.Request, err interface{}) {
	const size = 64 << 10
	buf := make([]byte, size)
	buf = buf[:runtime.Stack(buf, false)]
	log.Printf("panic serving %v: %v\n%s", req.RemoteAddr, err, buf)
}
<commit_msg>server/util.go Fix comment typo<commit_after>/*
 Contains various general helper functions
*/

package server

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
)

// Wrapper type for compound errors
type wrapError struct {
	text  string
	inner error
}

func (e wrapError) Error() string {
	text := e.text
	if e.inner != nil {
		text += ": " + e.inner.Error()
	}
	return text
}

// throw panics, if there is an error. Rob Pike must never know.
func throw(err error) {
	if err != nil {
		panic(err)
	}
}

// checkAuth checks if the suplied Ident is priveledged to perform an action
func checkAuth(action string, ident Ident) bool {
	if class, ok := config.Staff.Classes[ident.Auth]; ok {
		return class.Rights[action]
	}
	return false
}

// Determine access rights of an IP
func lookUpIdent(ip string) Ident {
	ident := Ident{IP: ip}

	// TODO: BANS

	return ident
}

// Confirm client has rights to access board
func canAccessBoard(board string, ident Ident) bool {
	var isBoard bool
	if board == "all" {
		isBoard = true
	} else {
		for _, b := range config.Boards.Enabled {
			if board == b {
				isBoard = true
				break
			}
		}
	}
	return isBoard && !ident.Banned
}

// Compute a truncated MD5 hash from a buffer
func hashBuffer(buf []byte) string {
	hasher := md5.New()
	_, err := hasher.Write(buf)
	throw(err)
	return hex.EncodeToString(hasher.Sum(nil))[:16]
}

// Shorthand for marshaling JSON and handling the error
func marshalJSON(input interface{}) []byte {
	data, err := json.Marshal(input)
	throw(err)
	return data
}

// Shorthand for unmarshalling JSON
func unmarshalJSON(data []byte, store interface{}) {
	throw(json.Unmarshal(data, store))
}

// copyFile reads a file from disk and copies it into the writer
func copyFile(path string, writer io.Writer) {
	file, err := os.Open(path)
	throw(err)
	defer file.Close()
	_, err = io.Copy(writer, file)
	throw(err)
}

// Shorthand for converting a post ID to a string for JSON keys
func idToString(id uint64) string {
	return strconv.FormatUint(id, 10)
}

// chooseLang selects the language to use in responses to the client, by
// checking the language setting of the request's cookies and verifying it
// against the available selection on the server. Defaults to the server's
// default language.
func chooseLang(req *http.Request) string {
	cookie, err := req.Cookie("lang")
	if err == http.ErrNoCookie { // Only possible error
		return config.Lang.Default
	}
	for _, lang := range config.Lang.Enabled {
		if cookie.Value == lang {
			return lang
		}
	}
	return config.Lang.Default
}

// Log an error with its stack trace
func logError(req *http.Request, err interface{}) {
	const size = 64 << 10
	buf := make([]byte, size)
	buf = buf[:runtime.Stack(buf, false)]
	log.Printf("panic serving %v: %v\n%s", req.RemoteAddr, err, buf)
}
<|endoftext|>


<commit_before>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"bufio"
	"code.google.com/p/min-game/ai"
	"code.google.com/p/min-game/animal"
	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/item"
	"code.google.com/p/min-game/ui"
	"code.google.com/p/min-game/world"
	"encoding/json"
	"io"
	"math/rand"
)

var TileSize = world.TileSize

type Game struct {
	wo         *world.World
	cam        ui.Camera
	base       Base
	Astro      *Player
	Herbivores []animal.Herbivores
	Treasure   []item.Treasure
}

// ReadGame returns a *Game, read from the given
// reader.
func ReadGame(r io.Reader) (*Game, error) {
	g := new(Game)
	in := bufio.NewReader(r)
	var err error
	if g.wo, err = world.Read(in); err != nil {
		return nil, err
	}
	g.cam = ui.Camera{Torus: g.wo.Pixels, Dims: ScreenDims}
	crashSite := geom.Pt(float64(g.wo.X0), float64(g.wo.Y0)).Mul(TileSize)
	g.Astro = NewPlayer(g.wo, crashSite)
	g.base = NewBase(crashSite)

	if err := json.NewDecoder(in).Decode(&g); err != nil {
		panic(err)
	}
	g.CenterOnTile(g.wo.Tile(g.Astro.body.Center()))
	return g, nil
}

func (e *Game) Transparent() bool {
	return false
}

// CenterOnTile centers the display on a given tile.
func (e *Game) CenterOnTile(x, y int) {
	pt := geom.Pt(float64(x), float64(y))
	halfTile := TileSize.Div(geom.Pt(2, 2))
	e.cam.Center(pt.Mul(TileSize).Add(halfTile))
}

func (e *Game) Draw(d ui.Drawer) {
	pt := ScreenDims.Div(TileSize)
	w, h := int(pt.X), int(pt.Y)
	x0, y0 := e.wo.Tile(e.cam.Pt)

	for x := x0; x <= x0+w; x++ {
		for y := y0; y <= y0+h; y++ {
			l := e.wo.At(x, y)
			e.cam.Draw(d, ui.Sprite{
				Name:   l.Terrain.Name,
				Bounds: geom.Rectangle{geom.Pt(0, 0), TileSize},
				Shade:  shade(l),
			}, geom.Pt(float64(x), float64(y)).Mul(TileSize))
		}
	}

	e.base.Draw(d, e.cam)
	for _, t := range e.Treasure {
		if t.Item == nil {
			continue
		}
		e.cam.Draw(d, ui.Sprite{
			Name:   "Present",
			Bounds: geom.Rect(0, 0, t.Box.Dx(), t.Box.Dy()),
			Shade:  shade(e.wo.At(e.wo.Tile(t.Box.Center()))),
		}, t.Box.Min)
	}
	e.Astro.Draw(d, e.cam)
	for i := range e.Herbivores {
		e.Herbivores[i].Draw(d, e.cam)
	}

	e.Astro.drawO2(d)

	if !*debug {
		return
	}
	d.SetFont(DialogFont, 8)
	d.SetColor(White)
	sz := d.TextSize(e.Astro.info)
	d.Draw(e.Astro.info, geom.Pt(0, ScreenDims.Y-sz.Y))
}

// Shade returns the shade value for a location.
func shade(l *world.Loc) float32 {
	const minSh = 0.15
	const slope = (1 - minSh) / world.MaxElevation
	return slope*float32(l.Elevation-l.Depth) + minSh
}

func (ex *Game) Handle(stk *ui.ScreenStack, ev ui.Event) error {
	k, ok := ev.(ui.Key)
	if !ok || !k.Down {
		return nil
	}

	switch k.Button {
	case ui.Menu:
		stk.Push(NewPauseScreen(ex.Astro))
	case ui.Action:
		for i := 0; i < len(ex.Treasure); i++ {
			t := &ex.Treasure[i]
			if !ex.wo.Pixels.Overlaps(ex.Astro.body.Box, t.Box) {
				continue
			}
			scr := NewNormalMessage("You don't have room for that in your pack.")
			if ex.Astro.PutPack(t.Item) {
				scr = NewNormalMessage("Bravo! You got the " + t.Item.Name + "!")
				ex.Treasure[i] = ex.Treasure[len(ex.Treasure)-1]
				ex.Treasure = ex.Treasure[:len(ex.Treasure)-1]
			}
			stk.Push(scr)
			return nil
		}
		if ex.wo.Pixels.Overlaps(ex.Astro.body.Box, ex.base.Box) {
			stk.Push(NewBaseScreen(ex.Astro, &ex.base))
			return nil
		}
	case ui.Hands:
		if ex.Astro.Held != nil {
			dropped := ex.Astro.Held
			ex.Astro.Held = nil
			ex.Treasure = append(ex.Treasure, item.Treasure{dropped, ex.Astro.body.Box})
			break
		}
		for i := 0; i < len(ex.Treasure); i++ {
			t := &ex.Treasure[i]
			if !ex.wo.Pixels.Overlaps(ex.Astro.body.Box, t.Box) {
				continue
			}
			ex.Astro.Held = ex.Treasure[i].Item
			ex.Treasure[i] = ex.Treasure[len(ex.Treasure)-1]
			ex.Treasure = ex.Treasure[:len(ex.Treasure)-1]
			scr := NewNormalMessage("Ahh, you decided to hold onto the " + t.Item.Name + "!")
			stk.Push(scr)
			return nil
		}
	}
	return nil
}

func (e *Game) Update(stk *ui.ScreenStack) error {
	const speed = 4 // px

	if e.Astro.o2 == 0 && !*debug {
		if et := e.Astro.FindEtele(); et == nil {
			stk.Push(NewGameOverScreen())
		} else {
			et.Uses--
			e.Astro.body.Vel = geom.Pt(0, 0)
			dims := geom.Pt(e.Astro.body.Box.Dx(), e.Astro.body.Box.Dy())
			e.Astro.body.Box.Min = e.base.Box.Min
			e.Astro.body.Box.Max = e.base.Box.Min.Add(dims)
			e.Astro.RefillO2()
		}
	}

	e.Astro.body.Vel = geom.Pt(0, 0)
	if stk.Buttons&ui.Left != 0 {
		e.Astro.body.Vel.X -= speed
	}
	if stk.Buttons&ui.Right != 0 {
		e.Astro.body.Vel.X += speed
	}
	if stk.Buttons&ui.Down != 0 {
		e.Astro.body.Vel.Y += speed
	}
	if stk.Buttons&ui.Up != 0 {
		e.Astro.body.Vel.Y -= speed
	}
	e.Astro.Move(e.wo)
	e.cam.Center(e.Astro.body.Box.Center())

	for i := range e.Herbivores {
		ai.UpdateBoids(stk.NFrames, e.Herbivores[i], &e.Astro.body, e.wo)
		e.Herbivores[i].Move(e.wo)
	}

	return nil
}

func randPoint(xmax, ymax float64) geom.Point {
	return geom.Pt(rand.Float64()*xmax, rand.Float64()*ymax)
}
<commit_msg>Drop items where they look like they should go.<commit_after>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"bufio"
	"code.google.com/p/min-game/ai"
	"code.google.com/p/min-game/animal"
	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/item"
	"code.google.com/p/min-game/ui"
	"code.google.com/p/min-game/world"
	"encoding/json"
	"io"
	"math/rand"
)

var TileSize = world.TileSize

type Game struct {
	wo         *world.World
	cam        ui.Camera
	base       Base
	Astro      *Player
	Herbivores []animal.Herbivores
	Treasure   []item.Treasure
}

// ReadGame returns a *Game, read from the given
// reader.
func ReadGame(r io.Reader) (*Game, error) {
	g := new(Game)
	in := bufio.NewReader(r)
	var err error
	if g.wo, err = world.Read(in); err != nil {
		return nil, err
	}
	g.cam = ui.Camera{Torus: g.wo.Pixels, Dims: ScreenDims}
	crashSite := geom.Pt(float64(g.wo.X0), float64(g.wo.Y0)).Mul(TileSize)
	g.Astro = NewPlayer(g.wo, crashSite)
	g.base = NewBase(crashSite)

	if err := json.NewDecoder(in).Decode(&g); err != nil {
		panic(err)
	}
	g.CenterOnTile(g.wo.Tile(g.Astro.body.Center()))
	return g, nil
}

func (e *Game) Transparent() bool {
	return false
}

// CenterOnTile centers the display on a given tile.
func (e *Game) CenterOnTile(x, y int) {
	pt := geom.Pt(float64(x), float64(y))
	halfTile := TileSize.Div(geom.Pt(2, 2))
	e.cam.Center(pt.Mul(TileSize).Add(halfTile))
}

func (e *Game) Draw(d ui.Drawer) {
	pt := ScreenDims.Div(TileSize)
	w, h := int(pt.X), int(pt.Y)
	x0, y0 := e.wo.Tile(e.cam.Pt)

	for x := x0; x <= x0+w; x++ {
		for y := y0; y <= y0+h; y++ {
			l := e.wo.At(x, y)
			e.cam.Draw(d, ui.Sprite{
				Name:   l.Terrain.Name,
				Bounds: geom.Rectangle{geom.Pt(0, 0), TileSize},
				Shade:  shade(l),
			}, geom.Pt(float64(x), float64(y)).Mul(TileSize))
		}
	}

	e.base.Draw(d, e.cam)
	for _, t := range e.Treasure {
		if t.Item == nil {
			continue
		}
		e.cam.Draw(d, ui.Sprite{
			Name:   "Present",
			Bounds: geom.Rect(0, 0, t.Box.Dx(), t.Box.Dy()),
			Shade:  shade(e.wo.At(e.wo.Tile(t.Box.Center()))),
		}, t.Box.Min)
	}
	e.Astro.Draw(d, e.cam)
	for i := range e.Herbivores {
		e.Herbivores[i].Draw(d, e.cam)
	}

	e.Astro.drawO2(d)

	if !*debug {
		return
	}
	d.SetFont(DialogFont, 8)
	d.SetColor(White)
	sz := d.TextSize(e.Astro.info)
	d.Draw(e.Astro.info, geom.Pt(0, ScreenDims.Y-sz.Y))
}

// Shade returns the shade value for a location.
func shade(l *world.Loc) float32 {
	const minSh = 0.15
	const slope = (1 - minSh) / world.MaxElevation
	return slope*float32(l.Elevation-l.Depth) + minSh
}

func (ex *Game) Handle(stk *ui.ScreenStack, ev ui.Event) error {
	k, ok := ev.(ui.Key)
	if !ok || !k.Down {
		return nil
	}

	switch k.Button {
	case ui.Menu:
		stk.Push(NewPauseScreen(ex.Astro))
	case ui.Action:
		for i := 0; i < len(ex.Treasure); i++ {
			t := &ex.Treasure[i]
			if !ex.wo.Pixels.Overlaps(ex.Astro.body.Box, t.Box) {
				continue
			}
			scr := NewNormalMessage("You don't have room for that in your pack.")
			if ex.Astro.PutPack(t.Item) {
				scr = NewNormalMessage("Bravo! You got the " + t.Item.Name + "!")
				ex.Treasure[i] = ex.Treasure[len(ex.Treasure)-1]
				ex.Treasure = ex.Treasure[:len(ex.Treasure)-1]
			}
			stk.Push(scr)
			return nil
		}
		if ex.wo.Pixels.Overlaps(ex.Astro.body.Box, ex.base.Box) {
			stk.Push(NewBaseScreen(ex.Astro, &ex.base))
			return nil
		}
	case ui.Hands:
		if ex.Astro.Held != nil {
			dropped := ex.Astro.Held
			ex.Astro.Held = nil
			pt := ex.Astro.HeldLoc()
			box := geom.Rectangle{pt, pt.Add(TileSize)}
			ex.Treasure = append(ex.Treasure, item.Treasure{dropped, box})
			break
		}
		for i := 0; i < len(ex.Treasure); i++ {
			t := &ex.Treasure[i]
			if !ex.wo.Pixels.Overlaps(ex.Astro.body.Box, t.Box) {
				continue
			}
			ex.Astro.Held = ex.Treasure[i].Item
			ex.Treasure[i] = ex.Treasure[len(ex.Treasure)-1]
			ex.Treasure = ex.Treasure[:len(ex.Treasure)-1]
			scr := NewNormalMessage("Ahh, you decided to hold onto the " + t.Item.Name + "!")
			stk.Push(scr)
			return nil
		}
	}
	return nil
}

func (e *Game) Update(stk *ui.ScreenStack) error {
	const speed = 4 // px

	if e.Astro.o2 == 0 && !*debug {
		if et := e.Astro.FindEtele(); et == nil {
			stk.Push(NewGameOverScreen())
		} else {
			et.Uses--
			e.Astro.body.Vel = geom.Pt(0, 0)
			dims := geom.Pt(e.Astro.body.Box.Dx(), e.Astro.body.Box.Dy())
			e.Astro.body.Box.Min = e.base.Box.Min
			e.Astro.body.Box.Max = e.base.Box.Min.Add(dims)
			e.Astro.RefillO2()
		}
	}

	e.Astro.body.Vel = geom.Pt(0, 0)
	if stk.Buttons&ui.Left != 0 {
		e.Astro.body.Vel.X -= speed
	}
	if stk.Buttons&ui.Right != 0 {
		e.Astro.body.Vel.X += speed
	}
	if stk.Buttons&ui.Down != 0 {
		e.Astro.body.Vel.Y += speed
	}
	if stk.Buttons&ui.Up != 0 {
		e.Astro.body.Vel.Y -= speed
	}
	e.Astro.Move(e.wo)
	e.cam.Center(e.Astro.body.Box.Center())

	for i := range e.Herbivores {
		ai.UpdateBoids(stk.NFrames, e.Herbivores[i], &e.Astro.body, e.wo)
		e.Herbivores[i].Move(e.wo)
	}

	return nil
}

func randPoint(xmax, ymax float64) geom.Point {
	return geom.Pt(rand.Float64()*xmax, rand.Float64()*ymax)
}
<|endoftext|>


<commit_before>package canopus

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestServerInstantiate(t *testing.T) {
	var s *CoapServer
	s = NewCoapServer("localhost:1000")

	assert.NotNil(t, s)
	assert.Equal(t, 1000, s.localAddr.Port)
	assert.Equal(t, "udp", s.localAddr.Network())

	s = NewLocalServer()
	assert.NotNil(t, s)
	assert.Equal(t, 5683, s.localAddr.Port)
	assert.Equal(t, "udp", s.localAddr.Network())
}

//func TestDiscoveryService(t *testing.T) {
//	server := NewCoapServer(":5684")
//	assert.NotNil(t, server)
//	assert.Equal(t, 5684, server.localAddr.Port)
//	assert.Equal(t, "udp", server.localAddr.Network())
//
//	go server.Start()
//	client := NewCoapClient()
//	client.OnStart(func(server *CoapServer) {
//		tok := "abc123"
//		client.Dial("localhost:5684")
//
//		req := NewRequest(TYPE_CONFIRMABLE, GET, GenerateMessageId())
//		req.SetToken(tok)
//		req.SetRequestURI(".well-known/core")
//		resp, err := client.Send(req)
//		assert.Nil(t, err)
//
//		assert.Equal(t, tok, resp.GetMessage().GetTokenString())
//		client.Stop()
//	})
//	client.Start()
//}

//func TestClientServerRequestResponse(t *testing.T) {
//	server := NewLocalServer()
//
//	server.Get("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK GET")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Post("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK POST")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Put("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK PUT")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Delete("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK DELETE")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	go server.Start()
//
//	client := NewCoapClient()
//
//	client.OnStart(func(server *CoapServer) {
//		client.Dial("localhost:5683")
//		token := "tok1234"
//
//		var req CoapRequest
//		var resp CoapResponse
//		var err error
//
//		// 404 Test
//		req = NewConfirmableGetRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep-404")
//		resp, err = client.Send(req)
//		assert.Equal(t, COAPCODE_404_NOT_FOUND, resp.GetMessage().Code)
//
//		// GET
//		req = NewConfirmableGetRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK GET", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// POST
//		req = NewConfirmablePostRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK POST", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// PUT
//		req = NewConfirmablePutRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK PUT", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// DELETE
//		req = NewConfirmableDeleteRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK DELETE", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// Test default token set
//		req = NewConfirmableGetRequest()
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK GET", resp.GetMessage().Payload.String())
//		assert.NotEmpty(t, resp.GetMessage().GetTokenString())
//
//		client.Stop()
//	})
//	client.Start()
//}
<commit_msg>problem with drone.io -- fixing tests<commit_after>package canopus

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestServerInstantiate(t *testing.T) {
	var s *CoapServer
	s = NewCoapServer(":1000")

	assert.NotNil(t, s)
	assert.Equal(t, 1000, s.localAddr.Port)
	assert.Equal(t, "udp", s.localAddr.Network())

	s = NewLocalServer()
	assert.NotNil(t, s)
	assert.Equal(t, 5683, s.localAddr.Port)
	assert.Equal(t, "udp", s.localAddr.Network())
}

//func TestDiscoveryService(t *testing.T) {
//	server := NewCoapServer(":5684")
//	assert.NotNil(t, server)
//	assert.Equal(t, 5684, server.localAddr.Port)
//	assert.Equal(t, "udp", server.localAddr.Network())
//
//	go server.Start()
//	client := NewCoapClient()
//	client.OnStart(func(server *CoapServer) {
//		tok := "abc123"
//		client.Dial("localhost:5684")
//
//		req := NewRequest(TYPE_CONFIRMABLE, GET, GenerateMessageId())
//		req.SetToken(tok)
//		req.SetRequestURI(".well-known/core")
//		resp, err := client.Send(req)
//		assert.Nil(t, err)
//
//		assert.Equal(t, tok, resp.GetMessage().GetTokenString())
//		client.Stop()
//	})
//	client.Start()
//}

//func TestClientServerRequestResponse(t *testing.T) {
//	server := NewLocalServer()
//
//	server.Get("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK GET")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Post("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK POST")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Put("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK PUT")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	server.Delete("/ep", func (req CoapRequest) CoapResponse {
//		msg := ContentMessage(req.GetMessage().MessageId, TYPE_ACKNOWLEDGEMENT)
//		msg.SetStringPayload("ACK DELETE")
//		res := NewResponse(msg, nil)
//
//		return res
//	})
//
//	go server.Start()
//
//	client := NewCoapClient()
//
//	client.OnStart(func(server *CoapServer) {
//		client.Dial("localhost:5683")
//		token := "tok1234"
//
//		var req CoapRequest
//		var resp CoapResponse
//		var err error
//
//		// 404 Test
//		req = NewConfirmableGetRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep-404")
//		resp, err = client.Send(req)
//		assert.Equal(t, COAPCODE_404_NOT_FOUND, resp.GetMessage().Code)
//
//		// GET
//		req = NewConfirmableGetRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK GET", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// POST
//		req = NewConfirmablePostRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK POST", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// PUT
//		req = NewConfirmablePutRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK PUT", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// DELETE
//		req = NewConfirmableDeleteRequest()
//		req.SetToken(token)
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK DELETE", resp.GetMessage().Payload.String())
//		assert.Equal(t, token, resp.GetMessage().GetTokenString())
//
//		// Test default token set
//		req = NewConfirmableGetRequest()
//		req.SetRequestURI("ep")
//		resp, err = client.Send(req)
//
//		assert.Nil(t, err)
//		assert.Equal(t, "ACK GET", resp.GetMessage().Payload.String())
//		assert.NotEmpty(t, resp.GetMessage().GetTokenString())
//
//		client.Stop()
//	})
//	client.Start()
//}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestDeleteKey(t *testing.T) {
	cleanData()
	path := expandPath("foobar")
	content := "foobar"
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", path)
	}
	if err := ioutil.WriteFile(path, []byte(content), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", path, content)
	}
	deleteKey(path)
	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
		t.Error(err)
	}
}

func TestReadKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	if err := os.MkdirAll(filepath.Dir(testPath), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", testPath)
	}
	if err := ioutil.WriteFile(testPath, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPath, testContent)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent)
	}
}

func TestReadKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile1 := expandPath("foo/bar1")
	testPathFile2 := expandPath("foo/bar2")
	testContent := "foobar"
	if err := os.MkdirAll(testPathDirectory, os.ModePerm); err != nil {
		t.Errorf("Could not create directory '%s'\n", testPathDirectory)
	}
	if err := ioutil.WriteFile(testPathFile1, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile1, testContent)
	}
	if err := ioutil.WriteFile(testPathFile2, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile2, testContent)
	}

	entry, err := readKey(testPathDirectory)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Too many/few results given (%+v).", entry.data)
	}
}

func TestHTTPGetKey(t *testing.T) {
	cleanData()
	// Key does not exists
	req, err := http.NewRequest("GET", "http://localhost/foobar", nil)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()
	handler(w, req)
	if w.Code != http.StatusNotFound {
		t.Errorf("Expected Code %i, got %i", http.StatusNotFound, w.Code)
	}

	testFilePath := expandPath("foobar")
	testContent := "foobar"
	if err := os.MkdirAll(filepath.Dir(testFilePath), os.ModePerm); err != nil {
		t.Errorf("Could not create directory '%s'\n", testFilePath)
	}
	if err := ioutil.WriteFile(testFilePath, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s' (%v)\n", testFilePath, testContent, err)
	}

	req, err = http.NewRequest("GET", "http://localhost/foobar", nil)
	if err != nil {
		t.Error(err)
	}
	w = httptest.NewRecorder()
	handler(w, req)
	if w.Code != http.StatusOK {
		t.Errorf("Expected Code %i, got %i", http.StatusNotFound, w.Code)
	}
	expectedBody := "{\"key\":\"foobar\",\"namespace\":false,\"value\":\"foobar\"}\n"
	if w.Body.String() != expectedBody {
		t.Errorf("Expected Body '%s', got '%s'", expectedBody, w.Body.String())
	}
}

func TestCacheUpdatedOnWrite(t *testing.T) {
	cleanData()
	testPath := expandPath("foo/bar/zero")
	testContent1 := "oldContent"
	testContent2 := "newContent"

	err := putKey(testPath, testContent1)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent1 {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent1)
	}

	err = putKey(testPath, testContent2)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent2 {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent2)
	}
}

func TestParentCacheUpdated(t *testing.T) {
	cleanData()
	testPath1 := expandPath("foo/bar/zero")
	testPath2 := expandPath("foo/bar/one")
	testPathParent := expandPath("foo/bar")
	testContent := "foobar"

	err := putKey(testPath1, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 1 {
		t.Errorf("Should have 1 result, got %v.", len(entry.data))
	}

	err = putKey(testPath2, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Should have 2 results, got %v.", len(entry.data))
	}
}

func TestRootParentCacheUpdated(t *testing.T) {
	cleanData()
	testPath1 := expandPath("zero")
	testPath2 := expandPath("one")
	testPathParent := expandPath("/")
	testContent := "foobar"

	err := putKey(testPath1, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 1 {
		t.Errorf("Should have 1 result, got %v.", len(entry.data))
	}

	err = putKey(testPath2, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Should have 2 results, got %v.", len(entry.data))
	}
}

func TestCacheUpdatedOnDelete(t *testing.T) {
	cleanData()
	testPath := expandPath("foo/bar/zero")
	testContent := "testContent"

	err := putKey(testPath, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent)
	}

	err = deleteKey(testPath)
	if err != nil {
		t.Error("Failed to remove key.")
	}

	entry, err = readKey(testPath)
	if err == nil {
		t.Errorf("Entry '%+v' at '%v' should not exist, but does.", entry, testPath)
	}
}

func TestPutKeyCachedWriteUpdatedOnDisk(t *testing.T) {
	cleanData()
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	var mtime time.Time

	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}

	if fileInfo, err := os.Stat(testPathFile); err != nil {
		t.Fail()
	} else {
		mtime = fileInfo.ModTime()
	}

	time.Sleep(time.Millisecond * 1200)

	err = putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}

	if fileInfo, err := os.Stat(testPathFile); err != nil {
		t.Fail()
	} else {
		newMTime := fileInfo.ModTime()
		if newMTime != mtime {
			t.Errorf("File's mtime unncessarily changed from %v to %v.", mtime, newMTime)
		}
	}
}

func cleanData() {
	os.RemoveAll(opts.DataPath)
	skvsCache = make(map[string]Entry)
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	cleanData()
	os.Exit(exit)
}
<commit_msg>additional unit test<commit_after>package main

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestDeleteKey(t *testing.T) {
	cleanData()
	path := expandPath("foobar")
	content := "foobar"
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", path)
	}
	if err := ioutil.WriteFile(path, []byte(content), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", path, content)
	}
	deleteKey(path)
	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
		t.Error(err)
	}
}

func TestReadKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	if err := os.MkdirAll(filepath.Dir(testPath), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", testPath)
	}
	if err := ioutil.WriteFile(testPath, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPath, testContent)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent)
	}
}

func TestReadKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile1 := expandPath("foo/bar1")
	testPathFile2 := expandPath("foo/bar2")
	testContent := "foobar"
	if err := os.MkdirAll(testPathDirectory, os.ModePerm); err != nil {
		t.Errorf("Could not create directory '%s'\n", testPathDirectory)
	}
	if err := ioutil.WriteFile(testPathFile1, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile1, testContent)
	}
	if err := ioutil.WriteFile(testPathFile2, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile2, testContent)
	}

	entry, err := readKey(testPathDirectory)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Too many/few results given (%+v).", entry.data)
	}
}

func TestHTTPGetKey(t *testing.T) {
	cleanData()
	// Key does not exists
	req, err := http.NewRequest("GET", "http://localhost/foobar", nil)
	if err != nil {
		t.Error(err)
	}
	w := httptest.NewRecorder()
	handler(w, req)
	if w.Code != http.StatusNotFound {
		t.Errorf("Expected Code %i, got %i", http.StatusNotFound, w.Code)
	}

	testFilePath := expandPath("foobar")
	testContent := "foobar"
	if err := os.MkdirAll(filepath.Dir(testFilePath), os.ModePerm); err != nil {
		t.Errorf("Could not create directory '%s'\n", testFilePath)
	}
	if err := ioutil.WriteFile(testFilePath, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s' (%v)\n", testFilePath, testContent, err)
	}

	req, err = http.NewRequest("GET", "http://localhost/foobar", nil)
	if err != nil {
		t.Error(err)
	}
	w = httptest.NewRecorder()
	handler(w, req)
	if w.Code != http.StatusOK {
		t.Errorf("Expected Code %i, got %i", http.StatusNotFound, w.Code)
	}
	expectedBody := "{\"key\":\"foobar\",\"namespace\":false,\"value\":\"foobar\"}\n"
	if w.Body.String() != expectedBody {
		t.Errorf("Expected Body '%s', got '%s'", expectedBody, w.Body.String())
	}
}

func TestCacheUpdatedOnWrite(t *testing.T) {
	cleanData()
	testPath := expandPath("foo/bar/zero")
	testContent1 := "oldContent"
	testContent2 := "newContent"

	err := putKey(testPath, testContent1)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent1 {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent1)
	}

	err = putKey(testPath, testContent2)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent2 {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent2)
	}
}

func TestParentCacheUpdated(t *testing.T) {
	cleanData()
	testPath1 := expandPath("foo/bar/zero")
	testPath2 := expandPath("foo/bar/one")
	testPathParent := expandPath("foo/bar")
	testContent := "foobar"

	err := putKey(testPath1, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 1 {
		t.Errorf("Should have 1 result, got %v.", len(entry.data))
	}

	err = putKey(testPath2, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Should have 2 results, got %v.", len(entry.data))
	}
}

func TestParentCacheUpdated2(t *testing.T) {
	cleanData()
	testPath1 := expandPath("foo/bar/zero")
	testPath2 := expandPath("foo/bar/one")
	testPathParent := expandPath("foo/bar")
	testContent := "foobar"

	err := putKey(testPath1, testContent)
	if err != nil {
		t.Error(err)
	}

	err = putKey(testPath2, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Should have 2 result, got %v.", len(entry.data))
	}

	deleteKey(testPath1)

	entry, err = readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 1 {
		t.Errorf("Should have 1 results, got %v.", len(entry.data))
	}
}

func TestRootParentCacheUpdated(t *testing.T) {
	cleanData()
	testPath1 := expandPath("zero")
	testPath2 := expandPath("one")
	testPathParent := expandPath("/")
	testContent := "foobar"

	err := putKey(testPath1, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 1 {
		t.Errorf("Should have 1 result, got %v.", len(entry.data))
	}

	err = putKey(testPath2, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err = readKey(testPathParent)
	if err != nil {
		t.Error(err)
	}
	if !entry.isNamespace {
		t.Error("Is not a namespaced value, but should be.")
	}
	if len(entry.data) != 2 {
		t.Errorf("Should have 2 results, got %v.", len(entry.data))
	}
}

func TestCacheUpdatedOnDelete(t *testing.T) {
	cleanData()
	testPath := expandPath("foo/bar/zero")
	testContent := "testContent"

	err := putKey(testPath, testContent)
	if err != nil {
		t.Error(err)
	}

	entry, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if entry.isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(entry.data) != 1 || entry.data[0] != testContent {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", entry.data, testContent)
	}

	err = deleteKey(testPath)
	if err != nil {
		t.Error("Failed to remove key.")
	}

	entry, err = readKey(testPath)
	if err == nil {
		t.Errorf("Entry '%+v' at '%v' should not exist, but does.", entry, testPath)
	}
}

func TestPutKeyCachedWriteUpdatedOnDisk(t *testing.T) {
	cleanData()
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	var mtime time.Time

	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}

	if fileInfo, err := os.Stat(testPathFile); err != nil {
		t.Fail()
	} else {
		mtime = fileInfo.ModTime()
	}

	time.Sleep(time.Millisecond * 1200)

	err = putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}

	if fileInfo, err := os.Stat(testPathFile); err != nil {
		t.Fail()
	} else {
		newMTime := fileInfo.ModTime()
		if newMTime != mtime {
			t.Errorf("File's mtime unncessarily changed from %v to %v.", mtime, newMTime)
		}
	}
}

func cleanData() {
	os.RemoveAll(opts.DataPath)
	skvsCache = make(map[string]Entry)
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	cleanData()
	os.Exit(exit)
}
<|endoftext|>


<commit_before>package testsrv

import (
	"net/http"
	"testing"
	"time"

	"github.com/arschles/assert"
)

func TestNoMsgs(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
	}))
	recvCh := make(chan []*ReceivedRequest)
	// ensure that it returns after waitTime
	waitTime := 10 * time.Millisecond
	go func() {
		recvCh <- srv.AcceptN(20, waitTime)
	}()
	select {
	case recv := <-recvCh:
		assert.Equal(t, len(recv), 0, "number of received messages")
	case <-time.After(waitTime * 2):
		t.Errorf("AcceptN didn't return after [%+v]", waitTime*2)
	}
}
<commit_msg>closing<commit_after>package testsrv

import (
	"net/http"
	"testing"
	"time"

	"github.com/arschles/assert"
)

func TestNoMsgs(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
	}))
	defer srv.Close()
	recvCh := make(chan []*ReceivedRequest)
	// ensure that it returns after waitTime
	waitTime := 10 * time.Millisecond
	go func() {
		recvCh <- srv.AcceptN(20, waitTime)
	}()
	select {
	case recv := <-recvCh:
		assert.Equal(t, len(recv), 0, "number of received messages")
	case <-time.After(waitTime * 2):
		t.Errorf("AcceptN didn't return after [%+v]", waitTime*2)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/pressly/chi"
	"net/http"
	"os"
	"bufio"
	"fmt"
	"strings"
	"io"
	"time"
	"html/template"
	"io/ioutil"
	"flag"
)

func main() {
	r := chi.NewRouter()
	r.Get("/", showFiles)
	r.Get("/*", showFiles)
	r.Post("/", handlePost)

	port := flag.String("port", "80", "Specifies the port to listen for incoming connections")
	tlsPort := flag.String("tlsPort", "443", "Specifies the port to listen for incoming secure connections")
	tlsCert := flag.String("tlsCert", "cert.pem", "Specifies the port to listen for incoming secure connections")
	tlsKey := flag.String("tlsKey", "key.pem", "Specifies the port to listen for incoming secure connections")

	homeDir := flag.String("dir", "public", "Specifies the root directory which all directories and requests will be stored under")
	flag.Parse()

	err := os.MkdirAll(*homeDir, 0644)
	if err != nil {
		panic("unable to create dir")
	}
	os.Chdir(*homeDir)

	//This will fail silently if the key and cert cant be loaded
	//We should inform the user if this occurs
	go http.ListenAndServeTLS(":" + *tlsPort, *tlsCert, *tlsKey, r)

	http.ListenAndServe(":" + *port, r)
}

func showFiles(w http.ResponseWriter, r *http.Request) {

	t := template.Must(template.New("index").Parse(`{{define "index"}}
		{{range .Files}}
		{{.Name}}

		{{end}}
		{{end}}`))

	path := chi.URLParam(r, "*")

	if info, err := os.Stat("./" + path); err == nil {
		if info.IsDir() {
			files, err := ioutil.ReadDir("./" + path)
			if err != nil {
				panic("Unable to read directory")
			}

			templData := struct {
				Path  string
				Files []os.FileInfo
			}{
				info.Name(),
				files,
			}

			t.Execute(w, templData)
		} else {
			f, _ := ioutil.ReadFile(path)
			w.Write(f)
		}
	} else {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
	}
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	t := time.Now()
	dir := r.URL.Query().Get("dir")
	if dir != "" {
		//Make sure the requested directory is around
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	} else {
		//No directory requested so we give them the default
		dir = t.Format("2006-01-02")
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	}

	//Create file which is named after the create time
	fo, err := os.Create("./" + dir + "/" + t.Format("15.04.05.0000"))
	if err != nil {
		panic(err)
	}
	// close fo on exit and check for its returned error
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	writer := bufio.NewWriter(fo)
	defer writer.Flush()

	//Write headers to file
	for k, v := range r.Header {
		fmt.Fprintln(writer, k + ":", strings.Join(v, ","))
	}

	fmt.Fprintln(writer)
	//Write request body to file
	io.Copy(writer, r.Body)
	w.Write([]byte(fo.Name()[1:]))
}<commit_msg>Added option to turn on listener for https and some logging to better explain what is gobble is doing<commit_after>package main

import (
	"github.com/pressly/chi"
	"net/http"
	"os"
	"bufio"
	"fmt"
	"strings"
	"io"
	"time"
	"html/template"
	"io/ioutil"
	"flag"
	"log"
)

func main() {
	r := chi.NewRouter()
	r.Get("/", showFiles)
	r.Get("/*", showFiles)
	r.Post("/", handlePost)

	port := flag.String("port", "80", "Specifies the port to listen for incoming connections")
	useTls := flag.Bool("tls", false, "Tells gobble to listen for secure connections (ie. https)")
	tlsPort := flag.String("tlsPort", "443", "Specifies the port to listen for incoming secure connections")
	tlsCert := flag.String("tlsCert", "cert.pem", "Specifies the path to the x509 certificate")
	tlsKey := flag.String("tlsKey", "key.pem", "Specifies the path to the private key corresponding to the x509 certificate")

	homeDir := flag.String("dir", "public", "Specifies the root directory which all directories and requests will be stored under")
	flag.Parse()

	err := os.MkdirAll(*homeDir, 0644)
	if err != nil {
		panic("unable to create dir")
	}
	os.Chdir(*homeDir)

	if *useTls == true {
		go func(tlsPort *string, tlsCert *string, tlsKey *string) {
			log.Println("Starting secure server on port " + *tlsPort)
			log.Fatal(http.ListenAndServeTLS(":" + *tlsPort, *tlsCert, *tlsKey, r))
		}(tlsPort, tlsCert, tlsKey)
	}

	log.Println("Starting server on port " + *port)
	log.Fatal(http.ListenAndServe(":" + *port, r))
}

func showFiles(w http.ResponseWriter, r *http.Request) {

	t := template.Must(template.New("index").Parse(`{{define "index"}}
		{{range .Files}}
		{{.Name}}

		{{end}}
		{{end}}`))

	path := chi.URLParam(r, "*")

	if info, err := os.Stat("./" + path); err == nil {
		if info.IsDir() {
			files, err := ioutil.ReadDir("./" + path)
			if err != nil {
				panic("Unable to read directory")
			}

			templData := struct {
				Path  string
				Files []os.FileInfo
			}{
				info.Name(),
				files,
			}

			t.Execute(w, templData)
		} else {
			f, _ := ioutil.ReadFile(path)
			w.Write(f)
		}
	} else {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
	}
}

func handlePost(w http.ResponseWriter, r *http.Request) {
	t := time.Now()
	dir := r.URL.Query().Get("dir")
	if dir != "" {
		//Make sure the requested directory is around
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	} else {
		//No directory requested so we give them the default
		dir = t.Format("2006-01-02")
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	}

	//Create file which is named after the create time
	fo, err := os.Create("./" + dir + "/" + t.Format("15.04.05.0000"))
	if err != nil {
		panic(err)
	}
	// close fo on exit and check for its returned error
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	writer := bufio.NewWriter(fo)
	defer writer.Flush()

	//Write headers to file
	for k, v := range r.Header {
		fmt.Fprintln(writer, k + ":", strings.Join(v, ","))
	}

	fmt.Fprintln(writer)
	//Write request body to file
	io.Copy(writer, r.Body)
	w.Write([]byte(fo.Name()[1:]))
}<|endoftext|>


<commit_before>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "../go-notetxt"
        "flag"
        "os/user"
        "time"
        "strings"
        "strconv"
)

func main() {

        conf, _ := globalconf.New("gonote")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 && !today {
                        fmt.Println("I need something to add.")
                        return
                }

                var text string
                t := time.Now().Local()

                if today {
                        text = fmt.Sprintf("Daily journal, date %s", t.Format("02. 01. 2006"))
                } else {
                        text = strings.Join(args, " ")
                }

                file, err := notetxt.CreateNote(text, t.Format("2006/01/"), dir)
                if err != nil {
                        panic(err);
                }

                notetxt.OpenFileInEditor(file)
            },
        }
        cmdAdd.Flags().BoolVarP(&today, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "ls",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                needle := strings.Join(args, " ")

                for i, note := range notes {
                    if note.Matches(needle) {
                        fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                    }
                }
            },
        }

        var cmdEdit = &cobra.Command{
            Use:   "edit <id>|<selector>",
            Short: "Edit notes.",
            Long:  `Edit a note identified by either an ID or a selector.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 {
                        fmt.Println("Either a note ID or a selector is required.")
                        return
                }

                noteid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Notes matching your selector:\n")
                        cmdList.Run(cmd, args)
                        return
                }

                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                if noteid > len(notes) || noteid < 0 {
                        fmt.Printf("Invalid note ID (%v)\n", noteid)
                        return
                }

                notetxt.OpenFileInEditor(notes[noteid].Filename)

            },
        }

        var cmdTag = &cobra.Command{
            Use:   "tag <noteid> <tag-name>",
            Short: "Attaches a tag to a note.",
            Long:  `Tags a note with a one or more tags.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 2 {
                        fmt.Printf("Too few arguments.")
                }

                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                noteid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                if noteid > len(notes) || noteid < 0 {
                        fmt.Printf("Invalid note ID (%v)\n", noteid)
                        return
                }

                file := notes[noteid].Filename
                tag := args[1]
                err = notetxt.TagNote(file, tag, dir)
                if err != nil {
                        panic(err)
                }

            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonote",
            Short: "gonote is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
                cmdList.Run(cmd, args)
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.AddCommand(cmdTag)
        GonoterCmd.AddCommand(cmdEdit)
        GonoterCmd.Execute()
}
<commit_msg>update: Beter handling of edit command<commit_after>package main

import  (
        "fmt"
        "github.com/spf13/cobra"
        "github.com/rakyll/globalconf"
        "../go-notetxt"
        "flag"
        "os/user"
        "time"
        "strings"
        "strconv"
)

func main() {

        conf, _ := globalconf.New("gonote")

        var flagNotedir = flag.String("dir", "", "Location of the note.txt directory.")
        var dir string

        var today bool

        var cmdAdd = &cobra.Command{
            Use:   "add [title] [tag]",
            Short: "Add a note.",
            Long:  `Add a note and tag it.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 && !today {
                        fmt.Println("I need something to add.")
                        return
                }

                var text string
                t := time.Now().Local()

                if today {
                        text = fmt.Sprintf("Daily journal, date %s", t.Format("02. 01. 2006"))
                } else {
                        text = strings.Join(args, " ")
                }

                file, err := notetxt.CreateNote(text, t.Format("2006/01/"), dir)
                if err != nil {
                        panic(err);
                }

                notetxt.OpenFileInEditor(file)
            },
        }
        cmdAdd.Flags().BoolVarP(&today, "today", "T", false,
                                 "Add today's journal entry.")

        var cmdList = &cobra.Command{
            Use:   "ls",
            Short: "List notes.",
            Long:  `List all valid note files in the directory.`,
            Run: func(cmd *cobra.Command, args []string) {
                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                needle := strings.Join(args, " ")

                for i, note := range notes {
                    if note.Matches(needle) {
                        fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
                    }
                }
            },
        }

        var cmdEdit = &cobra.Command{
            Use:   "edit <id>|<selector>",
            Short: "Edit notes.",
            Long:  `Edit a note identified by either an ID or a selector.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 1 {
                        fmt.Println("Either a note ID or a selector is required.")
                        return
                }

                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                noteid, err := strconv.Atoi(args[0])
                if err != nil {
                        needle := strings.Join(args, " ")
                        filtered_notes := notes.FilterBy(needle)

                        if len(filtered_notes) == 1 {
                                notetxt.OpenFileInEditor(filtered_notes[0].Filename)
                        } else if len (filtered_notes) == 0 {
                                fmt.Printf("No notes matched your selector.")
                        } else {
                                fmt.Printf("Notes matching your selector:\n")
                                filtered_notes.Print()
                        }

                        return
                }

                if noteid > len(notes) || noteid < 0 {
                        fmt.Printf("Invalid note ID (%v)\n", noteid)
                        return
                }

                notetxt.OpenFileInEditor(notes[noteid].Filename)

            },
        }

        var cmdTag = &cobra.Command{
            Use:   "tag <noteid> <tag-name>",
            Short: "Attaches a tag to a note.",
            Long:  `Tags a note with a one or more tags.`,
            Run: func(cmd *cobra.Command, args []string) {
                if len(args) < 2 {
                        fmt.Printf("Too few arguments.")
                }

                notes, err := notetxt.ParseDir(dir)
                if err != nil {
                    panic(err)
                }

                noteid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                if noteid > len(notes) || noteid < 0 {
                        fmt.Printf("Invalid note ID (%v)\n", noteid)
                        return
                }

                file := notes[noteid].Filename
                tag := args[1]
                err = notetxt.TagNote(file, tag, dir)
                if err != nil {
                        panic(err)
                }

            },
        }

        var GonoterCmd = &cobra.Command{
            Use:   "gonote",
            Short: "gonote is a go implementation of note.txt specification.",
            Long: `A small, fast and fun implementation of note.txt`,
            Run: func(cmd *cobra.Command, args []string) {
                cmdList.Run(cmd, args)
            },
        }

        GonoterCmd.PersistentFlags().StringVarP(&dir, "directory", "", "",
                                     "Location of the note.txt directory.")

        conf.ParseAll()
        if dir == "" {
                if *flagNotedir == "" {
                        usr, err := user.Current()
                        if err != nil {
                                panic(err)
                        }

                        dir = usr.HomeDir + "/notes"
                } else {
                        dir = *flagNotedir
                }
        }

        GonoterCmd.AddCommand(cmdAdd)
        GonoterCmd.AddCommand(cmdList)
        GonoterCmd.AddCommand(cmdTag)
        GonoterCmd.AddCommand(cmdEdit)
        GonoterCmd.Execute()
}
<|endoftext|>