<commit_before>package hoverfly

import (
	"encoding/json"
	"fmt"
	"github.com/SpectoLabs/hoverfly/core/cache"
	"github.com/SpectoLabs/hoverfly/core/models"
	"github.com/SpectoLabs/hoverfly/core/testutil"
	"net/http"
	"strings"
	"testing"
)

func TestSetKey(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	k := []byte("randomkeyhere")
	v := []byte("value")

	err := dbClient.RequestCache.Set(k, v)
	testutil.Expect(t, err, nil)

	value, err := dbClient.RequestCache.Get(k)
	testutil.Expect(t, err, nil)
	testutil.Expect(t, string(value), string(v))
}

func TestPayloadSetGet(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	key := []byte("keySetGetCache")
	resp := models.ResponseDetails{
		Status: 200,
		Body:   "body here",
	}

	payload := models.Payload{Response: resp}
	bts, err := json.Marshal(payload)
	testutil.Expect(t, err, nil)

	err = dbClient.RequestCache.Set(key, bts)
	testutil.Expect(t, err, nil)

	var p models.Payload
	payloadBts, err := dbClient.RequestCache.Get(key)
	err = json.Unmarshal(payloadBts, &p)
	testutil.Expect(t, err, nil)
	testutil.Expect(t, payload.Response.Body, p.Response.Body)

	defer dbClient.RequestCache.DeleteData()
}

func TestGetNonExistingBucket(t *testing.T) {
	cache := cache.NewBoltDBCache(TestDB, []byte("somebucket"))

	_, err := cache.Get([]byte("whatever"))
	testutil.Expect(t, err.Error(), "Bucket \"somebucket\" not found!")
}

func TestDeleteBucket(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	k := []byte("randomkeyhere")
	v := []byte("value")
	// checking whether bucket is okay
	err := dbClient.RequestCache.Set(k, v)
	testutil.Expect(t, err, nil)

	value, err := dbClient.RequestCache.Get(k)
	testutil.Expect(t, err, nil)
	testutil.Expect(t, string(value), string(v))

	// deleting bucket
	err = dbClient.RequestCache.DeleteData()
	testutil.Expect(t, err, nil)

	// deleting it again
	err = dbClient.RequestCache.DeleteData()
	testutil.Refute(t, err, nil)
}

func TestGetAllRequestNoBucket(t *testing.T) {
	cache := cache.NewBoltDBCache(TestDB, []byte("somebucket"))

	cache.CurrentBucket = []byte("no_bucket_for_TestGetAllRequestNoBucket")
	_, err := cache.GetAllValues()
	// expecting nil since this would mean that records were wiped
	testutil.Expect(t, err, nil)
}

func TestCorruptedPayloads(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	k := []byte("randomkeyhere")
	v := []byte("value")

	err := dbClient.RequestCache.Set(k, v)
	testutil.Expect(t, err, nil)

	// corrupted payloads should be just skipped
	payloads, err := dbClient.RequestCache.GetAllValues()
	testutil.Expect(t, err, nil)
	testutil.Expect(t, len(payloads), 1)

}

func TestGetMultipleRecords(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com/q=%d", i), nil)
		testutil.Expect(t, err, nil)
		dbClient.captureRequest(req)
	}

	// getting requests
	values, err := dbClient.RequestCache.GetAllValues()
	testutil.Expect(t, err, nil)

	for _, value := range values {
		if payload, err := models.NewPayloadFromBytes(value); err == nil {
			testutil.Expect(t, payload.Request.Method, "GET")
			testutil.Expect(t, payload.Response.Status, 201)
		} else {
			t.Error(err)
		}
	}
}

func TestGetNonExistingKey(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// getting key
	_, err := dbClient.RequestCache.Get([]byte("should not be here"))
	testutil.Refute(t, err, nil)
}

func TestSetGetEmptyValue(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.RequestCache.Set([]byte("shouldbe"), []byte(""))
	testutil.Expect(t, err, nil)
	// getting key
	_, err = dbClient.RequestCache.Get([]byte("shouldbe"))
	testutil.Expect(t, err, nil)
}

func TestGetAllKeys(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		dbClient.RequestCache.Set([]byte(fmt.Sprintf("key%d", i)), []byte("value"))
	}

	keys, err := dbClient.RequestCache.GetAllKeys()
	testutil.Expect(t, err, nil)
	testutil.Expect(t, len(keys), 5)

	for k, v := range keys {
		testutil.Expect(t, strings.HasPrefix(k, "key"), true)
		testutil.Expect(t, v, true)
	}
}

func TestGetAllKeysEmpty(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	keys, err := dbClient.RequestCache.GetAllKeys()
	testutil.Expect(t, err, nil)
	testutil.Expect(t, len(keys), 0)
}
<commit_msg>Cleaning up the db_client_test by replacing testutils with Gomega<commit_after>package hoverfly

import (
	. "github.com/onsi/gomega"
	"encoding/json"
	"fmt"
	"github.com/SpectoLabs/hoverfly/core/cache"
	"github.com/SpectoLabs/hoverfly/core/models"
	"net/http"
	"testing"
)

func TestSetKey(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	k := []byte("randomkeyhere")
	v := []byte("value")

	err := dbClient.RequestCache.Set(k, v)
	Expect(err).To(BeNil())

	value, err := dbClient.RequestCache.Get(k)
	Expect(err).To(BeNil())
	Expect(value).To(Equal(v))
}

func TestPayloadSetGet(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	key := []byte("keySetGetCache")
	resp := models.ResponseDetails{
		Status: 200,
		Body:   "body here",
	}

	payload := models.Payload{Response: resp}
	bts, err := json.Marshal(payload)
	Expect(err).To(BeNil())

	err = dbClient.RequestCache.Set(key, bts)
	Expect(err).To(BeNil())

	var p models.Payload
	payloadBts, err := dbClient.RequestCache.Get(key)
	err = json.Unmarshal(payloadBts, &p)
	Expect(err).To(BeNil())
	Expect(payload.Response.Body).To(Equal(p.Response.Body))

	defer dbClient.RequestCache.DeleteData()
}

func TestGetNonExistingBucket(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewBoltDBCache(TestDB, []byte("somebucket"))

	_, err := cache.Get([]byte("whatever"))
	Expect(err).ToNot(BeNil())
	Expect(err).To(MatchError("Bucket \"somebucket\" not found!"))
}

func TestDeleteBucket(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	k := []byte("randomkeyhere")
	v := []byte("value")
	// checking whether bucket is okay
	err := dbClient.RequestCache.Set(k, v)
	Expect(err).To(BeNil())

	value, err := dbClient.RequestCache.Get(k)
	Expect(err).To(BeNil())
	Expect(value).To(Equal(v))

	// deleting bucket
	err = dbClient.RequestCache.DeleteData()
	Expect(err).To(BeNil())

	// deleting it again
	err = dbClient.RequestCache.DeleteData()
	Expect(err).ToNot(BeNil())
}

func TestGetAllRequestNoBucket(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewBoltDBCache(TestDB, []byte("somebucket"))

	cache.CurrentBucket = []byte("no_bucket_for_TestGetAllRequestNoBucket")
	_, err := cache.GetAllValues()
	// expecting nil since this would mean that records were wiped
	Expect(err).To(BeNil())
}

func TestCorruptedPayloads(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	k := []byte("randomkeyhere")
	v := []byte("value")

	err := dbClient.RequestCache.Set(k, v)
	Expect(err).To(BeNil())

	// corrupted payloads should be just skipped
	payloads, err := dbClient.RequestCache.GetAllValues()
	Expect(err).To(BeNil())
	Expect(payloads).To(HaveLen(1))
}

func TestGetMultipleRecords(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com/q=%d", i), nil)
		Expect(err).To(BeNil())
		dbClient.captureRequest(req)
	}

	// getting requests
	values, err := dbClient.RequestCache.GetAllValues()
	Expect(err).To(BeNil())

	for _, value := range values {
		if payload, err := models.NewPayloadFromBytes(value); err == nil {
			Expect(payload.Request.Method).To(Equal("GET"))
			Expect(payload.Response.Status).To(Equal(201))
		} else {
			t.Error(err)
		}
	}
}

func TestGetNonExistingKey(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// getting key
	_, err := dbClient.RequestCache.Get([]byte("should not be here"))
	Expect(err).ToNot(BeNil())
}

func TestSetGetEmptyValue(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.RequestCache.Set([]byte("shouldbe"), []byte(""))
	Expect(err).To(BeNil())
	// getting key
	_, err = dbClient.RequestCache.Get([]byte("shouldbe"))
	Expect(err).To(BeNil())
}

func TestGetAllKeys(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		dbClient.RequestCache.Set([]byte(fmt.Sprintf("key%d", i)), []byte("value"))
	}

	keys, err := dbClient.RequestCache.GetAllKeys()
	Expect(err).To(BeNil())
	Expect(keys).To(HaveLen(5))

	for k, v := range keys {
		Expect(k).To(HavePrefix("key"))
		Expect(v).To(BeTrue())
	}
}

func TestGetAllKeysEmpty(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	keys, err := dbClient.RequestCache.GetAllKeys()
	Expect(err).To(BeNil())
	Expect(keys).To(HaveLen(0))
}
<|endoftext|>


<commit_before>// Copyright Marc Weistroff
// Copyright Fabien Potencier
// Parts of this code comes from the "Symfony HttpFoundation" source code.
// Use of this source code is governed by a MIT license.
//
// Package cachecontrol provides HTTP Cache-Control header parsing with some
// utility functions to quickly deal with directives values.
package cachecontrol

import (
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var rx = regexp.MustCompile(`([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?`)

// Parse parses the cache directive of a Cache-Control header and returns a CacheControl
func Parse(directive string) CacheControl {
	cc := CacheControl{}
	matches := rx.FindAllString(directive, -1)

	for _, match := range matches {
		var key, value string
		key = match
		if index := strings.Index(match, "="); index != -1 {
			key, value = match[:index], match[index+1:]
		}
		cc[strings.ToLower(key)] = strings.TrimSpace(value)
	}

	return cc
}

// CacheControl holds Cache-Control directives and gives a few utility methods to quickly deal
// with directives values
type CacheControl map[string]string

func (c CacheControl) Public() bool {
	_, ok := c["public"]
	return ok
}

func (c CacheControl) NoStore() bool {
	_, ok := c["no-store"]
	return ok
}

func (c CacheControl) NoTransform() bool {
	_, ok := c["no-transform"]
	return ok
}

func (c CacheControl) OnlyIfCached() bool {
	_, ok := c["only-if-cached"]
	return ok
}

func (c CacheControl) MaxAge() time.Duration {
	return c.timedDirective("max-age")
}

func (c CacheControl) Private() (bool, string) {
	str, ok := c["private"]
	return ok, str
}

func (c CacheControl) NoCache() (bool, string) {
	str, ok := c["no-cache"]
	return ok, str
}

func (c CacheControl) MustRevalidate() bool {
	_, ok := c["must-revalidate"]
	return ok
}

func (c CacheControl) ProxyRevalidate() bool {
	_, ok := c["proxy-revalidate"]
	return ok
}

func (c CacheControl) MinFresh() time.Duration {
	return c.timedDirective("min-fresh")
}

// MaxStale returns -1 if the directive wasn't present or if an error happened
// during parsing the value. It returns math.MaxInt64 if it was present but if
// no value was provided. Otherwise, it returns the provided duration
func (c CacheControl) MaxStale() time.Duration {
	t, ok := c["max-stale"]
	if !ok {
		return -1
	}
	if t == "" {
		return math.MaxInt64
	}

	i, err := strconv.Atoi(t)
	if err != nil {
		return -1
	}
	return time.Duration(i) * time.Second
}

func (c CacheControl) timedDirective(key string) time.Duration {
	t, ok := c[key]
	if !ok {
		return -1
	}

	i, err := strconv.Atoi(t)
	if err != nil {
		return -1
	}
	return time.Duration(i) * time.Second
}
<commit_msg>Fix doc<commit_after>// Copyright Marc Weistroff
// Copyright Fabien Potencier
// Parts of this code comes from the "Symfony HttpFoundation" source code.
// Use of this source code is governed by a MIT license.

// Package cachecontrol provides HTTP Cache-Control header parsing with some
// utility functions to quickly deal with directives values.
package cachecontrol

import (
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var rx = regexp.MustCompile(`([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?`)

// Parse parses the cache directive of a Cache-Control header and returns a CacheControl
func Parse(directive string) CacheControl {
	cc := CacheControl{}
	matches := rx.FindAllString(directive, -1)

	for _, match := range matches {
		var key, value string
		key = match
		if index := strings.Index(match, "="); index != -1 {
			key, value = match[:index], match[index+1:]
		}
		cc[strings.ToLower(key)] = strings.TrimSpace(value)
	}

	return cc
}

// CacheControl holds Cache-Control directives and gives a few utility methods to quickly deal
// with directives values
type CacheControl map[string]string

func (c CacheControl) Public() bool {
	_, ok := c["public"]
	return ok
}

func (c CacheControl) NoStore() bool {
	_, ok := c["no-store"]
	return ok
}

func (c CacheControl) NoTransform() bool {
	_, ok := c["no-transform"]
	return ok
}

func (c CacheControl) OnlyIfCached() bool {
	_, ok := c["only-if-cached"]
	return ok
}

func (c CacheControl) MaxAge() time.Duration {
	return c.timedDirective("max-age")
}

func (c CacheControl) Private() (bool, string) {
	str, ok := c["private"]
	return ok, str
}

func (c CacheControl) NoCache() (bool, string) {
	str, ok := c["no-cache"]
	return ok, str
}

func (c CacheControl) MustRevalidate() bool {
	_, ok := c["must-revalidate"]
	return ok
}

func (c CacheControl) ProxyRevalidate() bool {
	_, ok := c["proxy-revalidate"]
	return ok
}

func (c CacheControl) MinFresh() time.Duration {
	return c.timedDirective("min-fresh")
}

// MaxStale returns -1 if the directive wasn't present or if an error happened
// during parsing the value. It returns math.MaxInt64 if it was present but if
// no value was provided. Otherwise, it returns the provided duration
func (c CacheControl) MaxStale() time.Duration {
	t, ok := c["max-stale"]
	if !ok {
		return -1
	}
	if t == "" {
		return math.MaxInt64
	}

	i, err := strconv.Atoi(t)
	if err != nil {
		return -1
	}
	return time.Duration(i) * time.Second
}

func (c CacheControl) timedDirective(key string) time.Duration {
	t, ok := c[key]
	if !ok {
		return -1
	}

	i, err := strconv.Atoi(t)
	if err != nil {
		return -1
	}
	return time.Duration(i) * time.Second
}
<|endoftext|>


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

package gcp

import (
	"context"
	"errors"
	"fmt"
	"log"
	"strings"
	"sync"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/bson"
	"google.golang.org/api/option"

	// Register uuid.UUID as BSON type.
	_ "github.com/looplab/eventhorizon/types/mongodb"

	eh "github.com/looplab/eventhorizon"
)

// DefaultQueueSize is the default queue size per handler for publishing events.
var DefaultQueueSize = 10

// EventBus is a local event bus that delegates handling of published events
// to all matching registered handlers, in order of registration.
type EventBus struct {
	appID        string
	client       *pubsub.Client
	topic        *pubsub.Topic
	registered   map[eh.EventHandlerType]struct{}
	registeredMu sync.RWMutex
	errCh        chan eh.EventBusError
	wg           sync.WaitGroup
}

// NewEventBus creates an EventBus, with optional GCP connection settings.
func NewEventBus(projectID, appID string, opts ...option.ClientOption) (*EventBus, error) {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID, opts...)
	if err != nil {
		return nil, err
	}

	// Get or create the topic.
	name := appID + "_events"
	topic := client.Topic(name)
	if ok, err := topic.Exists(ctx); err != nil {
		return nil, err
	} else if !ok {
		if topic, err = client.CreateTopic(ctx, name); err != nil {
			return nil, err
		}
	}
	topic.EnableMessageOrdering = true

	return &EventBus{
		appID:      appID,
		client:     client,
		topic:      topic,
		registered: map[eh.EventHandlerType]struct{}{},
		errCh:      make(chan eh.EventBusError, 100),
	}, nil
}

// HandlerType implements the HandlerType method of the eventhorizon.EventHandler interface.
func (b *EventBus) HandlerType() eh.EventHandlerType {
	return "eventbus"
}

const (
	aggregateTypeAttribute = "aggregate_type"
	eventTypeAttribute     = "event_type"
)

// HandleEvent implements the HandleEvent method of the eventhorizon.EventHandler interface.
func (b *EventBus) HandleEvent(ctx context.Context, event eh.Event) error {
	e := evt{
		AggregateID:   event.AggregateID().String(),
		AggregateType: event.AggregateType(),
		EventType:     event.EventType(),
		Version:       event.Version(),
		Timestamp:     event.Timestamp(),
		Context:       eh.MarshalContext(ctx),
	}

	// Marshal event data if there is any.
	if event.Data() != nil {
		var err error
		if e.RawData, err = bson.Marshal(event.Data()); err != nil {
			return errors.New("could not marshal event data: " + err.Error())
		}
	}

	// Marshal the event (using BSON for now).
	data, err := bson.Marshal(e)
	if err != nil {
		return errors.New("could not marshal event: " + err.Error())
	}

	res := b.topic.Publish(ctx, &pubsub.Message{
		Data: data,
		Attributes: map[string]string{
			aggregateTypeAttribute:     event.AggregateType().String(),
			event.EventType().String(): "", // The event type as a key to save space when filtering.
		},
		OrderingKey: event.AggregateID().String(),
	})
	if _, err := res.Get(ctx); err != nil {
		return errors.New("could not publish event: " + err.Error())
	}

	return nil
}

// AddHandler implements the AddHandler method of the eventhorizon.EventBus interface.
func (b *EventBus) AddHandler(ctx context.Context, m eh.EventMatcher, h eh.EventHandler) error {
	if m == nil {
		return eh.ErrMissingMatcher
	}
	if h == nil {
		return eh.ErrMissingHandler
	}

	// Check handler existence.
	b.registeredMu.Lock()
	defer b.registeredMu.Unlock()
	if _, ok := b.registered[h.HandlerType()]; ok {
		return eh.ErrHandlerAlreadyAdded
	}

	// Build the subscription filter.
	filter := createFilter(m)
	if len(filter) >= 256 {
		return fmt.Errorf("match filter is longer than 256 chars: %d", len(filter))
	}

	// Get or create the subscription.
	subscriptionID := b.appID + "_" + h.HandlerType().String()
	sub := b.client.Subscription(subscriptionID)
	if ok, err := sub.Exists(ctx); err != nil {
		return fmt.Errorf("could not check existing subscription: %w", err)
	} else if !ok {
		if sub, err = b.client.CreateSubscription(ctx, subscriptionID,
			pubsub.SubscriptionConfig{
				Topic:                 b.topic,
				Filter:                filter,
				EnableMessageOrdering: true,
			},
		); err != nil {
			return fmt.Errorf("could not create subscription: %w", err)
		}
	} else if ok {
		cfg, err := sub.Config(ctx)
		if err != nil {
			return fmt.Errorf("could not get subscription config: %w", err)
		}
		if cfg.Filter != filter {
			return fmt.Errorf("the existing filter for '%s' differs, please remove to recreate", h.HandlerType())
		}
		if !cfg.EnableMessageOrdering {
			return fmt.Errorf("message ordering not enabled for subscription '%s', please remove to recreate", h.HandlerType())
		}
	}
	// Default is to use 10 goroutines which is often not needed for multiple
	// handlers.
	sub.ReceiveSettings.NumGoroutines = 2

	// Register handler.
	b.registered[h.HandlerType()] = struct{}{}

	// Handle until context is cancelled.
	b.wg.Add(1)
	go b.handle(ctx, m, h, sub)

	return nil
}

// Errors implements the Errors method of the eventhorizon.EventBus interface.
func (b *EventBus) Errors() <-chan eh.EventBusError {
	return b.errCh
}

// Wait for all channels to close in the event bus group
func (b *EventBus) Wait() {
	b.wg.Wait()
}

// Handles all events coming in on the channel.
func (b *EventBus) handle(ctx context.Context, m eh.EventMatcher, h eh.EventHandler, sub *pubsub.Subscription) {
	defer b.wg.Done()

	for {
		if err := sub.Receive(ctx, b.handler(m, h)); err != nil {
			err = fmt.Errorf("could not receive: %w", err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			// Retry the receive loop if there was an error.
			time.Sleep(time.Second)
			continue
		}
		return
	}
}

func (b *EventBus) handler(m eh.EventMatcher, h eh.EventHandler) func(ctx context.Context, msg *pubsub.Message) {
	return func(ctx context.Context, msg *pubsub.Message) {
		// Decode the raw BSON event data.
		var e evt
		if err := bson.Unmarshal(msg.Data, &e); err != nil {
			err = fmt.Errorf("could not unmarshal event: %w", err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			msg.Nack()
			return
		}

		// Create an event of the correct type and decode from raw BSON.
		if len(e.RawData) > 0 {
			var err error
			if e.data, err = eh.CreateEventData(e.EventType); err != nil {
				err = fmt.Errorf("could not create event data: %w", err)
				select {
				case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
				default:
					log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
				}
				msg.Nack()
				return
			}
			if err := bson.Unmarshal(e.RawData, e.data); err != nil {
				err = fmt.Errorf("could not unmarshal event data: %w", err)
				select {
				case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
				default:
					log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
				}
				msg.Nack()
				return
			}
			e.RawData = nil
		}

		event := event{evt: e}
		ctx = eh.UnmarshalContext(ctx, e.Context)

		// Ignore non-matching events.
		if !m.Match(event) {
			msg.Ack()
			return
		}

		// Handle the event if it did match.
		if err := h.HandleEvent(ctx, event); err != nil {
			err = fmt.Errorf("could not handle event (%s): %w", h.HandlerType(), err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx, Event: event}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			msg.Nack()
			return
		}

		msg.Ack()
	}
}

// Creates a filter in the GCP pub sub filter syntax:
// https://cloud.google.com/pubsub/docs/filtering
func createFilter(m eh.EventMatcher) string {
	switch m := m.(type) {
	case eh.MatchEvents:
		s := make([]string, len(m))
		for i, et := range m {
			s[i] = fmt.Sprintf(`attributes:"%s"`, et) // Filter event types by key to save space.
		}
		return strings.Join(s, " OR ")
	case eh.MatchAggregates:
		s := make([]string, len(m))
		for i, at := range m {
			s[i] = fmt.Sprintf(`attributes.%s="%s"`, aggregateTypeAttribute, at)
		}
		return strings.Join(s, " OR ")
	case eh.MatchAny:
		s := make([]string, len(m))
		for i, sm := range m {
			s[i] = fmt.Sprintf("(%s)", createFilter(sm))
		}
		return strings.Join(s, " OR ")
	case eh.MatchAll:
		s := make([]string, len(m))
		for i, sm := range m {
			s[i] = fmt.Sprintf("(%s)", createFilter(sm))
		}
		return strings.Join(s, " AND ")
	default:
		return ""
	}
}

// evt is the internal event used on the wire only.
type evt struct {
	EventType     eh.EventType           `bson:"event_type"`
	RawData       bson.Raw               `bson:"data,omitempty"`
	data          eh.EventData           `bson:"-"`
	Timestamp     time.Time              `bson:"timestamp"`
	AggregateType eh.AggregateType       `bson:"aggregate_type"`
	AggregateID   string                 `bson:"_id"`
	Version       int                    `bson:"version"`
	Context       map[string]interface{} `bson:"context"`
}

// event is the private implementation of the eventhorizon.Event interface
// for a MongoDB event store.
type event struct {
	evt
}

// EventType implements the EventType method of the eventhorizon.Event interface.
func (e event) EventType() eh.EventType {
	return e.evt.EventType
}

// Data implements the Data method of the eventhorizon.Event interface.
func (e event) Data() eh.EventData {
	return e.evt.data
}

// Timestamp implements the Timestamp method of the eventhorizon.Event interface.
func (e event) Timestamp() time.Time {
	return e.evt.Timestamp
}

// AggregateType implements the AggregateType method of the eventhorizon.Event interface.
func (e event) AggregateType() eh.AggregateType {
	return e.evt.AggregateType
}

// AggrgateID implements the AggrgateID method of the eventhorizon.Event interface.
func (e event) AggregateID() uuid.UUID {
	id, err := uuid.Parse(e.evt.AggregateID)
	if err != nil {
		return uuid.Nil
	}
	return id
}

// Version implements the Version method of the eventhorizon.Event interface.
func (e event) Version() int {
	return e.evt.Version
}

// String implements the String method of the eventhorizon.Event interface.
func (e event) String() string {
	return fmt.Sprintf("%s@%d", e.evt.EventType, e.evt.Version)
}
<commit_msg>Tweak GCP pub/sub subscription config<commit_after>// Copyright (c) 2014 - The Event Horizon authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcp

import (
	"context"
	"errors"
	"fmt"
	"log"
	"strings"
	"sync"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/bson"
	"google.golang.org/api/option"

	// Register uuid.UUID as BSON type.
	_ "github.com/looplab/eventhorizon/types/mongodb"

	eh "github.com/looplab/eventhorizon"
)

// EventBus is a local event bus that delegates handling of published events
// to all matching registered handlers, in order of registration.
type EventBus struct {
	appID        string
	client       *pubsub.Client
	topic        *pubsub.Topic
	registered   map[eh.EventHandlerType]struct{}
	registeredMu sync.RWMutex
	errCh        chan eh.EventBusError
	wg           sync.WaitGroup
}

// NewEventBus creates an EventBus, with optional GCP connection settings.
func NewEventBus(projectID, appID string, opts ...option.ClientOption) (*EventBus, error) {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID, opts...)
	if err != nil {
		return nil, err
	}

	// Get or create the topic.
	name := appID + "_events"
	topic := client.Topic(name)
	if ok, err := topic.Exists(ctx); err != nil {
		return nil, err
	} else if !ok {
		if topic, err = client.CreateTopic(ctx, name); err != nil {
			return nil, err
		}
	}
	topic.EnableMessageOrdering = true

	return &EventBus{
		appID:      appID,
		client:     client,
		topic:      topic,
		registered: map[eh.EventHandlerType]struct{}{},
		errCh:      make(chan eh.EventBusError, 100),
	}, nil
}

// HandlerType implements the HandlerType method of the eventhorizon.EventHandler interface.
func (b *EventBus) HandlerType() eh.EventHandlerType {
	return "eventbus"
}

const (
	aggregateTypeAttribute = "aggregate_type"
	eventTypeAttribute     = "event_type"
)

// HandleEvent implements the HandleEvent method of the eventhorizon.EventHandler interface.
func (b *EventBus) HandleEvent(ctx context.Context, event eh.Event) error {
	e := evt{
		AggregateID:   event.AggregateID().String(),
		AggregateType: event.AggregateType(),
		EventType:     event.EventType(),
		Version:       event.Version(),
		Timestamp:     event.Timestamp(),
		Context:       eh.MarshalContext(ctx),
	}

	// Marshal event data if there is any.
	if event.Data() != nil {
		var err error
		if e.RawData, err = bson.Marshal(event.Data()); err != nil {
			return errors.New("could not marshal event data: " + err.Error())
		}
	}

	// Marshal the event (using BSON for now).
	data, err := bson.Marshal(e)
	if err != nil {
		return errors.New("could not marshal event: " + err.Error())
	}

	res := b.topic.Publish(ctx, &pubsub.Message{
		Data: data,
		Attributes: map[string]string{
			aggregateTypeAttribute:     event.AggregateType().String(),
			event.EventType().String(): "", // The event type as a key to save space when filtering.
		},
		OrderingKey: event.AggregateID().String(),
	})
	if _, err := res.Get(ctx); err != nil {
		return errors.New("could not publish event: " + err.Error())
	}

	return nil
}

// AddHandler implements the AddHandler method of the eventhorizon.EventBus interface.
func (b *EventBus) AddHandler(ctx context.Context, m eh.EventMatcher, h eh.EventHandler) error {
	if m == nil {
		return eh.ErrMissingMatcher
	}
	if h == nil {
		return eh.ErrMissingHandler
	}

	// Check handler existence.
	b.registeredMu.Lock()
	defer b.registeredMu.Unlock()
	if _, ok := b.registered[h.HandlerType()]; ok {
		return eh.ErrHandlerAlreadyAdded
	}

	// Build the subscription filter.
	filter := createFilter(m)
	if len(filter) >= 256 {
		return fmt.Errorf("match filter is longer than 256 chars: %d", len(filter))
	}

	// Get or create the subscription.
	subscriptionID := b.appID + "_" + h.HandlerType().String()
	sub := b.client.Subscription(subscriptionID)
	if ok, err := sub.Exists(ctx); err != nil {
		return fmt.Errorf("could not check existing subscription: %w", err)
	} else if !ok {
		if sub, err = b.client.CreateSubscription(ctx, subscriptionID,
			pubsub.SubscriptionConfig{
				Topic:                 b.topic,
				AckDeadline:           60 * time.Second,
				Filter:                filter,
				EnableMessageOrdering: true,
				RetryPolicy: &pubsub.RetryPolicy{
					MinimumBackoff: 3 * time.Second,
				},
			},
		); err != nil {
			return fmt.Errorf("could not create subscription: %w", err)
		}
	} else if ok {
		cfg, err := sub.Config(ctx)
		if err != nil {
			return fmt.Errorf("could not get subscription config: %w", err)
		}
		if cfg.Filter != filter {
			return fmt.Errorf("the existing filter for '%s' differs, please remove to recreate", h.HandlerType())
		}
		if !cfg.EnableMessageOrdering {
			return fmt.Errorf("message ordering not enabled for subscription '%s', please remove to recreate", h.HandlerType())
		}
	}

	// Register handler.
	b.registered[h.HandlerType()] = struct{}{}

	// Handle until context is cancelled.
	b.wg.Add(1)
	go b.handle(ctx, m, h, sub)

	return nil
}

// Errors implements the Errors method of the eventhorizon.EventBus interface.
func (b *EventBus) Errors() <-chan eh.EventBusError {
	return b.errCh
}

// Wait for all channels to close in the event bus group
func (b *EventBus) Wait() {
	b.wg.Wait()
}

// Handles all events coming in on the channel.
func (b *EventBus) handle(ctx context.Context, m eh.EventMatcher, h eh.EventHandler, sub *pubsub.Subscription) {
	defer b.wg.Done()

	for {
		if err := sub.Receive(ctx, b.handler(m, h)); err != nil {
			err = fmt.Errorf("could not receive: %w", err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			// Retry the receive loop if there was an error.
			time.Sleep(time.Second)
			continue
		}
		return
	}
}

func (b *EventBus) handler(m eh.EventMatcher, h eh.EventHandler) func(ctx context.Context, msg *pubsub.Message) {
	return func(ctx context.Context, msg *pubsub.Message) {
		// Decode the raw BSON event data.
		var e evt
		if err := bson.Unmarshal(msg.Data, &e); err != nil {
			err = fmt.Errorf("could not unmarshal event: %w", err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			msg.Nack()
			return
		}

		// Create an event of the correct type and decode from raw BSON.
		if len(e.RawData) > 0 {
			var err error
			if e.data, err = eh.CreateEventData(e.EventType); err != nil {
				err = fmt.Errorf("could not create event data: %w", err)
				select {
				case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
				default:
					log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
				}
				msg.Nack()
				return
			}
			if err := bson.Unmarshal(e.RawData, e.data); err != nil {
				err = fmt.Errorf("could not unmarshal event data: %w", err)
				select {
				case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx}:
				default:
					log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
				}
				msg.Nack()
				return
			}
			e.RawData = nil
		}

		event := event{evt: e}
		ctx = eh.UnmarshalContext(ctx, e.Context)

		// Ignore non-matching events.
		if !m.Match(event) {
			msg.Ack()
			return
		}

		// Handle the event if it did match.
		if err := h.HandleEvent(ctx, event); err != nil {
			err = fmt.Errorf("could not handle event (%s): %w", h.HandlerType(), err)
			select {
			case b.errCh <- eh.EventBusError{Err: err, Ctx: ctx, Event: event}:
			default:
				log.Printf("eventhorizon: missed error in GCP event bus: %s", err)
			}
			msg.Nack()
			return
		}

		msg.Ack()
	}
}

// Creates a filter in the GCP pub sub filter syntax:
// https://cloud.google.com/pubsub/docs/filtering
func createFilter(m eh.EventMatcher) string {
	switch m := m.(type) {
	case eh.MatchEvents:
		s := make([]string, len(m))
		for i, et := range m {
			s[i] = fmt.Sprintf(`attributes:"%s"`, et) // Filter event types by key to save space.
		}
		return strings.Join(s, " OR ")
	case eh.MatchAggregates:
		s := make([]string, len(m))
		for i, at := range m {
			s[i] = fmt.Sprintf(`attributes.%s="%s"`, aggregateTypeAttribute, at)
		}
		return strings.Join(s, " OR ")
	case eh.MatchAny:
		s := make([]string, len(m))
		for i, sm := range m {
			s[i] = fmt.Sprintf("(%s)", createFilter(sm))
		}
		return strings.Join(s, " OR ")
	case eh.MatchAll:
		s := make([]string, len(m))
		for i, sm := range m {
			s[i] = fmt.Sprintf("(%s)", createFilter(sm))
		}
		return strings.Join(s, " AND ")
	default:
		return ""
	}
}

// evt is the internal event used on the wire only.
type evt struct {
	EventType     eh.EventType           `bson:"event_type"`
	RawData       bson.Raw               `bson:"data,omitempty"`
	data          eh.EventData           `bson:"-"`
	Timestamp     time.Time              `bson:"timestamp"`
	AggregateType eh.AggregateType       `bson:"aggregate_type"`
	AggregateID   string                 `bson:"_id"`
	Version       int                    `bson:"version"`
	Context       map[string]interface{} `bson:"context"`
}

// event is the private implementation of the eventhorizon.Event interface
// for a MongoDB event store.
type event struct {
	evt
}

// EventType implements the EventType method of the eventhorizon.Event interface.
func (e event) EventType() eh.EventType {
	return e.evt.EventType
}

// Data implements the Data method of the eventhorizon.Event interface.
func (e event) Data() eh.EventData {
	return e.evt.data
}

// Timestamp implements the Timestamp method of the eventhorizon.Event interface.
func (e event) Timestamp() time.Time {
	return e.evt.Timestamp
}

// AggregateType implements the AggregateType method of the eventhorizon.Event interface.
func (e event) AggregateType() eh.AggregateType {
	return e.evt.AggregateType
}

// AggrgateID implements the AggrgateID method of the eventhorizon.Event interface.
func (e event) AggregateID() uuid.UUID {
	id, err := uuid.Parse(e.evt.AggregateID)
	if err != nil {
		return uuid.Nil
	}
	return id
}

// Version implements the Version method of the eventhorizon.Event interface.
func (e event) Version() int {
	return e.evt.Version
}

// String implements the String method of the eventhorizon.Event interface.
func (e event) String() string {
	return fmt.Sprintf("%s@%d", e.evt.EventType, e.evt.Version)
}
<|endoftext|>


<commit_before>package dummy

import (
	"github.com/tendermint/abci/types"
	cmn "github.com/tendermint/tmlibs/common"
)

// RandVal creates one random validator, with a key derived
// from the input value
func RandVal(i int) types.Validator {
	pubkey := cmn.RandBytes(33)
	power := cmn.RandUint16() + 1
	return types.Validator{pubkey, int64(power)}
}

// RandVals returns a list of cnt validators for initializing
// the application. Note that the keys are deterministically
// derived from the index in the array, while the power is
// random (Change this if not desired)
func RandVals(cnt int) []types.Validator {
	res := make([]types.Validator, cnt)
	for i := 0; i < cnt; i++ {
		res[i] = RandVal(i)
	}
	return res
}

// InitDummy initializes the dummy app with some data,
// which allows tests to pass and is fine as long as you
// don't make any tx that modify the validator state
func InitDummy(app *PersistentDummyApplication) {
	app.InitChain(types.RequestInitChain{
		Validators:    RandVals(1),
		AppStateBytes: []byte("[]"),
	})
}
<commit_msg>Change last instance of AppStateBytes to GenesisBytes<commit_after>package dummy

import (
	"github.com/tendermint/abci/types"
	cmn "github.com/tendermint/tmlibs/common"
)

// RandVal creates one random validator, with a key derived
// from the input value
func RandVal(i int) types.Validator {
	pubkey := cmn.RandBytes(33)
	power := cmn.RandUint16() + 1
	return types.Validator{pubkey, int64(power)}
}

// RandVals returns a list of cnt validators for initializing
// the application. Note that the keys are deterministically
// derived from the index in the array, while the power is
// random (Change this if not desired)
func RandVals(cnt int) []types.Validator {
	res := make([]types.Validator, cnt)
	for i := 0; i < cnt; i++ {
		res[i] = RandVal(i)
	}
	return res
}

// InitDummy initializes the dummy app with some data,
// which allows tests to pass and is fine as long as you
// don't make any tx that modify the validator state
func InitDummy(app *PersistentDummyApplication) {
	app.InitChain(types.RequestInitChain{
		Validators:   RandVals(1),
		GenesisBytes: []byte("[]"),
	})
}
<|endoftext|>


<commit_before>package bitrise

import (
	"fmt"
	"os"
	"path"
	"path/filepath"

	"github.com/bitrise-io/go-utils/pathutil"
)

var (
	// InputEnvstorePath ...
	InputEnvstorePath string
	// OutputEnvstorePath ...
	OutputEnvstorePath string
	// FormattedOutputPath ...
	FormattedOutputPath string
	// BitriseWorkDirPath ...
	BitriseWorkDirPath string
	// BitriseWorkStepsDirPath ...
	BitriseWorkStepsDirPath string
	// CurrentDir ...
	CurrentDir string
)

const (
	// EnvstorePathEnvKey ...
	EnvstorePathEnvKey = "ENVMAN_ENVSTORE_PATH"
	// FormattedOutputPathEnvKey ...
	FormattedOutputPathEnvKey = "BITRISE_STEP_FORMATTED_OUTPUT_FILE_PATH"
	// BitriseSourceDirEnvKey ...
	BitriseSourceDirEnvKey = "BITRISE_SOURCE_DIR"
	// BitriseDeployDirEnvKey ...
	BitriseDeployDirEnvKey = "BITRISE_DEPLOY_DIR"
)

func initBitriseWorkPaths() error {
	bitriseWorkDirPath, err := pathutil.NormalizedOSTempDirPath("bitrise")
	if err != nil {
		return err
	}
	if exist, err := pathutil.IsPathExists(bitriseWorkDirPath); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(bitriseWorkDirPath, 0777); err != nil {
			return err
		}
	}
	BitriseWorkDirPath = bitriseWorkDirPath

	bitriseWorkStepsDirPath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "step_src"))
	if err != nil {
		return err
	}
	if exist, err := pathutil.IsPathExists(bitriseWorkStepsDirPath); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(bitriseWorkStepsDirPath, 0777); err != nil {
			return err
		}
	}
	BitriseWorkStepsDirPath = bitriseWorkStepsDirPath

	return nil
}

// InitPaths ...
func InitPaths() error {
	if err := initBitriseWorkPaths(); err != nil {
		return fmt.Errorf("Failed to init bitrise paths: %s", err)
	}

	inputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "input_envstore.yml"))
	if err != nil {
		return fmt.Errorf("Failed to set envstore path: %s", err)
	}
	InputEnvstorePath = inputEnvstorePath

	outputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "output_envstore.yml"))
	if err != nil {
		return fmt.Errorf("Failed to set envstore path: %s", err)
	}
	OutputEnvstorePath = outputEnvstorePath

	formoutPath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "formatted_output.md"))
	if err != nil {
		return fmt.Errorf("Failed to set formatted output path: %s", err)
	}
	FormattedOutputPath = formoutPath

	currentDir, err := filepath.Abs("./")
	if err != nil {
		return fmt.Errorf("Failed to set current dir: %s", err)
	}
	CurrentDir = currentDir

	// BITRISE_SOURCE_DIR
	if os.Getenv(BitriseSourceDirEnvKey) == "" {
		if err := os.Setenv(BitriseSourceDirEnvKey, currentDir); err != nil {
			return fmt.Errorf("Failed to set BITRISE_SOURCE_DIR: %s", err)
		}
	}

	// BITRISE_DEPLOY_DIR
	if os.Getenv(BitriseDeployDirEnvKey) == "" {
		deployDir, err := pathutil.NormalizedOSTempDirPath("build")
		if err != nil {
			return fmt.Errorf("Failed to set deploy dir: %s", err)
		}

		if err := os.Setenv(BitriseDeployDirEnvKey, deployDir); err != nil {
			return fmt.Errorf("Failed to set BITRISE_DEPLOY_DIR: %s", err)
		}
	}

	return nil
}
<commit_msg>PR fix<commit_after>package bitrise

import (
	"fmt"
	"os"
	"path"
	"path/filepath"

	"github.com/bitrise-io/go-utils/pathutil"
)

var (
	// InputEnvstorePath ...
	InputEnvstorePath string
	// OutputEnvstorePath ...
	OutputEnvstorePath string
	// FormattedOutputPath ...
	FormattedOutputPath string
	// BitriseWorkDirPath ...
	BitriseWorkDirPath string
	// BitriseWorkStepsDirPath ...
	BitriseWorkStepsDirPath string
	// CurrentDir ...
	CurrentDir string
)

const (
	// EnvstorePathEnvKey ...
	EnvstorePathEnvKey = "ENVMAN_ENVSTORE_PATH"
	// FormattedOutputPathEnvKey ...
	FormattedOutputPathEnvKey = "BITRISE_STEP_FORMATTED_OUTPUT_FILE_PATH"
	// BitriseSourceDirEnvKey ...
	BitriseSourceDirEnvKey = "BITRISE_SOURCE_DIR"
	// BitriseDeployDirEnvKey ...
	BitriseDeployDirEnvKey = "BITRISE_DEPLOY_DIR"
)

func initBitriseWorkPaths() error {
	bitriseWorkDirPath, err := pathutil.NormalizedOSTempDirPath("bitrise")
	if err != nil {
		return err
	}
	if exist, err := pathutil.IsPathExists(bitriseWorkDirPath); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(bitriseWorkDirPath, 0777); err != nil {
			return err
		}
	}
	BitriseWorkDirPath = bitriseWorkDirPath

	bitriseWorkStepsDirPath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "step_src"))
	if err != nil {
		return err
	}
	if exist, err := pathutil.IsPathExists(bitriseWorkStepsDirPath); err != nil {
		return err
	} else if !exist {
		if err := os.MkdirAll(bitriseWorkStepsDirPath, 0777); err != nil {
			return err
		}
	}
	BitriseWorkStepsDirPath = bitriseWorkStepsDirPath

	return nil
}

// InitPaths ...
func InitPaths() error {
	if err := initBitriseWorkPaths(); err != nil {
		return fmt.Errorf("Failed to init bitrise paths: %s", err)
	}

	inputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "input_envstore.yml"))
	if err != nil {
		return fmt.Errorf("Failed to set envstore path: %s", err)
	}
	InputEnvstorePath = inputEnvstorePath

	outputEnvstorePath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "output_envstore.yml"))
	if err != nil {
		return fmt.Errorf("Failed to set envstore path: %s", err)
	}
	OutputEnvstorePath = outputEnvstorePath

	formoutPath, err := filepath.Abs(path.Join(BitriseWorkDirPath, "formatted_output.md"))
	if err != nil {
		return fmt.Errorf("Failed to set formatted output path: %s", err)
	}
	FormattedOutputPath = formoutPath

	currentDir, err := filepath.Abs("./")
	if err != nil {
		return fmt.Errorf("Failed to set current dir: %s", err)
	}
	CurrentDir = currentDir

	// BITRISE_SOURCE_DIR
	if os.Getenv(BitriseSourceDirEnvKey) == "" {
		if err := os.Setenv(BitriseSourceDirEnvKey, currentDir); err != nil {
			return fmt.Errorf("Failed to set BITRISE_SOURCE_DIR: %s", err)
		}
	}

	// BITRISE_DEPLOY_DIR
	if os.Getenv(BitriseDeployDirEnvKey) == "" {
		deployDir, err := pathutil.NormalizedOSTempDirPath("deploy")
		if err != nil {
			return fmt.Errorf("Failed to set deploy dir: %s", err)
		}

		if err := os.Setenv(BitriseDeployDirEnvKey, deployDir); err != nil {
			return fmt.Errorf("Failed to set BITRISE_DEPLOY_DIR: %s", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>remove failed should be updated<commit_after><|endoftext|>


<commit_before>package boleto

import (
	"html/template"

	"github.com/mundipagg/boleto-api/models"
)

//ConfigBank configure html template for each bank
type ConfigBank struct {
	Logo         template.HTML
	EspecieDoc   string
	Aceite       string
	Quantidade   string
	ValorCotacao string
	Moeda        string
}

//GetConfig returns boleto configution for each bank
func GetConfig(boleto models.BoletoRequest) ConfigBank {
	switch boleto.BankNumber {
	case models.BancoDoBrasil:
		return configBB(boleto)
	case models.Santander:
		return configSantander(boleto)
	case models.Citibank:
		return configCiti(boleto)
	case models.Bradesco:
		return configBradesco(boleto)
	case models.Caixa:
		return configCaixa(boleto)
	case models.Itau:
		return configItau(boleto)
	case models.Pefisa:
		return configPefisa(boleto)
	default:
		return configBB(boleto)
	}
}

func configCiti(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoCiti), EspecieDoc: "DMI", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configBB(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoBB), EspecieDoc: "DM", Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configCaixa(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoCaixa), EspecieDoc: "OUT", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configSantander(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoSantander), EspecieDoc: "DM", Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configItau(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoItau), EspecieDoc: "DM", Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configPefisa(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoPefisa), EspecieDoc: "DM", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configBradesco(boleto models.BoletoRequest) ConfigBank {
	switch boleto.Agreement.Wallet {
	case 4, 9, 19:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: "DM", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	case 25, 26:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: "Outro", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	default:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: "Outro", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	}
}
<commit_msg>:recycle: Envia ao layout campo Espécie conforme o BoletoType<commit_after>package boleto

import (
	"html/template"

	"github.com/mundipagg/boleto-api/models"
)

//ConfigBank configure html template for each bank
type ConfigBank struct {
	Logo         template.HTML
	EspecieDoc   string
	Aceite       string
	Quantidade   string
	ValorCotacao string
	Moeda        string
}

//GetConfig returns boleto configution for each bank
func GetConfig(boleto models.BoletoRequest) ConfigBank {
	switch boleto.BankNumber {
	case models.BancoDoBrasil:
		return configBB(boleto)
	case models.Santander:
		return configSantander(boleto)
	case models.Citibank:
		return configCiti(boleto)
	case models.Bradesco:
		return configBradesco(boleto)
	case models.Caixa:
		return configCaixa(boleto)
	case models.Itau:
		return configItau(boleto)
	case models.Pefisa:
		return configPefisa(boleto)
	default:
		return configBB(boleto)
	}
}

func configCiti(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoCiti), EspecieDoc: "DMI", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configBB(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoBB), EspecieDoc: "DM", Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configCaixa(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoCaixa), EspecieDoc: "OUT", Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configSantander(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoSantander), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configItau(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoItau), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "N", ValorCotacao: "", Moeda: "R$"}
}

func configPefisa(boleto models.BoletoRequest) ConfigBank {
	return ConfigBank{Logo: template.HTML(LogoPefisa), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "R$"}
}

func configBradesco(boleto models.BoletoRequest) ConfigBank {
	switch boleto.Agreement.Wallet {
	case 4, 9, 19:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	case 25, 26:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	default:
		return ConfigBank{Logo: template.HTML(LogoBradesco), EspecieDoc: boleto.Title.BoletoType, Aceite: "N", Quantidade: "", ValorCotacao: "", Moeda: "Real"}
	}
}
<|endoftext|>


<commit_before>package kinesumer

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	k "github.com/remind101/kinesumer/interface"
)

type ShardWorker struct {
	kinesis                k.Kinesis
	shard                  *kinesis.Shard
	checkpointer           k.Checkpointer
	stream                 string
	pollTime               int
	sequence               string
	stop                   <-chan Unit
	stopped                chan<- Unit
	c                      chan k.Record
	provisioner            k.Provisioner
	errHandler             func(k.Error)
	defaultIteratorType    string
	shardIteratorTimestamp time.Time
	GetRecordsLimit        int64
}

func (s *ShardWorker) GetShardIterator(iteratorType string, sequence string, timestamp time.Time) (string, error) {
	var tmp *string
	if len(sequence) > 0 {
		tmp = &sequence
	}
	iter, err := s.kinesis.GetShardIterator(&kinesis.GetShardIteratorInput{
		ShardId:                s.shard.ShardId,
		ShardIteratorType:      &iteratorType,
		StartingSequenceNumber: tmp,
		StreamName:             &s.stream,
		Timestamp:              &timestamp,
	})
	if err != nil {
		return "", err
	}
	return aws.StringValue(iter.ShardIterator), nil
}

func (s *ShardWorker) TryGetShardIterator(iteratorType string, sequence string, timestamp time.Time) string {
	it, err := s.GetShardIterator(iteratorType, sequence, timestamp)
	if err != nil {
		panic(err)
	}
	return it
}

func (s *ShardWorker) GetRecords(it string) ([]*kinesis.Record, string, int64, error) {
	resp, err := s.kinesis.GetRecords(&kinesis.GetRecordsInput{
		Limit:         &s.GetRecordsLimit,
		ShardIterator: &it,
	})
	if err != nil {
		return nil, "", 0, err
	}
	return resp.Records, aws.StringValue(resp.NextShardIterator), aws.Int64Value(resp.MillisBehindLatest), nil
}

func (s *ShardWorker) GetRecordsAndProcess(it, sequence string) (cont bool, nextIt string, nextSeq string) {
	records, nextIt, lag, err := s.GetRecords(it)
	if err != nil || len(records) == 0 {
		if err != nil {
			s.errHandler(NewError(EWarn, "GetRecords failed", err))
			nextIt = s.TryGetShardIterator("AFTER_SEQUENCE_NUMBER", sequence, time.Time{})
		}

		if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
			s.errHandler(NewError(EError, "Heartbeat failed", err))
			return true, "", sequence
		}
		// GetRecords is not guaranteed to return records even if there are records to be read.
		// However, if our lag time behind the shard head is <= 3 seconds then there's probably
		// no records.
		if lag <= 3000 /* milliseconds */ {
			select {
			case <-time.NewTimer(time.Duration(s.pollTime) * time.Millisecond).C:
			case <-s.stop:
				return true, "", sequence
			}
		}
	} else {
		for _, rec := range records {
			s.c <- &Record{
				data:               rec.Data,
				partitionKey:       aws.StringValue(rec.PartitionKey),
				sequenceNumber:     aws.StringValue(rec.SequenceNumber),
				shardId:            aws.StringValue(s.shard.ShardId),
				millisBehindLatest: lag,
				checkpointC:        s.checkpointer.DoneC(),
			}

			if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
				s.errHandler(NewError(EError, "Heartbeat failed", err))
				return true, "", sequence
			}
		}
		sequence = aws.StringValue(records[len(records)-1].SequenceNumber)
	}
	return false, nextIt, sequence
}

func (s *ShardWorker) RunWorker() {
	defer func() {
		if val := recover(); val != nil {
			msg := fmt.Sprintf("%v", val)
			s.errHandler(NewError(ECrit, msg, nil))
		}
	}()
	defer func() {
		s.provisioner.Release(aws.StringValue(s.shard.ShardId))
		s.stopped <- Unit{}
	}()

	sequence := s.checkpointer.GetStartSequence(aws.StringValue(s.shard.ShardId))
	end := s.shard.SequenceNumberRange.EndingSequenceNumber
	var it string
	if len(sequence) == 0 {
		sequence = aws.StringValue(s.shard.SequenceNumberRange.StartingSequenceNumber)

		s.errHandler(NewError(EWarn, "Using "+s.defaultIteratorType, nil))
		it = s.TryGetShardIterator(s.defaultIteratorType, "", time.Time{})
	} else {
		it = s.TryGetShardIterator("AFTER_SEQUENCE_NUMBER", sequence, time.Time{})
	}

loop:
	for {
		if len(it) == 0 || end != nil && sequence == *end {
			s.errHandler(NewError(EWarn, "Shard has reached its end", nil))
			break loop
		}

		if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
			s.errHandler(NewError(EError, "Heartbeat failed", err))
			break loop
		}

		select {
		case <-s.stop:
			break loop
		default:
			if brk, nextIt, seq := s.GetRecordsAndProcess(it, sequence); brk {
				break loop
			} else {
				it = nextIt
				sequence = seq
			}
		}
	}
}
<commit_msg>Actually reference the shard iterator timestamp<commit_after>package kinesumer

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	k "github.com/remind101/kinesumer/interface"
)

type ShardWorker struct {
	kinesis                k.Kinesis
	shard                  *kinesis.Shard
	checkpointer           k.Checkpointer
	stream                 string
	pollTime               int
	sequence               string
	stop                   <-chan Unit
	stopped                chan<- Unit
	c                      chan k.Record
	provisioner            k.Provisioner
	errHandler             func(k.Error)
	defaultIteratorType    string
	shardIteratorTimestamp time.Time
	GetRecordsLimit        int64
}

func (s *ShardWorker) GetShardIterator(iteratorType string, sequence string, timestamp time.Time) (string, error) {
	var tmp *string
	if len(sequence) > 0 {
		tmp = &sequence
	}
	iter, err := s.kinesis.GetShardIterator(&kinesis.GetShardIteratorInput{
		ShardId:                s.shard.ShardId,
		ShardIteratorType:      &iteratorType,
		StartingSequenceNumber: tmp,
		StreamName:             &s.stream,
		Timestamp:              &timestamp,
	})
	if err != nil {
		return "", err
	}
	return aws.StringValue(iter.ShardIterator), nil
}

func (s *ShardWorker) TryGetShardIterator(iteratorType string, sequence string, timestamp time.Time) string {
	it, err := s.GetShardIterator(iteratorType, sequence, timestamp)
	if err != nil {
		panic(err)
	}
	return it
}

func (s *ShardWorker) GetRecords(it string) ([]*kinesis.Record, string, int64, error) {
	resp, err := s.kinesis.GetRecords(&kinesis.GetRecordsInput{
		Limit:         &s.GetRecordsLimit,
		ShardIterator: &it,
	})
	if err != nil {
		return nil, "", 0, err
	}
	return resp.Records, aws.StringValue(resp.NextShardIterator), aws.Int64Value(resp.MillisBehindLatest), nil
}

func (s *ShardWorker) GetRecordsAndProcess(it, sequence string) (cont bool, nextIt string, nextSeq string) {
	records, nextIt, lag, err := s.GetRecords(it)
	if err != nil || len(records) == 0 {
		if err != nil {
			s.errHandler(NewError(EWarn, "GetRecords failed", err))
			nextIt = s.TryGetShardIterator("AFTER_SEQUENCE_NUMBER", sequence, time.Time{})
		}

		if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
			s.errHandler(NewError(EError, "Heartbeat failed", err))
			return true, "", sequence
		}
		// GetRecords is not guaranteed to return records even if there are records to be read.
		// However, if our lag time behind the shard head is <= 3 seconds then there's probably
		// no records.
		if lag <= 3000 /* milliseconds */ {
			select {
			case <-time.NewTimer(time.Duration(s.pollTime) * time.Millisecond).C:
			case <-s.stop:
				return true, "", sequence
			}
		}
	} else {
		for _, rec := range records {
			s.c <- &Record{
				data:               rec.Data,
				partitionKey:       aws.StringValue(rec.PartitionKey),
				sequenceNumber:     aws.StringValue(rec.SequenceNumber),
				shardId:            aws.StringValue(s.shard.ShardId),
				millisBehindLatest: lag,
				checkpointC:        s.checkpointer.DoneC(),
			}

			if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
				s.errHandler(NewError(EError, "Heartbeat failed", err))
				return true, "", sequence
			}
		}
		sequence = aws.StringValue(records[len(records)-1].SequenceNumber)
	}
	return false, nextIt, sequence
}

func (s *ShardWorker) RunWorker() {
	defer func() {
		if val := recover(); val != nil {
			msg := fmt.Sprintf("%v", val)
			s.errHandler(NewError(ECrit, msg, nil))
		}
	}()
	defer func() {
		s.provisioner.Release(aws.StringValue(s.shard.ShardId))
		s.stopped <- Unit{}
	}()

	sequence := s.checkpointer.GetStartSequence(aws.StringValue(s.shard.ShardId))
	end := s.shard.SequenceNumberRange.EndingSequenceNumber
	var it string
	if len(sequence) == 0 {
		sequence = aws.StringValue(s.shard.SequenceNumberRange.StartingSequenceNumber)

		s.errHandler(NewError(EWarn, "Using "+s.defaultIteratorType, nil))
		it = s.TryGetShardIterator(s.defaultIteratorType, "", s.shardIteratorTimestamp)
	} else {
		it = s.TryGetShardIterator("AFTER_SEQUENCE_NUMBER", sequence, time.Time{})
	}

loop:
	for {
		if len(it) == 0 || end != nil && sequence == *end {
			s.errHandler(NewError(EWarn, "Shard has reached its end", nil))
			break loop
		}

		if err := s.provisioner.Heartbeat(aws.StringValue(s.shard.ShardId)); err != nil {
			s.errHandler(NewError(EError, "Heartbeat failed", err))
			break loop
		}

		select {
		case <-s.stop:
			break loop
		default:
			if brk, nextIt, seq := s.GetRecordsAndProcess(it, sequence); brk {
				break loop
			} else {
				it = nextIt
				sequence = seq
			}
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>allow patching of volumes.<commit_after><|endoftext|>


<commit_before>package helpers

import "reflect"

// Checks if the slice $s contains $e
func SliceContains(s []interface{}, e interface{}) bool {
    for _, a := range s {
        if reflect.DeepEqual(a, e) {
            return true
        }
    }

    return false
}
<commit_msg>Add collection helpers<commit_after>package helpers

import (
    "reflect"
    "errors"
)

func interfaceToSlice(input interface{}) []interface{} {
    r := reflect.ValueOf(input)

    if r.Kind() != reflect.Slice {
        panic(errors.New("Passed arg is not a slice"))
    }

    c := r.Len()
    s := make([]interface{}, c)

    for i := 0; i < c; i++ {
        s[i] = r.Index(i).Interface()
    }

    return s
}

func SliceRemoveOrderedElement(input interface{}, idx int) []interface{} {
    array := interfaceToSlice(input)
    return append(array[:idx], array[idx + 1:]...)
}

func SliceRemoveElement(input interface{}, idx int) []interface{} {
    array := interfaceToSlice(input)
    array[len(array) - 1], array[idx] = array[idx], array[len(array) - 1]
    return array[:len(array) - 1]
}
<|endoftext|>


<commit_before><commit_msg>Added tests for b3037cdb2302da8579ffd0d663f553bfb476840e.<commit_after><|endoftext|>


<commit_before>package shell

import (
	"flag"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
	"github.com/chrislusf/seaweedfs/weed/s3iam"
)

func init() {
	Commands = append(Commands, &commandS3Configure{})
}

type commandS3Configure struct {
}

func (c *commandS3Configure) Name() string {
	return "s3.configure"
}

func (c *commandS3Configure) Help() string {
	return `configure and apply s3 options for each bucket
	# see the current configuration file content
	s3.configure
	`
}

func (c *commandS3Configure) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
	s3ConfigureCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	actions := s3ConfigureCommand.String("actions", "", "actions names")
	user := s3ConfigureCommand.String("user", "", "user name")
	buckets := s3ConfigureCommand.String("buckets", "", "bucket name")
	accessKey := s3ConfigureCommand.String("access_key", "", "specify the access key")
	secretKey := s3ConfigureCommand.String("secret_key", "", "specify the secret key")
	isDelete := s3ConfigureCommand.Bool("delete", false, "delete users, actions or access keys")
	apply := s3ConfigureCommand.Bool("apply", false, "update and apply s3 configuration")

	if err = s3ConfigureCommand.Parse(args); err != nil {
		return nil
	}

	s3cfg := &iam_pb.S3ApiConfiguration{}
	ifs := &s3iam.IAMFilerStore{}
	if err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
		ifs = s3iam.NewIAMFilerStore(&client)
		if err := ifs.LoadIAMConfig(s3cfg); err != nil {
			return nil
		}
		return nil
	}); err != nil {
		return err
	}

	idx := 0
	changed := false
	if *user != "" && *buckets != "" {
		for i, identity := range s3cfg.Identities {
			if *user == identity.Name {
				idx = i
				changed = true
				break
			}
		}
	}
	var cmdActions []string
	for _, bucket := range strings.Split(*buckets, ",") {
		for _, action := range strings.Split(*actions, ",") {
			cmdActions = append(cmdActions, fmt.Sprintf("%s:%s", action, bucket))
		}
	}
	if changed {
		if *isDelete {
			var exists []int
			for _, cmdAction := range cmdActions {
				for i, currentAction := range s3cfg.Identities[idx].Actions {
					if cmdAction == currentAction {
						exists = append(exists, i)
					}
				}
			}
			sort.Sort(sort.Reverse(sort.IntSlice(exists)))
			for _, i := range exists {
				s3cfg.Identities[idx].Actions = append(
					s3cfg.Identities[idx].Actions[:i],
					s3cfg.Identities[idx].Actions[i+1:]...,
				)
			}
			if *accessKey != "" {
				exists = []int{}
				for i, credential := range s3cfg.Identities[idx].Credentials {
					if credential.AccessKey == *accessKey {
						exists = append(exists, i)
					}
				}
				sort.Sort(sort.Reverse(sort.IntSlice(exists)))
				for _, i := range exists {
					s3cfg.Identities[idx].Credentials = append(
						s3cfg.Identities[idx].Credentials[:i],
						s3cfg.Identities[idx].Credentials[:i+1]...,
					)
				}

			}
			if *actions == "" && *accessKey == "" {
				s3cfg.Identities = append(s3cfg.Identities[:idx], s3cfg.Identities[idx+1:]...)
			}
		} else {
			s3cfg.Identities[idx].Actions = append(s3cfg.Identities[idx].Actions, cmdActions...)
			s3cfg.Identities[idx].Credentials = append(s3cfg.Identities[idx].Credentials, &iam_pb.Credential{
				AccessKey: *accessKey,
				SecretKey: *secretKey,
			})
		}
	} else {
		identity := iam_pb.Identity{
			Name:    *user,
			Actions: cmdActions,
		}
		identity.Credentials = append(identity.Credentials, &iam_pb.Credential{
			AccessKey: *accessKey,
			SecretKey: *secretKey,
		})
		s3cfg.Identities = append(s3cfg.Identities, &identity)
	}

	fmt.Fprintf(writer, fmt.Sprintf("%+v\n", s3cfg.Identities))
	fmt.Fprintln(writer)

	if *apply {
		if err := ifs.SaveIAMConfig(s3cfg); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>s3 config changes<commit_after>package shell

import (
	"flag"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
	"github.com/chrislusf/seaweedfs/weed/s3iam"
)

func init() {
	Commands = append(Commands, &commandS3Configure{})
}

type commandS3Configure struct {
}

func (c *commandS3Configure) Name() string {
	return "s3.configure"
}

func (c *commandS3Configure) Help() string {
	return `configure and apply s3 options for each bucket
	# see the current configuration file content
	s3.configure
	`
}

func (c *commandS3Configure) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
	s3ConfigureCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	actions := s3ConfigureCommand.String("actions", "", "actions names")
	user := s3ConfigureCommand.String("user", "", "user name")
	buckets := s3ConfigureCommand.String("buckets", "", "bucket name")
	accessKey := s3ConfigureCommand.String("access_key", "", "specify the access key")
	secretKey := s3ConfigureCommand.String("secret_key", "", "specify the secret key")
	isDelete := s3ConfigureCommand.Bool("delete", false, "delete users, actions or access keys")
	apply := s3ConfigureCommand.Bool("apply", false, "update and apply s3 configuration")

	if err = s3ConfigureCommand.Parse(args); err != nil {
		return nil
	}

	s3cfg := &iam_pb.S3ApiConfiguration{}
	ifs := &s3iam.IAMFilerStore{}
	if err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
		ifs = s3iam.NewIAMFilerStore(&client)
		if err := ifs.LoadIAMConfig(s3cfg); err != nil {
			return nil
		}
		return nil
	}); err != nil {
		return err
	}

	idx := 0
	changed := false
	if *user != "" {
		for i, identity := range s3cfg.Identities {
			if *user == identity.Name {
				idx = i
				changed = true
				break
			}
		}
	}
	var cmdActions []string
	for _, action := range strings.Split(*actions, ",") {
		if *buckets == "" {
			cmdActions = append(cmdActions, action)
		} else {
			for _, bucket := range strings.Split(*buckets, ",") {
				cmdActions = append(cmdActions, fmt.Sprintf("%s:%s", action, bucket))
			}
		}
	}
	if changed {
		if *isDelete {
			var exists []int
			for _, cmdAction := range cmdActions {
				for i, currentAction := range s3cfg.Identities[idx].Actions {
					if cmdAction == currentAction {
						exists = append(exists, i)
					}
				}
			}
			sort.Sort(sort.Reverse(sort.IntSlice(exists)))
			for _, i := range exists {
				s3cfg.Identities[idx].Actions = append(
					s3cfg.Identities[idx].Actions[:i],
					s3cfg.Identities[idx].Actions[i+1:]...,
				)
			}
			if *accessKey != "" {
				exists = []int{}
				for i, credential := range s3cfg.Identities[idx].Credentials {
					if credential.AccessKey == *accessKey {
						exists = append(exists, i)
					}
				}
				sort.Sort(sort.Reverse(sort.IntSlice(exists)))
				for _, i := range exists {
					s3cfg.Identities[idx].Credentials = append(
						s3cfg.Identities[idx].Credentials[:i],
						s3cfg.Identities[idx].Credentials[:i+1]...,
					)
				}

			}
			if *actions == "" && *accessKey == "" && *buckets == "" {
				s3cfg.Identities = append(s3cfg.Identities[:idx], s3cfg.Identities[idx+1:]...)
			}
		} else {
			if *actions != "" {
				for _, cmdAction := range cmdActions {
					found := false
					for _, action := range s3cfg.Identities[idx].Actions {
						if cmdAction == action {
							found = true
							break
						}
					}
					if !found {
						s3cfg.Identities[idx].Actions = append(s3cfg.Identities[idx].Actions, cmdAction)
					}
				}
			}
			if *accessKey != "" && *user != "anonymous" {
				found := false
				for _, credential := range s3cfg.Identities[idx].Credentials {
					if credential.AccessKey == *accessKey {
						found = true
						credential.SecretKey = *secretKey
						break
					}
				}
				if !found {
					s3cfg.Identities[idx].Credentials = append(s3cfg.Identities[idx].Credentials, &iam_pb.Credential{
						AccessKey: *accessKey,
						SecretKey: *secretKey,
					})
				}
			}
		}
	} else if *user != "" && *actions != "" {
		identity := iam_pb.Identity{
			Name:        *user,
			Actions:     cmdActions,
			Credentials: []*iam_pb.Credential{},
		}
		if *user != "anonymous" {
			identity.Credentials = append(identity.Credentials,
				&iam_pb.Credential{AccessKey: *accessKey, SecretKey: *secretKey})
		}
		s3cfg.Identities = append(s3cfg.Identities, &identity)
	}

	for _, identity := range s3cfg.Identities {
		fmt.Fprintf(writer, fmt.Sprintf("%+v\n", identity))
	}

	fmt.Fprintln(writer)

	if *apply {
		if err := ifs.SaveIAMConfig(s3cfg); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package storage

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/opt"

	"github.com/chrislusf/seaweedfs/weed/storage/idx"

	"github.com/syndtr/goleveldb/leveldb"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage/needle_map"
	. "github.com/chrislusf/seaweedfs/weed/storage/types"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type LevelDbNeedleMap struct {
	baseNeedleMapper
	dbFileName string
	db         *leveldb.DB
}

func NewLevelDbNeedleMap(dbFileName string, indexFile *os.File, opts *opt.Options) (m *LevelDbNeedleMap, err error) {
	m = &LevelDbNeedleMap{dbFileName: dbFileName}
	m.indexFile = indexFile
	if !isLevelDbFresh(dbFileName, indexFile) {
		glog.V(0).Infof("Start to Generate %s from %s", dbFileName, indexFile.Name())
		generateLevelDbFile(dbFileName, indexFile)
		glog.V(0).Infof("Finished Generating %s from %s", dbFileName, indexFile.Name())
	}
	glog.V(1).Infof("Opening %s...", dbFileName)

	if m.db, err = leveldb.OpenFile(dbFileName, opts); err != nil {
		if errors.IsCorrupted(err) {
			m.db, err = leveldb.RecoverFile(dbFileName, opts)
		}
		if err != nil {
			return
		}
	}
	glog.V(1).Infof("Loading %s...", indexFile.Name())
	mm, indexLoadError := newNeedleMapMetricFromIndexFile(indexFile)
	if indexLoadError != nil {
		return nil, indexLoadError
	}
	m.mapMetric = *mm
	return
}

func isLevelDbFresh(dbFileName string, indexFile *os.File) bool {
	// normally we always write to index file first
	dbLogFile, err := os.Open(filepath.Join(dbFileName, "LOG"))
	if err != nil {
		return false
	}
	defer dbLogFile.Close()
	dbStat, dbStatErr := dbLogFile.Stat()
	indexStat, indexStatErr := indexFile.Stat()
	if dbStatErr != nil || indexStatErr != nil {
		glog.V(0).Infof("Can not stat file: %v and %v", dbStatErr, indexStatErr)
		return false
	}

	return dbStat.ModTime().After(indexStat.ModTime())
}

func generateLevelDbFile(dbFileName string, indexFile *os.File) error {
	db, err := leveldb.OpenFile(dbFileName, nil)
	if err != nil {
		return err
	}
	defer db.Close()
	return idx.WalkIndexFile(indexFile, func(key NeedleId, offset Offset, size uint32) error {
		if !offset.IsZero() && size != TombstoneFileSize {
			levelDbWrite(db, key, offset, size)
		} else {
			levelDbDelete(db, key)
		}
		return nil
	})
}

func (m *LevelDbNeedleMap) Get(key NeedleId) (element *needle_map.NeedleValue, ok bool) {
	bytes := make([]byte, NeedleIdSize)
	NeedleIdToBytes(bytes[0:NeedleIdSize], key)
	data, err := m.db.Get(bytes, nil)
	if err != nil || len(data) != OffsetSize+SizeSize {
		return nil, false
	}
	offset := BytesToOffset(data[0:OffsetSize])
	size := util.BytesToUint32(data[OffsetSize : OffsetSize+SizeSize])
	return &needle_map.NeedleValue{Key: key, Offset: offset, Size: size}, true
}

func (m *LevelDbNeedleMap) Put(key NeedleId, offset Offset, size uint32) error {
	var oldSize uint32
	if oldNeedle, ok := m.Get(key); ok {
		oldSize = oldNeedle.Size
	}
	m.logPut(key, oldSize, size)
	// write to index file first
	if err := m.appendToIndexFile(key, offset, size); err != nil {
		return fmt.Errorf("cannot write to indexfile %s: %v", m.indexFile.Name(), err)
	}
	return levelDbWrite(m.db, key, offset, size)
}

func levelDbWrite(db *leveldb.DB, key NeedleId, offset Offset, size uint32) error {

	bytes := needle_map.ToBytes(key, offset, size)

	if err := db.Put(bytes[0:NeedleIdSize], bytes[NeedleIdSize:NeedleIdSize+OffsetSize+SizeSize], nil); err != nil {
		return fmt.Errorf("failed to write leveldb: %v", err)
	}
	return nil
}
func levelDbDelete(db *leveldb.DB, key NeedleId) error {
	bytes := make([]byte, NeedleIdSize)
	NeedleIdToBytes(bytes, key)
	return db.Delete(bytes, nil)
}

func (m *LevelDbNeedleMap) Delete(key NeedleId, offset Offset) error {
	if oldNeedle, ok := m.Get(key); ok {
		m.logDelete(oldNeedle.Size)
	}
	// write to index file first
	if err := m.appendToIndexFile(key, offset, TombstoneFileSize); err != nil {
		return err
	}
	return levelDbDelete(m.db, key)
}

func (m *LevelDbNeedleMap) Close() {
	indexFileName := m.indexFile.Name()
	if err := m.indexFile.Sync(); err != nil {
		glog.Warningf("sync file %s failed: %v", indexFileName, err)
	}
	if err := m.indexFile.Close(); err != nil {
		glog.Warningf("close index file %s failed: %v", indexFileName, err)
	}

	if err := m.db.Close(); err != nil {
		glog.Warningf("close levelDB failed: %v", err)
	}
}

func (m *LevelDbNeedleMap) Destroy() error {
	m.Close()
	os.Remove(m.indexFile.Name())
	return os.RemoveAll(m.dbFileName)
}
<commit_msg>adjust log level<commit_after>package storage

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/opt"

	"github.com/chrislusf/seaweedfs/weed/storage/idx"

	"github.com/syndtr/goleveldb/leveldb"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/storage/needle_map"
	. "github.com/chrislusf/seaweedfs/weed/storage/types"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type LevelDbNeedleMap struct {
	baseNeedleMapper
	dbFileName string
	db         *leveldb.DB
}

func NewLevelDbNeedleMap(dbFileName string, indexFile *os.File, opts *opt.Options) (m *LevelDbNeedleMap, err error) {
	m = &LevelDbNeedleMap{dbFileName: dbFileName}
	m.indexFile = indexFile
	if !isLevelDbFresh(dbFileName, indexFile) {
		glog.V(1).Infof("Start to Generate %s from %s", dbFileName, indexFile.Name())
		generateLevelDbFile(dbFileName, indexFile)
		glog.V(1).Infof("Finished Generating %s from %s", dbFileName, indexFile.Name())
	}
	glog.V(1).Infof("Opening %s...", dbFileName)

	if m.db, err = leveldb.OpenFile(dbFileName, opts); err != nil {
		if errors.IsCorrupted(err) {
			m.db, err = leveldb.RecoverFile(dbFileName, opts)
		}
		if err != nil {
			return
		}
	}
	glog.V(1).Infof("Loading %s...", indexFile.Name())
	mm, indexLoadError := newNeedleMapMetricFromIndexFile(indexFile)
	if indexLoadError != nil {
		return nil, indexLoadError
	}
	m.mapMetric = *mm
	return
}

func isLevelDbFresh(dbFileName string, indexFile *os.File) bool {
	// normally we always write to index file first
	dbLogFile, err := os.Open(filepath.Join(dbFileName, "LOG"))
	if err != nil {
		return false
	}
	defer dbLogFile.Close()
	dbStat, dbStatErr := dbLogFile.Stat()
	indexStat, indexStatErr := indexFile.Stat()
	if dbStatErr != nil || indexStatErr != nil {
		glog.V(0).Infof("Can not stat file: %v and %v", dbStatErr, indexStatErr)
		return false
	}

	return dbStat.ModTime().After(indexStat.ModTime())
}

func generateLevelDbFile(dbFileName string, indexFile *os.File) error {
	db, err := leveldb.OpenFile(dbFileName, nil)
	if err != nil {
		return err
	}
	defer db.Close()
	return idx.WalkIndexFile(indexFile, func(key NeedleId, offset Offset, size uint32) error {
		if !offset.IsZero() && size != TombstoneFileSize {
			levelDbWrite(db, key, offset, size)
		} else {
			levelDbDelete(db, key)
		}
		return nil
	})
}

func (m *LevelDbNeedleMap) Get(key NeedleId) (element *needle_map.NeedleValue, ok bool) {
	bytes := make([]byte, NeedleIdSize)
	NeedleIdToBytes(bytes[0:NeedleIdSize], key)
	data, err := m.db.Get(bytes, nil)
	if err != nil || len(data) != OffsetSize+SizeSize {
		return nil, false
	}
	offset := BytesToOffset(data[0:OffsetSize])
	size := util.BytesToUint32(data[OffsetSize : OffsetSize+SizeSize])
	return &needle_map.NeedleValue{Key: key, Offset: offset, Size: size}, true
}

func (m *LevelDbNeedleMap) Put(key NeedleId, offset Offset, size uint32) error {
	var oldSize uint32
	if oldNeedle, ok := m.Get(key); ok {
		oldSize = oldNeedle.Size
	}
	m.logPut(key, oldSize, size)
	// write to index file first
	if err := m.appendToIndexFile(key, offset, size); err != nil {
		return fmt.Errorf("cannot write to indexfile %s: %v", m.indexFile.Name(), err)
	}
	return levelDbWrite(m.db, key, offset, size)
}

func levelDbWrite(db *leveldb.DB, key NeedleId, offset Offset, size uint32) error {

	bytes := needle_map.ToBytes(key, offset, size)

	if err := db.Put(bytes[0:NeedleIdSize], bytes[NeedleIdSize:NeedleIdSize+OffsetSize+SizeSize], nil); err != nil {
		return fmt.Errorf("failed to write leveldb: %v", err)
	}
	return nil
}
func levelDbDelete(db *leveldb.DB, key NeedleId) error {
	bytes := make([]byte, NeedleIdSize)
	NeedleIdToBytes(bytes, key)
	return db.Delete(bytes, nil)
}

func (m *LevelDbNeedleMap) Delete(key NeedleId, offset Offset) error {
	if oldNeedle, ok := m.Get(key); ok {
		m.logDelete(oldNeedle.Size)
	}
	// write to index file first
	if err := m.appendToIndexFile(key, offset, TombstoneFileSize); err != nil {
		return err
	}
	return levelDbDelete(m.db, key)
}

func (m *LevelDbNeedleMap) Close() {
	indexFileName := m.indexFile.Name()
	if err := m.indexFile.Sync(); err != nil {
		glog.Warningf("sync file %s failed: %v", indexFileName, err)
	}
	if err := m.indexFile.Close(); err != nil {
		glog.Warningf("close index file %s failed: %v", indexFileName, err)
	}

	if err := m.db.Close(); err != nil {
		glog.Warningf("close levelDB failed: %v", err)
	}
}

func (m *LevelDbNeedleMap) Destroy() error {
	m.Close()
	os.Remove(m.indexFile.Name())
	return os.RemoveAll(m.dbFileName)
}
<|endoftext|>


<commit_before><commit_msg>Changing game server test port, so maybe travis won't complain...<commit_after><|endoftext|>


<commit_before><commit_msg>修改了buffer.go;sendrecv.go;process.go<commit_after><|endoftext|>


<commit_before><commit_msg>feat(slo): add logout response request validation (#247)<commit_after><|endoftext|>


<commit_before><commit_msg>Added auth shared lib<commit_after><|endoftext|>


<commit_before>package sparta

import (
	"fmt"
	"strings"

	_ "github.com/aws/aws-lambda-go/lambda"        // Force dep to resolve
	_ "github.com/aws/aws-lambda-go/lambdacontext" // Force dep to resolve
)

////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

const (
	// ProperName is the DRY name definition
	ProperName = "Sparta"
)
const (
	// LambdaBinaryTag is the build tag name used when building the binary
	LambdaBinaryTag = "lambdabinary"
)

var (
	// SpartaVersion defines the current Sparta release
	SpartaVersion = fmt.Sprintf("3.0.0.%s", SpartaGitShortHash)
)

// AWSLambdaRuntimeName is an alias for the runtime name
type AWSLambdaRuntimeName string

const (
	// Go1LambdaRuntime is the Go version runtime used for the lambda function
	Go1LambdaRuntime AWSLambdaRuntimeName = "go1.x"
)

var (
	// SpartaBinaryName is binary name that exposes the Go lambda function
	SpartaBinaryName = fmt.Sprintf("%s.lambda.amd64", ProperName)
)

const (
	// Custom Resource typename used to create new cloudFormationUserDefinedFunctionCustomResource
	cloudFormationLambda = "Custom::SpartaLambdaCustomResource"
	// divider length is the length of a divider in the text
	// based CLI output
	dividerLength = 48
)
const (
	// envVarLogLevel is the provision time debug value
	// carried into the execution environment
	envVarLogLevel = "SPARTA_LOG_LEVEL"
	// spartaEnvVarFunctionName is the name of this function in the
	// map. It's the function that will be registered to run
	// envVarFunctionName = "SPARTA_FUNC_NAME"
	// envVarDiscoveryInformation is the name of the discovery information
	// published into the environment
	envVarDiscoveryInformation = "SPARTA_DISCOVERY_INFO"
)

var (
	// internal logging header
	headerDivider = strings.Repeat("═", dividerLength)
)

// AWS Principal ARNs from http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
// See also
// http://docs.aws.amazon.com/general/latest/gr/rande.html
// for region specific principal names
const (
	// @enum AWSPrincipal
	APIGatewayPrincipal = "apigateway.amazonaws.com"
	// @enum AWSPrincipal
	CloudWatchEventsPrincipal = "events.amazonaws.com"
	// @enum AWSPrincipal
	SESPrincipal = "ses.amazonaws.com"
	// @enum AWSPrincipal
	SNSPrincipal = "sns.amazonaws.com"
	// @enum AWSPrincipal
	EC2Principal = "ec2.amazonaws.com"
	// @enum AWSPrincipal
	LambdaPrincipal = "lambda.amazonaws.com"
	// @enum AWSPrincipal
	ElasticLoadBalancingPrincipal = "elasticloadbalancing.amazonaws.com"
	// @enum KinesisFirehosePrincipal
	KinesisFirehosePrincipal = "firehose.amazonaws.com"
	// @enum EventBridgePrincipal
	EventBridgePrincipal = "events.amazonaws.com"
)

type contextKey int

const (
	// ContextKeyLogger is the request-independent *zerolog.Logger
	// instance common to all requests
	ContextKeyLogger contextKey = iota
	// ContextKeyRequestLogger is the *zerolog.Logger instance
	// that is annotated with request-identifying
	// information extracted from the AWS context object
	ContextKeyRequestLogger
	// ContextKeyLambdaContext is the *sparta.LambdaContext
	// pointer in the request
	// DEPRECATED
	ContextKeyLambdaContext
	// ContextKeyLambdaError is the possible error that was returned
	// from the lambda function
	ContextKeyLambdaError
	// ContextKeyLambdaResponse is the possible response that
	// was returned from the lambda function
	ContextKeyLambdaResponse
	// ContextKeyAWSConfig is the aws Session instance for this
	// request
	ContextKeyAWSConfig
)

const (
	// ContextKeyBuildOutputDir is the build-time output location
	ContextKeyBuildOutputDir contextKey = iota
	// ContextKeyBuildID is the build-time build id
	ContextKeyBuildID
	// ContextKeyBuildBinaryName is the name of the binary we're building
	ContextKeyBuildBinaryName
)
<commit_msg>Add Step Machine Principal<commit_after>package sparta

import (
	"fmt"
	"strings"

	_ "github.com/aws/aws-lambda-go/lambda"        // Force dep to resolve
	_ "github.com/aws/aws-lambda-go/lambdacontext" // Force dep to resolve
)

////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

const (
	// ProperName is the DRY name definition
	ProperName = "Sparta"
)
const (
	// LambdaBinaryTag is the build tag name used when building the binary
	LambdaBinaryTag = "lambdabinary"
)

var (
	// SpartaVersion defines the current Sparta release
	SpartaVersion = fmt.Sprintf("3.0.0.%s", SpartaGitShortHash)
)

// AWSLambdaRuntimeName is an alias for the runtime name
type AWSLambdaRuntimeName string

const (
	// Go1LambdaRuntime is the Go version runtime used for the lambda function
	Go1LambdaRuntime AWSLambdaRuntimeName = "go1.x"
)

var (
	// SpartaBinaryName is binary name that exposes the Go lambda function
	SpartaBinaryName = fmt.Sprintf("%s.lambda.amd64", ProperName)
)

const (
	// Custom Resource typename used to create new cloudFormationUserDefinedFunctionCustomResource
	cloudFormationLambda = "Custom::SpartaLambdaCustomResource"
	// divider length is the length of a divider in the text
	// based CLI output
	dividerLength = 48
)
const (
	// envVarLogLevel is the provision time debug value
	// carried into the execution environment
	envVarLogLevel = "SPARTA_LOG_LEVEL"
	// spartaEnvVarFunctionName is the name of this function in the
	// map. It's the function that will be registered to run
	// envVarFunctionName = "SPARTA_FUNC_NAME"
	// envVarDiscoveryInformation is the name of the discovery information
	// published into the environment
	envVarDiscoveryInformation = "SPARTA_DISCOVERY_INFO"
)

var (
	// internal logging header
	headerDivider = strings.Repeat("═", dividerLength)
)

// AWS Principal ARNs from http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
// See also
// http://docs.aws.amazon.com/general/latest/gr/rande.html
// for region specific principal names
const (
	// @enum AWSPrincipal
	APIGatewayPrincipal = "apigateway.amazonaws.com"
	// @enum AWSPrincipal
	CloudWatchEventsPrincipal = "events.amazonaws.com"
	// @enum AWSPrincipal
	SESPrincipal = "ses.amazonaws.com"
	// @enum AWSPrincipal
	SNSPrincipal = "sns.amazonaws.com"
	// @enum AWSPrincipal
	EC2Principal = "ec2.amazonaws.com"
	// @enum AWSPrincipal
	LambdaPrincipal = "lambda.amazonaws.com"
	// @enum AWSPrincipal
	ElasticLoadBalancingPrincipal = "elasticloadbalancing.amazonaws.com"
	// @enum KinesisFirehosePrincipal
	KinesisFirehosePrincipal = "firehose.amazonaws.com"
	// @enum EventBridgePrincipal
	EventBridgePrincipal = "events.amazonaws.com"
	// @enum StepMachinePrincipal
	StepMachinePrincipal = "states.amazonaws.com"
)

type contextKey int

const (
	// ContextKeyLogger is the request-independent *zerolog.Logger
	// instance common to all requests
	ContextKeyLogger contextKey = iota
	// ContextKeyRequestLogger is the *zerolog.Logger instance
	// that is annotated with request-identifying
	// information extracted from the AWS context object
	ContextKeyRequestLogger
	// ContextKeyLambdaContext is the *sparta.LambdaContext
	// pointer in the request
	// DEPRECATED
	ContextKeyLambdaContext
	// ContextKeyLambdaError is the possible error that was returned
	// from the lambda function
	ContextKeyLambdaError
	// ContextKeyLambdaResponse is the possible response that
	// was returned from the lambda function
	ContextKeyLambdaResponse
	// ContextKeyAWSConfig is the aws Session instance for this
	// request
	ContextKeyAWSConfig
)

const (
	// ContextKeyBuildOutputDir is the build-time output location
	ContextKeyBuildOutputDir contextKey = iota
	// ContextKeyBuildID is the build-time build id
	ContextKeyBuildID
	// ContextKeyBuildBinaryName is the name of the binary we're building
	ContextKeyBuildBinaryName
)
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/go-oauth2/oauth2/v4/errors"
	"github.com/go-oauth2/oauth2/v4/generates"
	"github.com/go-oauth2/oauth2/v4/manage"
	"github.com/go-oauth2/oauth2/v4/models"
	"github.com/go-oauth2/oauth2/v4/server"
	"github.com/go-oauth2/oauth2/v4/store"
	"github.com/go-session/session"
)

func main() {
	manager := manage.NewDefaultManager()
	manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)

	// token store
	manager.MustTokenStorage(store.NewMemoryTokenStore())

	// generate jwt access token
	manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512))

	clientStore := store.NewClientStore()
	clientStore.Set("222222", &models.Client{
		ID:     "222222",
		Secret: "22222222",
		Domain: "http://localhost:9094",
	})
	manager.MapClientStorage(clientStore)

	srv := server.NewServer(server.NewConfig(), manager)

	srv.SetPasswordAuthorizationHandler(func(username, password string) (userID string, err error) {
		if username == "test" && password == "test" {
			userID = "test"
		}
		return
	})

	srv.SetUserAuthorizationHandler(userAuthorizeHandler)

	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	http.HandleFunc("/login", loginHandler)
	http.HandleFunc("/auth", authHandler)

	http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
		store, err := session.Start(r.Context(), w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		var form url.Values
		if v, ok := store.Get("ReturnUri"); ok {
			form = v.(url.Values)
		}
		r.Form = form

		store.Delete("ReturnUri")
		store.Save()

		err = srv.HandleAuthorizeRequest(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	})

	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		err := srv.HandleTokenRequest(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
		token, err := srv.ValidationBearerToken(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		data := map[string]interface{}{
			"expires_in": int64(token.GetAccessCreateAt().Add(token.GetAccessExpiresIn()).Sub(time.Now()).Seconds()),
			"client_id":  token.GetClientID(),
			"user_id":    token.GetUserID(),
		}
		e := json.NewEncoder(w)
		e.SetIndent("", "  ")
		e.Encode(data)
	})

	log.Println("Server is running at 9096 port.")
	log.Fatal(http.ListenAndServe(":9096", nil))
}

func userAuthorizeHandler(w http.ResponseWriter, r *http.Request) (userID string, err error) {
	store, err := session.Start(r.Context(), w, r)
	if err != nil {
		return
	}

	uid, ok := store.Get("LoggedInUserID")
	if !ok {
		if r.Form == nil {
			r.ParseForm()
		}

		store.Set("ReturnUri", r.Form)
		store.Save()

		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusFound)
		return
	}

	userID = uid.(string)
	store.Delete("LoggedInUserID")
	store.Save()
	return
}

func loginHandler(w http.ResponseWriter, r *http.Request) {
	store, err := session.Start(r.Context(), w, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Method == "POST" {
		if r.Form == nil {
			if err := r.ParseForm(); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		store.Set("LoggedInUserID", r.Form.Get("username"))
		store.Save()

		w.Header().Set("Location", "/auth")
		w.WriteHeader(http.StatusFound)
		return
	}
	outputHTML(w, r, "static/login.html")
}

func authHandler(w http.ResponseWriter, r *http.Request) {
	store, err := session.Start(nil, w, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := store.Get("LoggedInUserID"); !ok {
		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusFound)
		return
	}

	outputHTML(w, r, "static/auth.html")
}

func outputHTML(w http.ResponseWriter, req *http.Request, filename string) {
	file, err := os.Open(filename)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer file.Close()
	fi, _ := file.Stat()
	http.ServeContent(w, req, file.Name(), fi.ModTime(), file)
}
<commit_msg>Proof of concept<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/go-oauth2/oauth2/v4/generates"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"time"

	"github.com/go-oauth2/oauth2/v4/errors"
	"github.com/go-oauth2/oauth2/v4/manage"
	"github.com/go-oauth2/oauth2/v4/models"
	"github.com/go-oauth2/oauth2/v4/server"
	"github.com/go-oauth2/oauth2/v4/store"
	"github.com/go-session/session"
)

var (
	dumpvar   bool
	idvar     string
	secretvar string
	domainvar string
	portvar   int
)

func init() {
	flag.BoolVar(&dumpvar, "d", true, "Dump requests and responses")
	flag.StringVar(&idvar, "i", "222222", "The client id being passed in")
	flag.StringVar(&secretvar, "s", "22222222", "The client secret being passed in")
	flag.StringVar(&domainvar, "r", "http://localhost:9094", "The domain of the redirect url")
	flag.IntVar(&portvar, "p", 9096, "the base port for the server")
}

func main() {
	flag.Parse()
	if dumpvar {
		log.Println("Dumping requests")
	}
	manager := manage.NewDefaultManager()
	manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)

	// token store
	manager.MustTokenStorage(store.NewMemoryTokenStore())

	// generate jwt access token
	// manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512))
	manager.MapAccessGenerate(generates.NewAccessGenerate())

	clientStore := store.NewClientStore()
	clientStore.Set(idvar, &models.Client{
		ID:     idvar,
		Secret: secretvar,
		Domain: domainvar,
	})
	manager.MapClientStorage(clientStore)

	srv := server.NewServer(server.NewConfig(), manager)

	srv.SetPasswordAuthorizationHandler(func(username, password string) (userID string, err error) {
		if username == "test" && password == "test" {
			userID = "test"
		}
		return
	})

	srv.SetUserAuthorizationHandler(userAuthorizeHandler)

	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	http.HandleFunc("/login", loginHandler)
	http.HandleFunc("/auth", authHandler)

	http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
		if dumpvar {
			dumpRequest(os.Stdout, "authorize", r)
		}

		store, err := session.Start(r.Context(), w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		var form url.Values
		if v, ok := store.Get("ReturnUri"); ok {
			form = v.(url.Values)
		}
		r.Form = form

		store.Delete("ReturnUri")
		store.Save()

		err = srv.HandleAuthorizeRequest(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	})

	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		if dumpvar {
			_ = dumpRequest(os.Stdout, "token", r) // Ignore the error
		}

		err := srv.HandleTokenRequest(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	})

	http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
		if dumpvar {
			_ = dumpRequest(os.Stdout, "test", r) // Ignore the error
		}
		token, err := srv.ValidationBearerToken(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		data := map[string]interface{}{
			"expires_in": int64(token.GetAccessCreateAt().Add(token.GetAccessExpiresIn()).Sub(time.Now()).Seconds()),
			"client_id":  token.GetClientID(),
			"user_id":    token.GetUserID(),
		}
		e := json.NewEncoder(w)
		e.SetIndent("", "  ")
		e.Encode(data)
	})

	log.Printf("Server is running at %d port.\n", portvar)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d",portvar), nil))
}

func dumpRequest(writer io.Writer, header string, r *http.Request) error {
	data, err := httputil.DumpRequest(r, true)
	if err != nil {
		return err
	}
	writer.Write([]byte("\n" + header + ": \n"))
	writer.Write(data)
	return nil
}

func userAuthorizeHandler(w http.ResponseWriter, r *http.Request) (userID string, err error) {
	if dumpvar {
		_ = dumpRequest(os.Stdout, "userAuthorizeHandler", r) // Ignore the error
	}
	store, err := session.Start(r.Context(), w, r)
	if err != nil {
		return
	}

	uid, ok := store.Get("LoggedInUserID")
	if !ok {
		if r.Form == nil {
			r.ParseForm()
		}

		store.Set("ReturnUri", r.Form)
		store.Save()

		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusFound)
		return
	}

	userID = uid.(string)
	store.Delete("LoggedInUserID")
	store.Save()
	return
}

func loginHandler(w http.ResponseWriter, r *http.Request) {
	if dumpvar {
		_ = dumpRequest(os.Stdout, "login", r) // Ignore the error
	}
	store, err := session.Start(r.Context(), w, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Method == "POST" {
		if r.Form == nil {
			if err := r.ParseForm(); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		store.Set("LoggedInUserID", r.Form.Get("username"))
		store.Save()

		w.Header().Set("Location", "/auth")
		w.WriteHeader(http.StatusFound)
		return
	}
	outputHTML(w, r, "static/login.html")
}

func authHandler(w http.ResponseWriter, r *http.Request) {
	if dumpvar {
		_ = dumpRequest(os.Stdout, "auth", r) // Ignore the error
	}
	store, err := session.Start(nil, w, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := store.Get("LoggedInUserID"); !ok {
		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusFound)
		return
	}

	outputHTML(w, r, "static/auth.html")
}

func outputHTML(w http.ResponseWriter, req *http.Request, filename string) {
	file, err := os.Open(filename)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer file.Close()
	fi, _ := file.Stat()
	http.ServeContent(w, req, file.Name(), fi.ModTime(), file)
}
<|endoftext|>