<commit_before>package dynamodb

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"time"

	"github.com/eikeon/aws4"
)

type dynamo struct {
	Tables
	client *aws4.Client
}

func NewDynamoDB() DynamoDB {
	return &dynamo{Tables: make(Tables)}
}

func (b *dynamo) getClient() *aws4.Client {
	if b.client == nil {
		b.client = aws4.DefaultClient
	}
	return b.client
}

func (db *dynamo) post(action string, parameters interface{}) (io.ReadCloser, error) {
	url := "https://dynamodb.us-east-1.amazonaws.com/"
	currentRetry := 0
	maxNumberOfRetries := 10
RETRY:
	var buf bytes.Buffer
	enc := json.NewEncoder(&buf)
	if err := enc.Encode(parameters); err != nil {
		return nil, err
	}
	if request, err := http.NewRequest("POST", url, &buf); err != nil {
		return nil, err
	} else {
		request.Header.Set("Content-Type", "application/x-amz-json-1.0")
		request.Header.Set("X-Amz-Target", "DynamoDB_20120810"+"."+action)

		if response, err := db.getClient().Do(request); err == nil {
			switch response.StatusCode {
			case 200:
				return response.Body, nil
			case 400:
				type ResponseError struct {
					StatusCode int
					Type       string `json:"__type"`
					Message    string
				}
				var error ResponseError
				if err = json.NewDecoder(response.Body).Decode(&error); err != nil {
					return nil, err
				}
				response.Body.Close()
				if error.Type == "com.amazonaws.dynamodb.v20120810#ProvisionedThroughputExceededException" {
					log.Println("Provisioned throughput exceeded... retrying.")
				} else {
					return nil, errors.New(fmt.Sprintf("%#v", error))
				}
			case 500:
				response.Body.Close()
				log.Println("Got a 500 error... retrying.")
			default:
				b, err := ioutil.ReadAll(response.Body)
				response.Body.Close()
				if err != nil {
					return nil, err
				}
				return nil, errors.New(string(b))
			}
		} else {
			return nil, err
		}
		if currentRetry < maxNumberOfRetries {
			wait := time.Duration(math.Pow(2, float64(currentRetry))) * 50 * time.Millisecond
			time.Sleep(wait)
			currentRetry = currentRetry + 1
			goto RETRY
		} else {
			return nil, errors.New("exceeded maximum number of retries")
		}

	}
}

func (db *dynamo) CreateTable(table *Table) error {
	reader, err := db.post("CreateTable", table)
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) UpdateTable(tableName string, provisionedThroughput ProvisionedThroughput) error {
	reader, err := db.post("UpdateTable", struct {
		TableName             string
		ProvisionedThroughput ProvisionedThroughput
	}{tableName, provisionedThroughput})
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) DescribeTable(tableName string) (*TableDescription, error) {
	reader, err := db.post("DescribeTable", struct {
		TableName string
	}{tableName})
	if err != nil {
		return nil, err
	}
	var description TableDescription
	if err = json.NewDecoder(reader).Decode(&description); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}
	return &description, err
}

func (db *dynamo) DeleteTable(tableName string) error {
	reader, err := db.post("DeleteTable", struct {
		TableName string
	}{tableName})
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) PutItem(tableName string, item Item) error {
	reader, err := db.post("PutItem", struct {
		TableName string
		Item      Item
	}{tableName, item})
	if err != nil {
		return err
	}
	// TODO: decode response
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) GetItem(tableName string, key Key) (*GetItemResponse, error) {
	reader, err := db.post("GetItem", struct {
		TableName string
		Key       Key
	}{tableName, key})
	if err != nil {
		return nil, err
	}

	response := &GetItemResponse{}
	if err = json.NewDecoder(reader).Decode(&response); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}

	return response, err
}

func (db *dynamo) Scan(tableName string) (*ScanResponse, error) {
	reader, err := db.post("Scan", struct {
		TableName string
	}{tableName})
	if err != nil {
		return nil, err
	}
	response := &ScanResponse{}
	if err = json.NewDecoder(reader).Decode(&response); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}
	return response, nil
}
<commit_msg>Added action to retry message.<commit_after>package dynamodb

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"time"

	"github.com/eikeon/aws4"
)

type dynamo struct {
	Tables
	client *aws4.Client
}

func NewDynamoDB() DynamoDB {
	return &dynamo{Tables: make(Tables)}
}

func (b *dynamo) getClient() *aws4.Client {
	if b.client == nil {
		b.client = aws4.DefaultClient
	}
	return b.client
}

func (db *dynamo) post(action string, parameters interface{}) (io.ReadCloser, error) {
	url := "https://dynamodb.us-east-1.amazonaws.com/"
	currentRetry := 0
	maxNumberOfRetries := 10
RETRY:
	var buf bytes.Buffer
	enc := json.NewEncoder(&buf)
	if err := enc.Encode(parameters); err != nil {
		return nil, err
	}
	if request, err := http.NewRequest("POST", url, &buf); err != nil {
		return nil, err
	} else {
		request.Header.Set("Content-Type", "application/x-amz-json-1.0")
		request.Header.Set("X-Amz-Target", "DynamoDB_20120810"+"."+action)

		if response, err := db.getClient().Do(request); err == nil {
			switch response.StatusCode {
			case 200:
				return response.Body, nil
			case 400:
				type ResponseError struct {
					StatusCode int
					Type       string `json:"__type"`
					Message    string
				}
				var error ResponseError
				if err = json.NewDecoder(response.Body).Decode(&error); err != nil {
					return nil, err
				}
				response.Body.Close()
				if error.Type == "com.amazonaws.dynamodb.v20120810#ProvisionedThroughputExceededException" {
					log.Println("Provisioned throughput exceeded... retrying:", action)
				} else {
					return nil, errors.New(fmt.Sprintf("%#v", error))
				}
			case 500:
				response.Body.Close()
				log.Println("Got a 500 error... retrying.")
			default:
				b, err := ioutil.ReadAll(response.Body)
				response.Body.Close()
				if err != nil {
					return nil, err
				}
				return nil, errors.New(string(b))
			}
		} else {
			return nil, err
		}
		if currentRetry < maxNumberOfRetries {
			wait := time.Duration(math.Pow(2, float64(currentRetry))) * 50 * time.Millisecond
			time.Sleep(wait)
			currentRetry = currentRetry + 1
			goto RETRY
		} else {
			return nil, errors.New("exceeded maximum number of retries")
		}

	}
}

func (db *dynamo) CreateTable(table *Table) error {
	reader, err := db.post("CreateTable", table)
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) UpdateTable(tableName string, provisionedThroughput ProvisionedThroughput) error {
	reader, err := db.post("UpdateTable", struct {
		TableName             string
		ProvisionedThroughput ProvisionedThroughput
	}{tableName, provisionedThroughput})
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) DescribeTable(tableName string) (*TableDescription, error) {
	reader, err := db.post("DescribeTable", struct {
		TableName string
	}{tableName})
	if err != nil {
		return nil, err
	}
	var description TableDescription
	if err = json.NewDecoder(reader).Decode(&description); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}
	return &description, err
}

func (db *dynamo) DeleteTable(tableName string) error {
	reader, err := db.post("DeleteTable", struct {
		TableName string
	}{tableName})
	if err != nil {
		return err
	}
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) PutItem(tableName string, item Item) error {
	reader, err := db.post("PutItem", struct {
		TableName string
		Item      Item
	}{tableName, item})
	if err != nil {
		return err
	}
	// TODO: decode response
	if reader != nil {
		reader.Close()
	}
	return err
}

func (db *dynamo) GetItem(tableName string, key Key) (*GetItemResponse, error) {
	reader, err := db.post("GetItem", struct {
		TableName string
		Key       Key
	}{tableName, key})
	if err != nil {
		return nil, err
	}

	response := &GetItemResponse{}
	if err = json.NewDecoder(reader).Decode(&response); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}

	return response, err
}

func (db *dynamo) Scan(tableName string) (*ScanResponse, error) {
	reader, err := db.post("Scan", struct {
		TableName string
	}{tableName})
	if err != nil {
		return nil, err
	}
	response := &ScanResponse{}
	if err = json.NewDecoder(reader).Decode(&response); err != nil {
		return nil, err
	}
	if reader != nil {
		reader.Close()
	}
	return response, nil
}
<|endoftext|>


<commit_before>package riakpbc

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
)

type Encoder struct{}

func NewEncoder() *Encoder {
	self := new(Encoder)
	return self
}

func (self *Encoder) Marshal(data interface{}) (*RpbContent, error) {
	t := reflect.ValueOf(data)
	if t.Kind() != reflect.Ptr {
		return nil, errors.New(fmt.Sprintf("Expected a pointer not %s", t.Kind()))
	}

	// Output
	isJson := false
	out := &RpbContent{}

	e := t.Elem()
	switch e.Kind() {
	case reflect.Struct:
		for i := 0; i < e.NumField(); i++ {
			val := e.Field(i).Interface()
			fld := e.Type().Field(i)
			knd := e.Field(i).Kind()
			tag := fld.Tag

			// Skip anonymous fields
			if fld.Anonymous {
				continue
			}

			// If any of the struct tags are "json" then this is a json structure.
			if tag.Get("json") != "" {
				isJson = true
			}

			if tdata := tag.Get("riak"); tdata != "" {
				for _, tfield := range strings.Split(tdata, ",") {
					switch tfield {
					case "index":
						var key string
						switch knd {
						case reflect.Int:
							key = fld.Name + "_int"
							break
						case reflect.String:
							key = fld.Name + "_bin"
							break
						}
						index := &RpbPair{
							Key:   []byte(strings.ToLower(key)),
							Value: []byte(val.(string)),
						}
						out.Indexes = append(out.Indexes, index)
						break
					case "link":

						break
					}
				}
			}
		}
		break
	default:
		return nil, errors.New("Marshal expected a struct")
	}

	// Automatically marshal json structures.
	if isJson {
		jsondata, err := json.Marshal(data)
		if err != nil {
			return nil, err
		}
		out.Value = jsondata
	}

	return out, nil
}
<commit_msg>content type<commit_after>package riakpbc

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
)

type Encoder struct{}

func NewEncoder() *Encoder {
	self := new(Encoder)
	return self
}

func (self *Encoder) Marshal(data interface{}) (*RpbContent, error) {
	t := reflect.ValueOf(data)
	if t.Kind() != reflect.Ptr {
		return nil, errors.New(fmt.Sprintf("Expected a pointer not %s", t.Kind()))
	}

	// Output
	isJson := false
	out := &RpbContent{}

	e := t.Elem()
	switch e.Kind() {
	case reflect.Struct:
		for i := 0; i < e.NumField(); i++ {
			val := e.Field(i).Interface()
			fld := e.Type().Field(i)
			knd := e.Field(i).Kind()
			tag := fld.Tag

			// Skip anonymous fields
			if fld.Anonymous {
				continue
			}

			// If any of the struct tags are "json" then this is a json structure.
			if tag.Get("json") != "" {
				isJson = true
			}

			if tdata := tag.Get("riak"); tdata != "" {
				for _, tfield := range strings.Split(tdata, ",") {
					switch tfield {
					case "index":
						var key string
						switch knd {
						case reflect.Int:
							key = fld.Name + "_int"
							break
						case reflect.String:
							key = fld.Name + "_bin"
							break
						}
						index := &RpbPair{
							Key:   []byte(strings.ToLower(key)),
							Value: []byte(val.(string)),
						}
						out.Indexes = append(out.Indexes, index)
						break
					case "link":

						break
					}
				}
			}
		}
		break
	default:
		return nil, errors.New("Marshal expected a struct")
	}

	// Automatically marshal json structures.
	if isJson {
		jsondata, err := json.Marshal(data)
		if err != nil {
			return nil, err
		}
		out.Value = jsondata
		out.ContentType = []byte("application/json")
	}

	return out, nil
}
<|endoftext|>


<commit_before>package lemon

import (
	"context"
	"os"
	"sync"
	"time"
)

// Engine is a components that handle your application lifecycle.
//
// Start
//
// It will start every registered hook (or daemon, service, etc...) and block until it
// receives a SIGINT, SIGTERM or SIGQUIT signal.
//
// For example:
//
//   if e, err := New(); err == nil {
//       e.Register(&MyService{})
//       e.Register(&MyWorker{})
//       e.Start()
//       // Wait until Ctrl-C
//   }
//
// Stop
//
// When your application has to stop, the engine will notify every hook to shutdown gracefully.
// However, if a hook fails to stop before timeout, the underlying goroutine will be destroyed...
//
type Engine struct {
	interrupt      chan os.Signal
	timeout        time.Duration
	hooks          []Hook
	wait           sync.WaitGroup
	parent         context.Context
	ctx            context.Context
	cancel         context.CancelFunc
	signals        []os.Signal
	beforeShutdown func()
	afterShutdown  func()
	logger         func(error)
}

// New creates a new engine with given options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func New(options ...Option) (*Engine, error) {
	return NewWithContext(context.Background(), options...)
}

// NewWithContext creates a new engine with given context and options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func NewWithContext(parent context.Context, options ...Option) (*Engine, error) {

	e := &Engine{}
	e.parent = parent
	e.init()

	for _, o := range options {
		if err := o.apply(e); err != nil {
			return nil, err
		}
	}

	return e, nil
}

func (e *Engine) launch(h Hook) {

	e.wait.Add(1)

	go func() {

		defer e.wait.Done()

		runtime := &HookRuntime{}

		// Wait for an event to notify this goroutine that a shutdown is required.
		// It could either be from engine's context or during Hook startup if an error has occurred.
		// NOTE: If HookRuntime returns an error, we have to shutdown every Hook...
		if err := runtime.WaitForEvent(e.ctx, h); err != nil {
			e.log(err)
			e.cancel()
		}

		// Wait for hook to gracefully shutdown, or kill it after timeout.
		// This is handled by HookRuntime.
		for _, err := range runtime.Shutdown(e.timeout) {
			e.log(err)
		}

	}()
}

// init configures default parameters for engine.
func (e *Engine) init() {

	if e.parent == nil {
		e.parent = context.Background()
	}

	if e.ctx == nil || e.cancel == nil {
		e.ctx, e.cancel = context.WithCancel(context.Background())
	}

	if e.timeout == 0 {
		e.timeout = DefaultTimeout
	}

	if len(e.signals) == 0 {
		e.signals = Signals
	}

	if e.interrupt == nil {
		e.interrupt = make(chan os.Signal, 1)
	}

}

// Start will launch the engine and start registered hooks.
// It will block until every hooks has shutdown, gracefully or with force...
func (e *Engine) Start() {

	e.init()

	go e.waitShutdownNotification()

	for _, h := range e.hooks {
		e.launch(h)
	}

	e.wait.Wait()

	if e.afterShutdown != nil {
		e.afterShutdown()
	}

}
<commit_msg>refactor(error): Update Start()<commit_after>package lemon

import (
	"context"
	"os"
	"sync"
	"time"
)

// Engine is a components that handle your application lifecycle.
//
// Start
//
// It will start every registered hook (or daemon, service, etc...) and block until it
// receives a SIGINT, SIGTERM or SIGQUIT signal.
//
// For example:
//
//   if e, err := New(); err == nil {
//       e.Register(&MyService{})
//       e.Register(&MyWorker{})
//       e.Start()
//       // Wait until Ctrl-C
//   }
//
// Stop
//
// When your application has to stop, the engine will notify every hook to shutdown gracefully.
// However, if a hook fails to stop before timeout, the underlying goroutine will be destroyed...
//
type Engine struct {
	interrupt      chan os.Signal
	timeout        time.Duration
	hooks          []Hook
	wait           sync.WaitGroup
	parent         context.Context
	ctx            context.Context
	cancel         context.CancelFunc
	signals        []os.Signal
	beforeShutdown func()
	afterShutdown  func()
	logger         func(error)
	mutex          sync.Mutex
	cause          error
}

// New creates a new engine with given options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func New(options ...Option) (*Engine, error) {
	return NewWithContext(context.Background(), options...)
}

// NewWithContext creates a new engine with given context and options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func NewWithContext(parent context.Context, options ...Option) (*Engine, error) {

	e := &Engine{}
	e.parent = parent
	e.init()

	for _, o := range options {
		if err := o.apply(e); err != nil {
			return nil, err
		}
	}

	return e, nil
}

func (e *Engine) launch(h Hook) {

	e.wait.Add(1)

	go func() {

		defer e.wait.Done()

		runtime := &HookRuntime{}

		// Wait for an event to notify this goroutine that a shutdown is required.
		// It could either be from engine's context or during Hook startup if an error has occurred.
		// NOTE: If HookRuntime returns an error, we have to shutdown every Hook...
		if err := runtime.WaitForEvent(e.ctx, h); err != nil {
			e.mutex.Lock()
			e.log(err)
			e.cancel()
			e.cause = err
			e.mutex.Unlock()
		}

		// Wait for hook to gracefully shutdown, or kill it after timeout.
		// This is handled by HookRuntime.
		for _, err := range runtime.Shutdown(e.timeout) {
			e.mutex.Lock()
			e.log(err)
			e.mutex.Unlock()
		}

	}()
}

// init configures default parameters for engine.
func (e *Engine) init() {

	if e.parent == nil {
		e.parent = context.Background()
	}

	if e.ctx == nil || e.cancel == nil {
		e.ctx, e.cancel = context.WithCancel(context.Background())
	}

	if e.timeout == 0 {
		e.timeout = DefaultTimeout
	}

	if len(e.signals) == 0 {
		e.signals = Signals
	}

	if e.interrupt == nil {
		e.interrupt = make(chan os.Signal, 1)
	}

}

// Start will launch the engine and start registered hooks.
// It will block until every hooks has shutdown, gracefully or with force...
func (e *Engine) Start() error {

	e.init()

	go e.waitShutdownNotification()

	for _, h := range e.hooks {
		e.launch(h)
	}

	e.wait.Wait()

	if e.afterShutdown != nil {
		e.afterShutdown()
	}

	e.mutex.Lock()
	defer e.mutex.Unlock()

	return e.cause

}
<|endoftext|>


<commit_before>package mcstore

import (
	"net/http"

	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db/schema"

	"net/http/httptest"

	"github.com/materials-commons/mcstore/pkg/domain/mocks"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("DataHandler", func() {
	Describe("getOriginalFormValue Method Tests", func() {
		It("Should return false if original flag is not given", func() {
			req, _ := http.NewRequest("GET", "http://localhost", nil)
			Expect(getOriginalFormValue(req)).To(BeFalse())
		})

		It("Should return false if original flag is passed with no value", func() {
			req, _ := http.NewRequest("GET", "http://localhost?original", nil)
			Expect(getOriginalFormValue(req)).To(BeFalse())
		})

		Context("Setting original flag to any value should always return true", func() {
			It("Should return true for numeric true and false (0, 1)", func() {
				req, _ := http.NewRequest("GET", "http://localhost?original=0", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())

				req, _ = http.NewRequest("GET", "http://localhost?original=1", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())
			})

			It("Should return true for boolean true and false", func() {
				req, _ := http.NewRequest("GET", "http://localhost?original=false", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())

				req, _ = http.NewRequest("GET", "http://localhost?original=true", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())
			})
		})

		It("Should work if original is passed in as the second flag", func() {
			req, _ := http.NewRequest("GET", "http://localhost?apikey=abc&original=true", nil)
			Expect(getOriginalFormValue(req)).To(BeTrue())
		})
	})

	Describe("isConvertedImage Method Tests", func() {
		It("Should return true for image/tiff", func() {
			Expect(isConvertedImage("image/tiff")).To(BeTrue())
		})

		It("Should return true for image/x-ms-bmp", func() {
			Expect(isConvertedImage("image/x-ms-bmp")).To(BeTrue())
		})

		It("Should return true for image/bmp", func() {
			Expect(isConvertedImage("image/bmp")).To(BeTrue())
		})

		It("Should return false for image/jpg", func() {
			Expect(isConvertedImage("image/jpg")).To(BeFalse())
		})
	})

	Describe("filePath Method Tests", func() {
		var (
			saved string
			f     schema.File = schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}
		)

		BeforeEach(func() {
			saved = config.GetString("MCDIR")
			config.Set("MCDIR", "/tmp/mcdir")
		})

		AfterEach(func() {
			config.Set("MCDIR", saved)
		})

		It("Should return converted and not original for tiff images", func() {
			f.MediaType.Mime = "image/tiff"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())))
		})

		It("Should return original with converted image when asking for original", func() {
			f.MediaType.Mime = "image/tiff"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original when unconverted type and not requesting original", func() {
			f.MediaType.Mime = "text/plain"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original when unconverted and requesting original", func() {
			f.MediaType.Mime = "text/plain"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return usesID converted path when uses is set and not requesting original on tiff", func() {
			f.MediaType.Mime = "image/tiff"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())))
		})

		It("Should return usesID original path when uses is set and requesting original on tiff", func() {
			f.MediaType.Mime = "image/tiff"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original with uses set not requesting original for text/plain (non-converted)", func() {
			f.MediaType.Mime = "text/plain"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original with uses set, requesting original for non-converted type", func() {
			f.MediaType.Mime = "text/plain"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

	})

	Describe("serveData Method Tests", func() {
		var (
			server      *httptest.Server
			saved       string = config.GetString("MCDIR")
			rr          *httptest.ResponseRecorder
			datahandler http.Handler
			access      *mocks.Access
			dhhandler   *dataHandler
		)

		BeforeEach(func() {
			access = mocks.NewMAccess()
			datahandler = NewDataHandler(access)
			dhhandler = datahandler.(*dataHandler)
			server = httptest.NewServer(datahandler)
			rr = httptest.NewRecorder()
			config.Set("MCDIR", "/tmp/mcdir")
		})

		AfterEach(func() {
			server.Close()
			config.Set("MCDIR", saved)
		})

		It("Should fail if no apikey is specified", func() {
			req, _ := http.NewRequest("GET", server.URL, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(Equal(app.ErrNoAccess), "Expected ErrNoAccess, got: %s ", err)
			Expect(path).To(Equal(""), "Got unexpected value for path %s", path)
			Expect(mediatype).To(Equal(""), "Got unexpected value for mediatype %s", mediatype)
		})

		It("Should fail when user doesn't have access to the requested file", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123"
			req, _ := http.NewRequest("GET", fileURL, nil)
			var nilFile *schema.File
			access.On("GetFile", "abc123", "abc-defg-456").Return(nilFile, app.ErrNoAccess)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(Equal(app.ErrNoAccess), "Expected ErrNoAccess: %s", err)
			Expect(path).To(Equal(""), "Got unexpected value for path %s", path)
			Expect(mediatype).To(Equal(""), "Got unexpected value for mediatype %s", mediatype)
		})

		It("Should succeed with a good key and fileID and return converted image for a tiff", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123"
			req, _ := http.NewRequest("GET", fileURL, nil)
			f := schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}

			access.On("GetFile", "abc123", "abc-defg-456").Return(&f, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(BeNil())
			Expect(mediatype).To(Equal("image/jpeg"), "Expected image/jpeg, got %s", mediatype)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())), "Got unexpected value for path %s", path)
		})

		It("Should succeed with a good key and fileID, and return the original image when original flag set for tiff", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123&original=true"
			req, _ := http.NewRequest("GET", fileURL, nil)
			f := schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}

			access.On("GetFile", "abc123", "abc-defg-456").Return(&f, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(BeNil())
			Expect(mediatype).To(Equal("image/tiff"), "Expected image/tiff, got %s", mediatype)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())), "Got unexpected value for path %s", path)
		})
	})
})
<commit_msg>Update test description.<commit_after>package mcstore

import (
	"net/http"

	"github.com/materials-commons/config"
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db/schema"

	"net/http/httptest"

	"github.com/materials-commons/mcstore/pkg/domain/mocks"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("DataHandler", func() {
	Describe("getOriginalFormValue Method Tests", func() {
		It("Should return false if original flag is not given", func() {
			req, _ := http.NewRequest("GET", "http://localhost", nil)
			Expect(getOriginalFormValue(req)).To(BeFalse())
		})

		It("Should return false if original flag is passed with no value", func() {
			req, _ := http.NewRequest("GET", "http://localhost?original", nil)
			Expect(getOriginalFormValue(req)).To(BeFalse())
		})

		Context("Setting original flag to any value should always return true", func() {
			It("Should return true for numeric true and false (0, 1)", func() {
				req, _ := http.NewRequest("GET", "http://localhost?original=0", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())

				req, _ = http.NewRequest("GET", "http://localhost?original=1", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())
			})

			It("Should return true for boolean true and false", func() {
				req, _ := http.NewRequest("GET", "http://localhost?original=false", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())

				req, _ = http.NewRequest("GET", "http://localhost?original=true", nil)
				Expect(getOriginalFormValue(req)).To(BeTrue())
			})
		})

		It("Should work if original is passed in as the second flag", func() {
			req, _ := http.NewRequest("GET", "http://localhost?apikey=abc&original=true", nil)
			Expect(getOriginalFormValue(req)).To(BeTrue())
		})
	})

	Describe("isConvertedImage Method Tests", func() {
		It("Should return true for image/tiff", func() {
			Expect(isConvertedImage("image/tiff")).To(BeTrue())
		})

		It("Should return true for image/x-ms-bmp", func() {
			Expect(isConvertedImage("image/x-ms-bmp")).To(BeTrue())
		})

		It("Should return true for image/bmp", func() {
			Expect(isConvertedImage("image/bmp")).To(BeTrue())
		})

		It("Should return false for image/jpg", func() {
			Expect(isConvertedImage("image/jpg")).To(BeFalse())
		})
	})

	Describe("filePath Method Tests", func() {
		var (
			saved string
			f     schema.File = schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}
		)

		BeforeEach(func() {
			saved = config.GetString("MCDIR")
			config.Set("MCDIR", "/tmp/mcdir")
		})

		AfterEach(func() {
			config.Set("MCDIR", saved)
		})

		It("Should return converted and not original for tiff images", func() {
			f.MediaType.Mime = "image/tiff"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())))
		})

		It("Should return original even though converted is available when asking for original", func() {
			f.MediaType.Mime = "image/tiff"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original when unconverted type and not requesting original", func() {
			f.MediaType.Mime = "text/plain"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original when unconverted and requesting original", func() {
			f.MediaType.Mime = "text/plain"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return usesID converted path when uses is set and not requesting original on tiff", func() {
			f.MediaType.Mime = "image/tiff"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())))
		})

		It("Should return usesID original path when uses is set and requesting original on tiff", func() {
			f.MediaType.Mime = "image/tiff"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original with uses set not requesting original for text/plain (non-converted)", func() {
			f.MediaType.Mime = "text/plain"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, false)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

		It("Should return original with uses set, requesting original for non-converted type", func() {
			f.MediaType.Mime = "text/plain"
			f.UsesID = "def-ghij-789"
			path := filePath(&f, true)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())))
		})

	})

	Describe("serveData Method Tests", func() {
		var (
			server      *httptest.Server
			saved       string = config.GetString("MCDIR")
			rr          *httptest.ResponseRecorder
			datahandler http.Handler
			access      *mocks.Access
			dhhandler   *dataHandler
		)

		BeforeEach(func() {
			access = mocks.NewMAccess()
			datahandler = NewDataHandler(access)
			dhhandler = datahandler.(*dataHandler)
			server = httptest.NewServer(datahandler)
			rr = httptest.NewRecorder()
			config.Set("MCDIR", "/tmp/mcdir")
		})

		AfterEach(func() {
			server.Close()
			config.Set("MCDIR", saved)
		})

		It("Should fail if no apikey is specified", func() {
			req, _ := http.NewRequest("GET", server.URL, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(Equal(app.ErrNoAccess), "Expected ErrNoAccess, got: %s ", err)
			Expect(path).To(Equal(""), "Got unexpected value for path %s", path)
			Expect(mediatype).To(Equal(""), "Got unexpected value for mediatype %s", mediatype)
		})

		It("Should fail when user doesn't have access to the requested file", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123"
			req, _ := http.NewRequest("GET", fileURL, nil)
			var nilFile *schema.File
			access.On("GetFile", "abc123", "abc-defg-456").Return(nilFile, app.ErrNoAccess)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(Equal(app.ErrNoAccess), "Expected ErrNoAccess: %s", err)
			Expect(path).To(Equal(""), "Got unexpected value for path %s", path)
			Expect(mediatype).To(Equal(""), "Got unexpected value for mediatype %s", mediatype)
		})

		It("Should succeed with a good key and fileID and return converted image for a tiff", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123"
			req, _ := http.NewRequest("GET", fileURL, nil)
			f := schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}

			access.On("GetFile", "abc123", "abc-defg-456").Return(&f, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(BeNil())
			Expect(mediatype).To(Equal("image/jpeg"), "Expected image/jpeg, got %s", mediatype)
			Expect(path).To(Equal(app.MCDir.FilePathImageConversion(f.FileID())), "Got unexpected value for path %s", path)
		})

		It("Should succeed with a good key and fileID, and return the original image when original flag set for tiff", func() {
			fileURL := server.URL + "/abc-defg-456?apikey=abc123&original=true"
			req, _ := http.NewRequest("GET", fileURL, nil)
			f := schema.File{
				ID: "abc-defg-456",
				MediaType: schema.MediaType{
					Mime: "image/tiff",
				},
			}

			access.On("GetFile", "abc123", "abc-defg-456").Return(&f, nil)
			path, mediatype, err := dhhandler.serveData(rr, req)
			Expect(err).To(BeNil())
			Expect(mediatype).To(Equal("image/tiff"), "Expected image/tiff, got %s", mediatype)
			Expect(path).To(Equal(app.MCDir.FilePath(f.FileID())), "Got unexpected value for path %s", path)
		})
	})
})
<|endoftext|>


<commit_before>package message

import (
	"bufio"
	"errors"
	"io"
	"math"
	"strings"

	"github.com/emersion/go-message/textproto"
)

// An Entity is either a whole message or a one of the parts in the body of a
// multipart entity.
type Entity struct {
	Header Header    // The entity's header.
	Body   io.Reader // The decoded entity's body.

	mediaType   string
	mediaParams map[string]string
}

// New makes a new message with the provided header and body. The entity's
// transfer encoding and charset are automatically decoded to UTF-8.
//
// If the message uses an unknown transfer encoding or charset, New returns an
// error that verifies IsUnknownCharset, but also returns an Entity that can
// be read.
func New(header Header, body io.Reader) (*Entity, error) {
	var err error

	mediaType, mediaParams, _ := header.ContentType()

	// QUIRK: RFC 2045 section 6.4 specifies that multipart messages can't have
	// a Content-Transfer-Encoding other than "7bit", "8bit" or "binary".
	// However some messages in the wild are non-conformant and have it set to
	// e.g. "quoted-printable". So we just ignore it for multipart.
	// See https://github.com/emersion/go-message/issues/48
	if !strings.HasPrefix(mediaType, "multipart/") {
		enc := header.Get("Content-Transfer-Encoding")
		if decoded, encErr := encodingReader(enc, body); encErr != nil {
			err = UnknownEncodingError{encErr}
		} else {
			body = decoded
		}
	}

	// RFC 2046 section 4.1.2: charset only applies to text/*
	if strings.HasPrefix(mediaType, "text/") {
		if ch, ok := mediaParams["charset"]; ok {
			if converted, charsetErr := charsetReader(ch, body); charsetErr != nil {
				err = UnknownCharsetError{charsetErr}
			} else {
				body = converted
			}
		}
	}

	return &Entity{
		Header:      header,
		Body:        body,
		mediaType:   mediaType,
		mediaParams: mediaParams,
	}, err
}

// NewMultipart makes a new multipart message with the provided header and
// parts. The Content-Type header must begin with "multipart/".
//
// If the message uses an unknown transfer encoding, NewMultipart returns an
// error that verifies IsUnknownCharset, but also returns an Entity that can
// be read.
func NewMultipart(header Header, parts []*Entity) (*Entity, error) {
	r := &multipartBody{
		header: header,
		parts:  parts,
	}

	return New(header, r)
}

const defaultMaxHeaderBytes = 1 << 20 // 1 MB

var errHeaderTooBig = errors.New("message: header exceeds maximum size")

// limitedReader is the same as io.LimitedReader, but returns a custom error.
type limitedReader struct {
	R io.Reader
	N int64
}

func (lr *limitedReader) Read(p []byte) (int, error) {
	if lr.N <= 0 {
		return 0, errHeaderTooBig
	}
	if int64(len(p)) > lr.N {
		p = p[0:lr.N]
	}
	n, err := lr.R.Read(p)
	lr.N -= int64(n)
	return n, err
}

type ReadOptions struct {
	// MaxHeaderBytes limits the maximum permissible size of a message header
	// block. If exceeded, an error will be returned.
	// -1 == no limit, 0 == default value (1MB)
	MaxHeaderBytes int64
}

// withDefaults returns a sanitised version of the options with defaults/special
// values accounted for.
func (o *ReadOptions) withDefaults() *ReadOptions {
	var out ReadOptions
	if o != nil {
		out = *o
	}
	if out.MaxHeaderBytes == 0 {
		out.MaxHeaderBytes = defaultMaxHeaderBytes
	} else if out.MaxHeaderBytes < 0 {
		out.MaxHeaderBytes = math.MaxInt64
	}
	return &out
}

// ReadWithOptions see Read, but allows overriding some parameters with
// ReadOptions.
//
// If the message uses an unknown transfer encoding or charset, ReadWithOptions
// returns an error that verifies IsUnknownCharset or IsUnknownEncoding, but
// also returns an Entity that can be read.
func ReadWithOptions(r io.Reader, opts *ReadOptions) (*Entity, error) {
	opts = opts.withDefaults()

	lr := &limitedReader{R: r, N: opts.MaxHeaderBytes}
	br := bufio.NewReader(lr)

	h, err := textproto.ReadHeader(br)
	if err != nil {
		return nil, err
	}

	lr.N = math.MaxInt64

	return New(Header{h}, br)
}

// Read reads a message from r. The message's encoding and charset are
// automatically decoded to raw UTF-8. Note that this function only reads the
// message header.
//
// If the message uses an unknown transfer encoding or charset, Read returns an
// error that verifies IsUnknownCharset or IsUnknownEncoding, but also returns
// an Entity that can be read.
func Read(r io.Reader) (*Entity, error) {
	return ReadWithOptions(r, nil)
}

// MultipartReader returns a MultipartReader that reads parts from this entity's
// body. If this entity is not multipart, it returns nil.
func (e *Entity) MultipartReader() MultipartReader {
	if !strings.HasPrefix(e.mediaType, "multipart/") {
		return nil
	}
	if mb, ok := e.Body.(*multipartBody); ok {
		return mb
	}
	return &multipartReader{textproto.NewMultipartReader(e.Body, e.mediaParams["boundary"])}
}

// writeBodyTo writes this entity's body to w (without the header).
func (e *Entity) writeBodyTo(w *Writer) error {
	var err error
	if mb, ok := e.Body.(*multipartBody); ok {
		err = mb.writeBodyTo(w)
	} else {
		_, err = io.Copy(w, e.Body)
	}
	return err
}

// WriteTo writes this entity's header and body to w.
func (e *Entity) WriteTo(w io.Writer) error {
	ew, err := CreateWriter(w, e.Header)
	if err != nil {
		return err
	}
	defer ew.Close()

	return e.writeBodyTo(ew)
}

// WalkFunc is the type of the function called for each part visited by Walk.
//
// The path argument is a list of multipart indices leading to the part. The
// root part has a nil path.
//
// If there was an encoding error walking to a part, the incoming error will
// describe the problem and the function can decide how to handle that error.
//
// Unlike IMAP part paths, indices start from 0 (instead of 1) and a
// non-multipart message has a nil path (instead of {1}).
//
// If an error is returned, processing stops.
type WalkFunc func(path []int, entity *Entity, err error) error

// Walk walks the entity's multipart tree, calling walkFunc for each part in
// the tree, including the root entity.
//
// Walk consumes the entity.
func (e *Entity) Walk(walkFunc WalkFunc) error {
	var multipartReaders []MultipartReader
	var path []int
	part := e
	for {
		var err error
		if part == nil {
			if len(multipartReaders) == 0 {
				break
			}

			// Get the next part from the last multipart reader
			mr := multipartReaders[len(multipartReaders)-1]
			part, err = mr.NextPart()
			if err == io.EOF {
				multipartReaders = multipartReaders[:len(multipartReaders)-1]
				path = path[:len(path)-1]
				continue
			} else if IsUnknownEncoding(err) || IsUnknownCharset(err) {
				// Forward the error to walkFunc
			} else if err != nil {
				return err
			}

			path[len(path)-1]++
		}

		// Copy the path since we'll mutate it on the next iteration
		var pathCopy []int
		if len(path) > 0 {
			pathCopy = make([]int, len(path))
			copy(pathCopy, path)
		}

		if err := walkFunc(pathCopy, part, err); err != nil {
			return err
		}

		if mr := part.MultipartReader(); mr != nil {
			multipartReaders = append(multipartReaders, mr)
			path = append(path, -1)
		}

		part = nil
	}

	return nil
}
<commit_msg>Improve ReadOptions docs<commit_after>package message

import (
	"bufio"
	"errors"
	"io"
	"math"
	"strings"

	"github.com/emersion/go-message/textproto"
)

// An Entity is either a whole message or a one of the parts in the body of a
// multipart entity.
type Entity struct {
	Header Header    // The entity's header.
	Body   io.Reader // The decoded entity's body.

	mediaType   string
	mediaParams map[string]string
}

// New makes a new message with the provided header and body. The entity's
// transfer encoding and charset are automatically decoded to UTF-8.
//
// If the message uses an unknown transfer encoding or charset, New returns an
// error that verifies IsUnknownCharset, but also returns an Entity that can
// be read.
func New(header Header, body io.Reader) (*Entity, error) {
	var err error

	mediaType, mediaParams, _ := header.ContentType()

	// QUIRK: RFC 2045 section 6.4 specifies that multipart messages can't have
	// a Content-Transfer-Encoding other than "7bit", "8bit" or "binary".
	// However some messages in the wild are non-conformant and have it set to
	// e.g. "quoted-printable". So we just ignore it for multipart.
	// See https://github.com/emersion/go-message/issues/48
	if !strings.HasPrefix(mediaType, "multipart/") {
		enc := header.Get("Content-Transfer-Encoding")
		if decoded, encErr := encodingReader(enc, body); encErr != nil {
			err = UnknownEncodingError{encErr}
		} else {
			body = decoded
		}
	}

	// RFC 2046 section 4.1.2: charset only applies to text/*
	if strings.HasPrefix(mediaType, "text/") {
		if ch, ok := mediaParams["charset"]; ok {
			if converted, charsetErr := charsetReader(ch, body); charsetErr != nil {
				err = UnknownCharsetError{charsetErr}
			} else {
				body = converted
			}
		}
	}

	return &Entity{
		Header:      header,
		Body:        body,
		mediaType:   mediaType,
		mediaParams: mediaParams,
	}, err
}

// NewMultipart makes a new multipart message with the provided header and
// parts. The Content-Type header must begin with "multipart/".
//
// If the message uses an unknown transfer encoding, NewMultipart returns an
// error that verifies IsUnknownCharset, but also returns an Entity that can
// be read.
func NewMultipart(header Header, parts []*Entity) (*Entity, error) {
	r := &multipartBody{
		header: header,
		parts:  parts,
	}

	return New(header, r)
}

const defaultMaxHeaderBytes = 1 << 20 // 1 MB

var errHeaderTooBig = errors.New("message: header exceeds maximum size")

// limitedReader is the same as io.LimitedReader, but returns a custom error.
type limitedReader struct {
	R io.Reader
	N int64
}

func (lr *limitedReader) Read(p []byte) (int, error) {
	if lr.N <= 0 {
		return 0, errHeaderTooBig
	}
	if int64(len(p)) > lr.N {
		p = p[0:lr.N]
	}
	n, err := lr.R.Read(p)
	lr.N -= int64(n)
	return n, err
}

// ReadOptions are options for ReadWithOptions.
type ReadOptions struct {
	// MaxHeaderBytes limits the maximum permissible size of a message header
	// block. If exceeded, an error will be returned.
	//
	// Set to -1 for no limit, set to 0 for the default value (1MB).
	MaxHeaderBytes int64
}

// withDefaults returns a sanitised version of the options with defaults/special
// values accounted for.
func (o *ReadOptions) withDefaults() *ReadOptions {
	var out ReadOptions
	if o != nil {
		out = *o
	}
	if out.MaxHeaderBytes == 0 {
		out.MaxHeaderBytes = defaultMaxHeaderBytes
	} else if out.MaxHeaderBytes < 0 {
		out.MaxHeaderBytes = math.MaxInt64
	}
	return &out
}

// ReadWithOptions see Read, but allows overriding some parameters with
// ReadOptions.
//
// If the message uses an unknown transfer encoding or charset, ReadWithOptions
// returns an error that verifies IsUnknownCharset or IsUnknownEncoding, but
// also returns an Entity that can be read.
func ReadWithOptions(r io.Reader, opts *ReadOptions) (*Entity, error) {
	opts = opts.withDefaults()

	lr := &limitedReader{R: r, N: opts.MaxHeaderBytes}
	br := bufio.NewReader(lr)

	h, err := textproto.ReadHeader(br)
	if err != nil {
		return nil, err
	}

	lr.N = math.MaxInt64

	return New(Header{h}, br)
}

// Read reads a message from r. The message's encoding and charset are
// automatically decoded to raw UTF-8. Note that this function only reads the
// message header.
//
// If the message uses an unknown transfer encoding or charset, Read returns an
// error that verifies IsUnknownCharset or IsUnknownEncoding, but also returns
// an Entity that can be read.
func Read(r io.Reader) (*Entity, error) {
	return ReadWithOptions(r, nil)
}

// MultipartReader returns a MultipartReader that reads parts from this entity's
// body. If this entity is not multipart, it returns nil.
func (e *Entity) MultipartReader() MultipartReader {
	if !strings.HasPrefix(e.mediaType, "multipart/") {
		return nil
	}
	if mb, ok := e.Body.(*multipartBody); ok {
		return mb
	}
	return &multipartReader{textproto.NewMultipartReader(e.Body, e.mediaParams["boundary"])}
}

// writeBodyTo writes this entity's body to w (without the header).
func (e *Entity) writeBodyTo(w *Writer) error {
	var err error
	if mb, ok := e.Body.(*multipartBody); ok {
		err = mb.writeBodyTo(w)
	} else {
		_, err = io.Copy(w, e.Body)
	}
	return err
}

// WriteTo writes this entity's header and body to w.
func (e *Entity) WriteTo(w io.Writer) error {
	ew, err := CreateWriter(w, e.Header)
	if err != nil {
		return err
	}
	defer ew.Close()

	return e.writeBodyTo(ew)
}

// WalkFunc is the type of the function called for each part visited by Walk.
//
// The path argument is a list of multipart indices leading to the part. The
// root part has a nil path.
//
// If there was an encoding error walking to a part, the incoming error will
// describe the problem and the function can decide how to handle that error.
//
// Unlike IMAP part paths, indices start from 0 (instead of 1) and a
// non-multipart message has a nil path (instead of {1}).
//
// If an error is returned, processing stops.
type WalkFunc func(path []int, entity *Entity, err error) error

// Walk walks the entity's multipart tree, calling walkFunc for each part in
// the tree, including the root entity.
//
// Walk consumes the entity.
func (e *Entity) Walk(walkFunc WalkFunc) error {
	var multipartReaders []MultipartReader
	var path []int
	part := e
	for {
		var err error
		if part == nil {
			if len(multipartReaders) == 0 {
				break
			}

			// Get the next part from the last multipart reader
			mr := multipartReaders[len(multipartReaders)-1]
			part, err = mr.NextPart()
			if err == io.EOF {
				multipartReaders = multipartReaders[:len(multipartReaders)-1]
				path = path[:len(path)-1]
				continue
			} else if IsUnknownEncoding(err) || IsUnknownCharset(err) {
				// Forward the error to walkFunc
			} else if err != nil {
				return err
			}

			path[len(path)-1]++
		}

		// Copy the path since we'll mutate it on the next iteration
		var pathCopy []int
		if len(path) > 0 {
			pathCopy = make([]int, len(path))
			copy(pathCopy, path)
		}

		if err := walkFunc(pathCopy, part, err); err != nil {
			return err
		}

		if mr := part.MultipartReader(); mr != nil {
			multipartReaders = append(multipartReaders, mr)
			path = append(path, -1)
		}

		part = nil
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	return &equalsMatcher{x}
}

type equalsMatcher struct {
	expected interface{}
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstUint64(e uint64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		i := c.Int()
		if i >= 0 && uint64(i) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if c.Uint() == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	ck := c.Kind()

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	// If the actual value is lower precision, turn the comparison around so we
	// apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match
	// float32(0.1).
	case ck == reflect.Float32 || ck == reflect.Complex64:
		return Equals(c.Interface()).Matches(e)

  // Otherwise, compare with double precision.
	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Other types
////////////////////////////////////////////////////////////

func checkAgainstBool(e bool, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Bool {
		res = MATCH_UNDEFINED
		err = "which is not a bool"
		return
	}

	res = MATCH_FALSE
	if c.Bool() == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUintptr(e uintptr, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Uintptr {
		res = MATCH_UNDEFINED
		err = "which is not a uintptr"
		return
	}

	res = MATCH_FALSE
	if uintptr(c.Uint()) == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstChan(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Create a description of e's type, e.g. "chan int".
	typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem())

	// Make sure c is a chan of the correct type.
	if c.Kind() != reflect.Chan ||
	   c.Type().ChanDir() != e.Type().ChanDir() ||
		 c.Type().Elem() != e.Type().Elem() {
		res = MATCH_UNDEFINED
		err = fmt.Sprintf("which is not a %s", typeStr)
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := reflect.ValueOf(m.expected)
	c := reflect.ValueOf(candidate)
	ek := e.Kind()

	switch {
	case ek == reflect.Bool:
		return checkAgainstBool(e.Bool(), c)

	case isSignedInteger(e):
		return checkAgainstInt64(e.Int(), c)

	case isUnsignedInteger(e):
		return checkAgainstUint64(e.Uint(), c)

	case ek == reflect.Uintptr:
		return checkAgainstUintptr(uintptr(e.Uint()), c)

	case ek == reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case ek == reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case ek == reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case ek == reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)

	case ek == reflect.Chan:
		return checkAgainstChan(e, c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expected)
}
<commit_msg>Refactored a bit.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	return &equalsMatcher{reflect.ValueOf(x)}
}

type equalsMatcher struct {
	expectedValue reflect.Value
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstUint64(e uint64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		i := c.Int()
		if i >= 0 && uint64(i) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if c.Uint() == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	ck := c.Kind()

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	// If the actual value is lower precision, turn the comparison around so we
	// apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match
	// float32(0.1).
	case ck == reflect.Float32 || ck == reflect.Complex64:
		return Equals(c.Interface()).Matches(e)

  // Otherwise, compare with double precision.
	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Other types
////////////////////////////////////////////////////////////

func checkAgainstBool(e bool, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Bool {
		res = MATCH_UNDEFINED
		err = "which is not a bool"
		return
	}

	res = MATCH_FALSE
	if c.Bool() == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUintptr(e uintptr, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Uintptr {
		res = MATCH_UNDEFINED
		err = "which is not a uintptr"
		return
	}

	res = MATCH_FALSE
	if uintptr(c.Uint()) == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstChan(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Create a description of e's type, e.g. "chan int".
	typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem())

	// Make sure c is a chan of the correct type.
	if c.Kind() != reflect.Chan ||
	   c.Type().ChanDir() != e.Type().ChanDir() ||
		 c.Type().Elem() != e.Type().Elem() {
		res = MATCH_UNDEFINED
		err = fmt.Sprintf("which is not a %s", typeStr)
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := m.expectedValue
	c := reflect.ValueOf(candidate)
	ek := e.Kind()

	switch {
	case ek == reflect.Bool:
		return checkAgainstBool(e.Bool(), c)

	case isSignedInteger(e):
		return checkAgainstInt64(e.Int(), c)

	case isUnsignedInteger(e):
		return checkAgainstUint64(e.Uint(), c)

	case ek == reflect.Uintptr:
		return checkAgainstUintptr(uintptr(e.Uint()), c)

	case ek == reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case ek == reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case ek == reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case ek == reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)

	case ek == reflect.Chan:
		return checkAgainstChan(e, c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expectedValue.Interface())
}
<|endoftext|>


<commit_before>package stats

type statsErr struct {
	err string
}

func (s statsErr) Error() string {
	return s.err
}

// These are the package-wide error values.
// All error identification should use these values.
var (
	EmptyInput  = statsErr{"Imput must not be empty."}
	SampleSize  = statsErr{"Samples number must be less than input length."}
	NaNErr      = statsErr{"Not a number"}
	NegativeErr = statsErr{"Slice must not contain negative values."}
	ZeroErr     = statsErr{"Slice must not contain zero values."}
	BoundsErr   = statsErr{"Input is outside of range."}
	SizeErr     = statsErr{"Slices must be the same length."}
)
<commit_msg>Imput -> Input<commit_after>package stats

type statsErr struct {
	err string
}

func (s statsErr) Error() string {
	return s.err
}

// These are the package-wide error values.
// All error identification should use these values.
var (
	EmptyInput  = statsErr{"Input must not be empty."}
	SampleSize  = statsErr{"Samples number must be less than input length."}
	NaNErr      = statsErr{"Not a number"}
	NegativeErr = statsErr{"Slice must not contain negative values."}
	ZeroErr     = statsErr{"Slice must not contain zero values."}
	BoundsErr   = statsErr{"Input is outside of range."}
	SizeErr     = statsErr{"Slices must be the same length."}
)
<|endoftext|>


<commit_before>package minecraft

import (
	"fmt"
	"github.com/MJKWoolnough/minecraft/nbt"
)

type MissingTagError struct {
	TagName string
}

func (m MissingTagError) Error() string {
	return fmt.Sprintf("minecraft: missing %q tag", m.TagName)
}

type WrongTypeError struct {
	TagName        string
	Expecting, Got nbt.TagId
}

func (w WrongTypeError) Error() string {
	return fmt.Sprintf("minecraft: tag %q is of incorrect type, expecting %q, got %q", w.TagName, w.Expecting, w.Got)
}

type OOB struct{}

func (OOB) Error() string {
	return "Received Out-of-bounds error"
}

type UnexpectedValue struct {
	TagName, Expecting, Got string
}

func (u UnexpectedValue) Error() string {
	return fmt.Sprintf("minecraft: tag %q was expecting %s, but got %q", u.TagName, u.Expecting, u.Got)
}

type UnknownCompression struct {
	Code byte
}

func (u UnknownCompression) Error() string {
	return fmt.Sprintf("unknown compression code: %d", u.Code)
}

type ExpectedData struct{}

func (ExpectedData) Error() string {
	return "received nil data stream where non-nil was expected."
}

type NoLock struct{}

func (NoLock) Error() string {
	return "lost lock on files"
}

type ConflictError struct {
	X, Z int32
}

func (c ConflictError) Error() string {
	return fmt.Sprintf("already setting chunk %d,%d, recall SetChunk to set again", c.X, c.Z)
}

type FilePathSetError struct {
	X, Z int32
	Err  error
}

func (f *FilePathSetError) Error() string {
	return fmt.Sprintf("chunk %d, %d had the following error: %s", f.X, f.Z, f.Err.Error())
}

type MultiError struct {
	Errors []error
}

func (m *MultiError) Error() string {
	if len(m.Errors) == 1 {
		return Errors[0].Error()
	}
	return fmt.Sprintf("received %d errors", len(m.Errors))
}
<commit_msg>Corrected bug in errors<commit_after>package minecraft

import (
	"fmt"
	"github.com/MJKWoolnough/minecraft/nbt"
)

type MissingTagError struct {
	TagName string
}

func (m MissingTagError) Error() string {
	return fmt.Sprintf("minecraft: missing %q tag", m.TagName)
}

type WrongTypeError struct {
	TagName        string
	Expecting, Got nbt.TagId
}

func (w WrongTypeError) Error() string {
	return fmt.Sprintf("minecraft: tag %q is of incorrect type, expecting %q, got %q", w.TagName, w.Expecting, w.Got)
}

type OOB struct{}

func (OOB) Error() string {
	return "Received Out-of-bounds error"
}

type UnexpectedValue struct {
	TagName, Expecting, Got string
}

func (u UnexpectedValue) Error() string {
	return fmt.Sprintf("minecraft: tag %q was expecting %s, but got %q", u.TagName, u.Expecting, u.Got)
}

type UnknownCompression struct {
	Code byte
}

func (u UnknownCompression) Error() string {
	return fmt.Sprintf("unknown compression code: %d", u.Code)
}

type ExpectedData struct{}

func (ExpectedData) Error() string {
	return "received nil data stream where non-nil was expected."
}

type NoLock struct{}

func (NoLock) Error() string {
	return "lost lock on files"
}

type ConflictError struct {
	X, Z int32
}

func (c ConflictError) Error() string {
	return fmt.Sprintf("already setting chunk %d,%d, recall SetChunk to set again", c.X, c.Z)
}

type FilePathSetError struct {
	X, Z int32
	Err  error
}

func (f *FilePathSetError) Error() string {
	return fmt.Sprintf("chunk %d, %d had the following error: %s", f.X, f.Z, f.Err.Error())
}

type MultiError struct {
	Errors []error
}

func (m *MultiError) Error() string {
	if len(m.Errors) == 1 {
		return m.Errors[0].Error()
	}
	return fmt.Sprintf("received %d errors", len(m.Errors))
}
<|endoftext|>


<commit_before>package bbs

type Error struct {
	Type    string `json:"name"`
	Message string `json:"message"`
}

func (err Error) Error() string {
	return err.Message
}

const (
	InvalidDomain = "InvalidDomain"

	InvalidJSON     = "InvalidJSON"
	InvalidRequest  = "InvalidRequest"
	InvalidResponse = "InvalidResponse"

	UnknownError = "UnknownError"
	Unauthorized = "Unauthorized"

	ActualLRPIndexNotFound = "ActualLRPIndexNotFound"

	ResourceConflict = "ResourceConflict"
	RouterError      = "RouterError"
)
<commit_msg>Removed unused LRP error<commit_after>package bbs

type Error struct {
	Type    string `json:"name"`
	Message string `json:"message"`
}

func (err Error) Error() string {
	return err.Message
}

const (
	InvalidDomain = "InvalidDomain"

	InvalidJSON     = "InvalidJSON"
	InvalidRequest  = "InvalidRequest"
	InvalidResponse = "InvalidResponse"

	UnknownError = "UnknownError"
	Unauthorized = "Unauthorized"

	ResourceConflict = "ResourceConflict"
	RouterError      = "RouterError"
)
<|endoftext|>


<commit_before>package oauthutil

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/ncw/rclone/fs"
	"github.com/skratchdot/open-golang/open"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
)

const (
	// TitleBarRedirectURL is the OAuth2 redirect URL to use when the authorization
	// code should be returned in the title bar of the browser, with the page text
	// prompting the user to copy the code and paste it in the application.
	TitleBarRedirectURL = "urn:ietf:wg:oauth:2.0:oob"

	// bindPort is the port that we bind the local webserver to
	bindPort = "53682"

	// bindAddress is binding for local webserver when active
	bindAddress = "127.0.0.1:" + bindPort

	// RedirectURL is redirect to local webserver when active
	RedirectURL = "http://" + bindAddress + "/"

	// RedirectPublicURL is redirect to local webserver when active with public name
	RedirectPublicURL = "http://localhost.rclone.org:" + bindPort + "/"

	// RedirectLocalhostURL is redirect to local webserver when active with localhost
	RedirectLocalhostURL = "http://localhost:" + bindPort + "/"
)

// oldToken contains an end-user's tokens.
// This is the data you must store to persist authentication.
//
// From the original code.google.com/p/goauth2/oauth package - used
// for backwards compatibility in the rclone config file
type oldToken struct {
	AccessToken  string
	RefreshToken string
	Expiry       time.Time
}

// getToken returns the token saved in the config file under
// section name.
func getToken(name string) (*oauth2.Token, error) {
	tokenString, err := fs.ConfigFile.GetValue(string(name), fs.ConfigToken)
	if err != nil {
		return nil, err
	}
	if tokenString == "" {
		return nil, fmt.Errorf("Empty token found - please run rclone config again")
	}
	token := new(oauth2.Token)
	err = json.Unmarshal([]byte(tokenString), token)
	if err != nil {
		return nil, err
	}
	// if has data then return it
	if token.AccessToken != "" && token.RefreshToken != "" {
		return token, nil
	}
	// otherwise try parsing as oldToken
	oldtoken := new(oldToken)
	err = json.Unmarshal([]byte(tokenString), oldtoken)
	if err != nil {
		return nil, err
	}
	// Fill in result into new token
	token.AccessToken = oldtoken.AccessToken
	token.RefreshToken = oldtoken.RefreshToken
	token.Expiry = oldtoken.Expiry
	// Save new format in config file
	err = putToken(name, token)
	if err != nil {
		return nil, err
	}
	return token, nil
}

// putToken stores the token in the config file
//
// This saves the config file if it changes
func putToken(name string, token *oauth2.Token) error {
	tokenBytes, err := json.Marshal(token)
	if err != nil {
		return err
	}
	tokenString := string(tokenBytes)
	old := fs.ConfigFile.MustValue(name, fs.ConfigToken)
	if tokenString != old {
		fs.ConfigFile.SetValue(name, fs.ConfigToken, tokenString)
		fs.SaveConfig()
		fs.Debug(name, "Saving new token in config file")
	}
	return nil
}

// tokenSource stores updated tokens in the config file
type tokenSource struct {
	Name        string
	TokenSource oauth2.TokenSource
	OldToken    oauth2.Token
}

// Token returns a token or an error.
// Token must be safe for concurrent use by multiple goroutines.
// The returned Token must not be modified.
//
// This saves the token in the config file if it has changed
func (ts *tokenSource) Token() (*oauth2.Token, error) {
	token, err := ts.TokenSource.Token()
	if err != nil {
		return nil, err
	}
	if *token != ts.OldToken {
		err = putToken(ts.Name, token)
		if err != nil {
			return nil, err
		}
	}
	return token, nil
}

// Check interface satisfied
var _ oauth2.TokenSource = (*tokenSource)(nil)

// Context returns a context with our HTTP Client baked in for oauth2
func Context() context.Context {
	return context.WithValue(nil, oauth2.HTTPClient, fs.Config.Client())
}

// overrideCredentials sets the ClientID and ClientSecret from the
// config file if they are not blank.
// If any value is overridden, true is returned.
func overrideCredentials(name string, config *oauth2.Config) bool {
	changed := false
	ClientID := fs.ConfigFile.MustValue(name, fs.ConfigClientID)
	if ClientID != "" {
		config.ClientID = ClientID
		changed = true
	}
	ClientSecret := fs.ConfigFile.MustValue(name, fs.ConfigClientSecret)
	if ClientSecret != "" {
		config.ClientSecret = ClientSecret
		changed = true
	}
	return changed
}

// NewClient gets a token from the config file and configures a Client
// with it
func NewClient(name string, config *oauth2.Config) (*http.Client, error) {
	overrideCredentials(name, config)
	token, err := getToken(name)
	if err != nil {
		return nil, err
	}

	// Set our own http client in the context
	ctx := Context()

	// Wrap the TokenSource in our TokenSource which saves changed
	// tokens in the config file
	ts := &tokenSource{
		Name:        name,
		OldToken:    *token,
		TokenSource: config.TokenSource(ctx, token),
	}
	return oauth2.NewClient(ctx, ts), nil

}

// Config does the initial creation of the token
//
// It may run an internal webserver to receive the results
func Config(id, name string, config *oauth2.Config) error {
	changed := overrideCredentials(name, config)
	automatic := fs.ConfigFile.MustValue(name, fs.ConfigAutomatic) != ""

	// See if already have a token
	tokenString := fs.ConfigFile.MustValue(name, "token")
	if tokenString != "" {
		fmt.Printf("Already have a token - refresh?\n")
		if !fs.Confirm() {
			return nil
		}
	}

	// Detect whether we should use internal web server
	useWebServer := false
	switch config.RedirectURL {
	case RedirectURL, RedirectPublicURL, RedirectLocalhostURL:
		useWebServer = true
		if automatic {
			break
		}
		fmt.Printf("Use auto config?\n")
		fmt.Printf(" * Say Y if not sure\n")
		fmt.Printf(" * Say N if you are working on a remote or headless machine\n")
		auto := fs.Confirm()
		if !auto {
			fmt.Printf("For this to work, you will need rclone available on a machine that has a web browser available.\n")
			fmt.Printf("Execute the following on your machine:\n")
			if changed {
				fmt.Printf("\trclone authorize %q %q %q\n", id, config.ClientID, config.ClientSecret)
			} else {
				fmt.Printf("\trclone authorize %q\n", id)
			}
			fmt.Println("Then paste the result below:")
			code := ""
			for code == "" {
				fmt.Printf("result> ")
				code = strings.TrimSpace(fs.ReadLine())
			}
			token := &oauth2.Token{}
			err := json.Unmarshal([]byte(code), token)
			if err != nil {
				return err
			}
			return putToken(name, token)
		}
	case TitleBarRedirectURL:
		useWebServer = automatic
		if !automatic {
			fmt.Printf("Use auto config?\n")
			fmt.Printf(" * Say Y if not sure\n")
			fmt.Printf(" * Say N if you are working on a remote or headless machine or Y didn't work\n")
			useWebServer = fs.Confirm()
		}
		if useWebServer {
			// copy the config and set to use the internal webserver
			configCopy := *config
			config = &configCopy
			config.RedirectURL = RedirectURL
		}
	}

	// Make random state
	stateBytes := make([]byte, 16)
	_, err := rand.Read(stateBytes)
	if err != nil {
		return err
	}
	state := fmt.Sprintf("%x", stateBytes)
	authURL := config.AuthCodeURL(state)

	// Prepare webserver
	server := authServer{
		state:       state,
		bindAddress: bindAddress,
		authURL:     authURL,
	}
	if useWebServer {
		server.code = make(chan string, 1)
		go server.Start()
		defer server.Stop()
		authURL = "http://" + bindAddress + "/auth"
	}

	// Generate a URL for the user to visit for authorization.
	_ = open.Start(authURL)
	fmt.Printf("If your browser doesn't open automatically go to the following link: %s\n", authURL)
	fmt.Printf("Log in and authorize rclone for access\n")

	var authCode string
	if useWebServer {
		// Read the code, and exchange it for a token.
		fmt.Printf("Waiting for code...\n")
		authCode = <-server.code
		if authCode != "" {
			fmt.Printf("Got code\n")
		} else {
			return fmt.Errorf("Failed to get code")
		}
	} else {
		// Read the code, and exchange it for a token.
		fmt.Printf("Enter verification code> ")
		authCode = fs.ReadLine()
	}
	token, err := config.Exchange(oauth2.NoContext, authCode)
	if err != nil {
		return fmt.Errorf("Failed to get token: %v", err)
	}

	// Print code if we do automatic retrieval
	if automatic {
		result, err := json.Marshal(token)
		if err != nil {
			return fmt.Errorf("Failed to marshal token: %v", err)
		}
		fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste", result)
	}
	return putToken(name, token)
}

// Local web server for collecting auth
type authServer struct {
	state       string
	listener    net.Listener
	bindAddress string
	code        chan string
	authURL     string
}

// startWebServer runs an internal web server to receive config details
func (s *authServer) Start() {
	fs.Debug(nil, "Starting auth server on %s", s.bindAddress)
	mux := http.NewServeMux()
	server := &http.Server{
		Addr:    s.bindAddress,
		Handler: mux,
	}
	mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, req *http.Request) {
		http.Error(w, "", 404)
		return
	})
	mux.HandleFunc("/auth", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, s.authURL, 307)
		return
	})
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		fs.Debug(nil, "Received request on auth server")
		code := req.FormValue("code")
		if code != "" {
			state := req.FormValue("state")
			if state != s.state {
				fs.Debug(nil, "State did not match: want %q got %q", s.state, state)
				fmt.Fprintf(w, "
Failure
\n
Auth state doesn't match
")
			} else {
				fs.Debug(nil, "Successfully got code")
				if s.code != nil {
					fmt.Fprintf(w, "
Success
\n
Go back to rclone to continue
")
					s.code <- code
				} else {
					fmt.Fprintf(w, "
Success
\n
Cut and paste this code into rclone: %s
", code)
				}
			}
			return
		}
		fs.Debug(nil, "No code found on request")
		fmt.Fprintf(w, "
Failed!
\nNo code found.")
		http.Error(w, "", 500)
	})

	var err error
	s.listener, err = net.Listen("tcp", s.bindAddress)
	if err != nil {
		log.Fatalf("Failed to start auth webserver: %v", err)
	}
	err = server.Serve(s.listener)
	fs.Debug(nil, "Closed auth server with error: %v", err)
}

func (s *authServer) Stop() {
	fs.Debug(nil, "Closing auth server")
	if s.code != nil {
		close(s.code)
		s.code = nil
	}
	_ = s.listener.Close()
}
<commit_msg>Disable keepalive to keep server from serving stale results.<commit_after>package oauthutil

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/ncw/rclone/fs"
	"github.com/skratchdot/open-golang/open"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
)

const (
	// TitleBarRedirectURL is the OAuth2 redirect URL to use when the authorization
	// code should be returned in the title bar of the browser, with the page text
	// prompting the user to copy the code and paste it in the application.
	TitleBarRedirectURL = "urn:ietf:wg:oauth:2.0:oob"

	// bindPort is the port that we bind the local webserver to
	bindPort = "53682"

	// bindAddress is binding for local webserver when active
	bindAddress = "127.0.0.1:" + bindPort

	// RedirectURL is redirect to local webserver when active
	RedirectURL = "http://" + bindAddress + "/"

	// RedirectPublicURL is redirect to local webserver when active with public name
	RedirectPublicURL = "http://localhost.rclone.org:" + bindPort + "/"

	// RedirectLocalhostURL is redirect to local webserver when active with localhost
	RedirectLocalhostURL = "http://localhost:" + bindPort + "/"
)

// oldToken contains an end-user's tokens.
// This is the data you must store to persist authentication.
//
// From the original code.google.com/p/goauth2/oauth package - used
// for backwards compatibility in the rclone config file
type oldToken struct {
	AccessToken  string
	RefreshToken string
	Expiry       time.Time
}

// getToken returns the token saved in the config file under
// section name.
func getToken(name string) (*oauth2.Token, error) {
	tokenString, err := fs.ConfigFile.GetValue(string(name), fs.ConfigToken)
	if err != nil {
		return nil, err
	}
	if tokenString == "" {
		return nil, fmt.Errorf("Empty token found - please run rclone config again")
	}
	token := new(oauth2.Token)
	err = json.Unmarshal([]byte(tokenString), token)
	if err != nil {
		return nil, err
	}
	// if has data then return it
	if token.AccessToken != "" && token.RefreshToken != "" {
		return token, nil
	}
	// otherwise try parsing as oldToken
	oldtoken := new(oldToken)
	err = json.Unmarshal([]byte(tokenString), oldtoken)
	if err != nil {
		return nil, err
	}
	// Fill in result into new token
	token.AccessToken = oldtoken.AccessToken
	token.RefreshToken = oldtoken.RefreshToken
	token.Expiry = oldtoken.Expiry
	// Save new format in config file
	err = putToken(name, token)
	if err != nil {
		return nil, err
	}
	return token, nil
}

// putToken stores the token in the config file
//
// This saves the config file if it changes
func putToken(name string, token *oauth2.Token) error {
	tokenBytes, err := json.Marshal(token)
	if err != nil {
		return err
	}
	tokenString := string(tokenBytes)
	old := fs.ConfigFile.MustValue(name, fs.ConfigToken)
	if tokenString != old {
		fs.ConfigFile.SetValue(name, fs.ConfigToken, tokenString)
		fs.SaveConfig()
		fs.Debug(name, "Saving new token in config file")
	}
	return nil
}

// tokenSource stores updated tokens in the config file
type tokenSource struct {
	Name        string
	TokenSource oauth2.TokenSource
	OldToken    oauth2.Token
}

// Token returns a token or an error.
// Token must be safe for concurrent use by multiple goroutines.
// The returned Token must not be modified.
//
// This saves the token in the config file if it has changed
func (ts *tokenSource) Token() (*oauth2.Token, error) {
	token, err := ts.TokenSource.Token()
	if err != nil {
		return nil, err
	}
	if *token != ts.OldToken {
		err = putToken(ts.Name, token)
		if err != nil {
			return nil, err
		}
	}
	return token, nil
}

// Check interface satisfied
var _ oauth2.TokenSource = (*tokenSource)(nil)

// Context returns a context with our HTTP Client baked in for oauth2
func Context() context.Context {
	return context.WithValue(nil, oauth2.HTTPClient, fs.Config.Client())
}

// overrideCredentials sets the ClientID and ClientSecret from the
// config file if they are not blank.
// If any value is overridden, true is returned.
func overrideCredentials(name string, config *oauth2.Config) bool {
	changed := false
	ClientID := fs.ConfigFile.MustValue(name, fs.ConfigClientID)
	if ClientID != "" {
		config.ClientID = ClientID
		changed = true
	}
	ClientSecret := fs.ConfigFile.MustValue(name, fs.ConfigClientSecret)
	if ClientSecret != "" {
		config.ClientSecret = ClientSecret
		changed = true
	}
	return changed
}

// NewClient gets a token from the config file and configures a Client
// with it
func NewClient(name string, config *oauth2.Config) (*http.Client, error) {
	overrideCredentials(name, config)
	token, err := getToken(name)
	if err != nil {
		return nil, err
	}

	// Set our own http client in the context
	ctx := Context()

	// Wrap the TokenSource in our TokenSource which saves changed
	// tokens in the config file
	ts := &tokenSource{
		Name:        name,
		OldToken:    *token,
		TokenSource: config.TokenSource(ctx, token),
	}
	return oauth2.NewClient(ctx, ts), nil

}

// Config does the initial creation of the token
//
// It may run an internal webserver to receive the results
func Config(id, name string, config *oauth2.Config) error {
	changed := overrideCredentials(name, config)
	automatic := fs.ConfigFile.MustValue(name, fs.ConfigAutomatic) != ""

	// See if already have a token
	tokenString := fs.ConfigFile.MustValue(name, "token")
	if tokenString != "" {
		fmt.Printf("Already have a token - refresh?\n")
		if !fs.Confirm() {
			return nil
		}
	}

	// Detect whether we should use internal web server
	useWebServer := false
	switch config.RedirectURL {
	case RedirectURL, RedirectPublicURL, RedirectLocalhostURL:
		useWebServer = true
		if automatic {
			break
		}
		fmt.Printf("Use auto config?\n")
		fmt.Printf(" * Say Y if not sure\n")
		fmt.Printf(" * Say N if you are working on a remote or headless machine\n")
		auto := fs.Confirm()
		if !auto {
			fmt.Printf("For this to work, you will need rclone available on a machine that has a web browser available.\n")
			fmt.Printf("Execute the following on your machine:\n")
			if changed {
				fmt.Printf("\trclone authorize %q %q %q\n", id, config.ClientID, config.ClientSecret)
			} else {
				fmt.Printf("\trclone authorize %q\n", id)
			}
			fmt.Println("Then paste the result below:")
			code := ""
			for code == "" {
				fmt.Printf("result> ")
				code = strings.TrimSpace(fs.ReadLine())
			}
			token := &oauth2.Token{}
			err := json.Unmarshal([]byte(code), token)
			if err != nil {
				return err
			}
			return putToken(name, token)
		}
	case TitleBarRedirectURL:
		useWebServer = automatic
		if !automatic {
			fmt.Printf("Use auto config?\n")
			fmt.Printf(" * Say Y if not sure\n")
			fmt.Printf(" * Say N if you are working on a remote or headless machine or Y didn't work\n")
			useWebServer = fs.Confirm()
		}
		if useWebServer {
			// copy the config and set to use the internal webserver
			configCopy := *config
			config = &configCopy
			config.RedirectURL = RedirectURL
		}
	}

	// Make random state
	stateBytes := make([]byte, 16)
	_, err := rand.Read(stateBytes)
	if err != nil {
		return err
	}
	state := fmt.Sprintf("%x", stateBytes)
	authURL := config.AuthCodeURL(state)

	// Prepare webserver
	server := authServer{
		state:       state,
		bindAddress: bindAddress,
		authURL:     authURL,
	}
	if useWebServer {
		server.code = make(chan string, 1)
		go server.Start()
		defer server.Stop()
		authURL = "http://" + bindAddress + "/auth"
	}

	// Generate a URL for the user to visit for authorization.
	_ = open.Start(authURL)
	fmt.Printf("If your browser doesn't open automatically go to the following link: %s\n", authURL)
	fmt.Printf("Log in and authorize rclone for access\n")

	var authCode string
	if useWebServer {
		// Read the code, and exchange it for a token.
		fmt.Printf("Waiting for code...\n")
		authCode = <-server.code
		if authCode != "" {
			fmt.Printf("Got code\n")
		} else {
			return fmt.Errorf("Failed to get code")
		}
	} else {
		// Read the code, and exchange it for a token.
		fmt.Printf("Enter verification code> ")
		authCode = fs.ReadLine()
	}
	token, err := config.Exchange(oauth2.NoContext, authCode)
	if err != nil {
		return fmt.Errorf("Failed to get token: %v", err)
	}

	// Print code if we do automatic retrieval
	if automatic {
		result, err := json.Marshal(token)
		if err != nil {
			return fmt.Errorf("Failed to marshal token: %v", err)
		}
		fmt.Printf("Paste the following into your remote machine --->\n%s\n<---End paste", result)
	}
	return putToken(name, token)
}

// Local web server for collecting auth
type authServer struct {
	state       string
	listener    net.Listener
	bindAddress string
	code        chan string
	authURL     string
}

// startWebServer runs an internal web server to receive config details
func (s *authServer) Start() {
	fs.Debug(nil, "Starting auth server on %s", s.bindAddress)
	mux := http.NewServeMux()
	server := &http.Server{
		Addr:    s.bindAddress,
		Handler: mux,
	}
	server.SetKeepAlivesEnabled(false)
	mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, req *http.Request) {
		http.Error(w, "", 404)
		return
	})
	mux.HandleFunc("/auth", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, s.authURL, http.StatusTemporaryRedirect)
		return
	})
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		fs.Debug(nil, "Received request on auth server")
		code := req.FormValue("code")
		if code != "" {
			state := req.FormValue("state")
			if state != s.state {
				fs.Debug(nil, "State did not match: want %q got %q", s.state, state)
				fmt.Fprintf(w, "
Failure
\n
Auth state doesn't match
")
			} else {
				fs.Debug(nil, "Successfully got code")
				if s.code != nil {
					fmt.Fprintf(w, "
Success
\n
Go back to rclone to continue
")
					s.code <- code
				} else {
					fmt.Fprintf(w, "
Success
\n
Cut and paste this code into rclone: %s
", code)
				}
			}
			return
		}
		fs.Debug(nil, "No code found on request")
		w.WriteHeader(500)
		fmt.Fprintf(w, "
Failed!
\nNo code found returned by remote server.")

	})

	var err error
	s.listener, err = net.Listen("tcp", s.bindAddress)
	if err != nil {
		log.Fatalf("Failed to start auth webserver: %v", err)
	}
	err = server.Serve(s.listener)
	fs.Debug(nil, "Closed auth server with error: %v", err)
}

func (s *authServer) Stop() {
	fs.Debug(nil, "Closing auth server")
	if s.code != nil {
		close(s.code)
		s.code = nil
	}
	_ = s.listener.Close()
}
<|endoftext|>


<commit_before>// Copyright 2017 The Ebiten 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 clock manages game timers.
package clock

import (
	"sync"
	"time"
)

var (
	lastNow int64

	// lastSystemTime is the last system time in the previous Update.
	// lastSystemTime indicates the logical time in the game, so this can be bigger than the curren time.
	lastSystemTime int64

	currentFPS  float64
	currentTPS  float64
	lastTPS     int64
	tpsCalcErr  int64
	lastUpdated int64
	fpsCount    = 0
	tpsCount    = 0

	m sync.Mutex
)

func init() {
	n := now()
	lastNow = n
	lastSystemTime = n
	lastUpdated = n
}

func CurrentFPS() float64 {
	m.Lock()
	v := currentFPS
	m.Unlock()
	return v
}

func CurrentTPS() float64 {
	m.Lock()
	v := currentTPS
	m.Unlock()
	return v
}

func min(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

// calcTPSFactor calculates the TPS that is used for the timer and the factor for the count.
// newTPS × factor should be equal to tps on average.
// If tps is equal to or lower than the baseTPS, newTPS equals to tps. The factor is 1.
// This means that the timer precision should be already enough.
// Otherwise, newTPS is euqal to baseTPS. The factor can be more than 1.
func calcTPSFactor(tps, baseTPS int64) (newTPS int64, factor int) {
	if tps <= baseTPS {
		return tps, 1
	}

	if lastTPS != tps {
		tpsCalcErr = 0
	}
	lastTPS = tps

	factor = int(tps / baseTPS)
	tpsCalcErr += tps - baseTPS*int64(factor)

	factor += int(tpsCalcErr / baseTPS)
	tpsCalcErr %= baseTPS

	return baseTPS, factor
}

func calcCountFromTPS(tps int64, now int64) int {
	if tps == 0 {
		return 0
	}
	if tps < 0 {
		panic("clock: tps must >= 0")
	}

	diff := now - lastSystemTime
	if diff < 0 {
		return 0
	}

	count := 0
	syncWithSystemClock := false

	// When TPS is big (e.g. 300), the timer precision is no longer reliable.
	// Multiply the factor later instead (#1444).
	var tpsFactor int
	tps, tpsFactor = calcTPSFactor(tps, 60) // TODO: 60 should be the current display's FPS.

	if diff > int64(time.Second)*5/tps {
		// The previous time is too old.
		// Let's force to sync the game time with the system clock.
		syncWithSystemClock = true
	} else {
		count = int(diff * tps / int64(time.Second))
	}

	// Stabilize the count.
	// Without this adjustment, count can be unstable like 0, 2, 0, 2, ...
	// TODO: Brush up this logic so that this will work with any FPS. Now this works only when FPS = TPS.
	if count == 0 && (int64(time.Second)/tps/2) < diff {
		count = 1
	}
	if count == 2 && (int64(time.Second)/tps*3/2) > diff {
		count = 1
	}

	if syncWithSystemClock {
		lastSystemTime = now
	} else {
		lastSystemTime += int64(count) * int64(time.Second) / tps
	}

	return count * tpsFactor
}

func updateFPSAndTPS(now int64, count int) {
	fpsCount++
	tpsCount += count
	if now < lastUpdated {
		panic("clock: lastUpdated must be older than now")
	}
	if time.Second > time.Duration(now-lastUpdated) {
		return
	}
	currentFPS = float64(fpsCount) * float64(time.Second) / float64(now-lastUpdated)
	currentTPS = float64(tpsCount) * float64(time.Second) / float64(now-lastUpdated)
	lastUpdated = now
	fpsCount = 0
	tpsCount = 0
}

const UncappedTPS = -1

// Update updates the inner clock state and returns an integer value
// indicating how many times the game should update based on given tps.
// tps represents TPS (ticks per second).
// If tps is UncappedTPS, Update always returns 1.
// If tps <= 0 and not UncappedTPS, Update always returns 0.
//
// Update is expected to be called per frame.
func Update(tps int) int {
	m.Lock()
	defer m.Unlock()

	n := now()
	if lastNow > n {
		// This ensures that now() must be monotonic (#875).
		panic("clock: lastNow must be older than n")
	}
	lastNow = n

	c := 0
	if tps == UncappedTPS {
		c = 1
	} else if tps > 0 {
		c = calcCountFromTPS(int64(tps), n)
	}
	updateFPSAndTPS(n, c)

	return c
}
<commit_msg>internal/clock: Simplify the logic to calculate tick per frame<commit_after>// Copyright 2017 The Ebiten 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 clock manages game timers.
package clock

import (
	"sync"
	"time"
)

var (
	lastNow int64

	// lastSystemTime is the last system time in the previous Update.
	// lastSystemTime indicates the logical time in the game, so this can be bigger than the curren time.
	lastSystemTime int64

	currentFPS  float64
	currentTPS  float64
	lastUpdated int64
	fpsCount    = 0
	tpsCount    = 0

	m sync.Mutex
)

func init() {
	n := now()
	lastNow = n
	lastSystemTime = n
	lastUpdated = n
}

func CurrentFPS() float64 {
	m.Lock()
	v := currentFPS
	m.Unlock()
	return v
}

func CurrentTPS() float64 {
	m.Lock()
	v := currentTPS
	m.Unlock()
	return v
}

func max(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func calcCountFromTPS(tps int64, now int64) int {
	if tps == 0 {
		return 0
	}
	if tps < 0 {
		panic("clock: tps must >= 0")
	}

	diff := now - lastSystemTime
	if diff < 0 {
		return 0
	}

	count := 0
	syncWithSystemClock := false

	// Detect whether the previous time is too old.
	// Use either a 5 ticks or 5/60 sec in the case when TPS is too big like 300 (#1444).
	if diff > max(int64(time.Second)*5/tps, int64(time.Second)*5/60) {
		// The previous time is too old.
		// Let's force to sync the game time with the system clock.
		syncWithSystemClock = true
	} else {
		count = int(diff * tps / int64(time.Second))
	}

	// Stabilize the count.
	// Without this adjustment, count can be unstable like 0, 2, 0, 2, ...
	// TODO: Brush up this logic so that this will work with any FPS. Now this works only when FPS = TPS.
	if count == 0 && (int64(time.Second)/tps/2) < diff {
		count = 1
	}
	if count == 2 && (int64(time.Second)/tps*3/2) > diff {
		count = 1
	}

	if syncWithSystemClock {
		lastSystemTime = now
	} else {
		lastSystemTime += int64(count) * int64(time.Second) / tps
	}

	return count
}

func updateFPSAndTPS(now int64, count int) {
	fpsCount++
	tpsCount += count
	if now < lastUpdated {
		panic("clock: lastUpdated must be older than now")
	}
	if time.Second > time.Duration(now-lastUpdated) {
		return
	}
	currentFPS = float64(fpsCount) * float64(time.Second) / float64(now-lastUpdated)
	currentTPS = float64(tpsCount) * float64(time.Second) / float64(now-lastUpdated)
	lastUpdated = now
	fpsCount = 0
	tpsCount = 0
}

const UncappedTPS = -1

// Update updates the inner clock state and returns an integer value
// indicating how many times the game should update based on given tps.
// tps represents TPS (ticks per second).
// If tps is UncappedTPS, Update always returns 1.
// If tps <= 0 and not UncappedTPS, Update always returns 0.
//
// Update is expected to be called per frame.
func Update(tps int) int {
	m.Lock()
	defer m.Unlock()

	n := now()
	if lastNow > n {
		// This ensures that now() must be monotonic (#875).
		panic("clock: lastNow must be older than n")
	}
	lastNow = n

	c := 0
	if tps == UncappedTPS {
		c = 1
	} else if tps > 0 {
		c = calcCountFromTPS(int64(tps), n)
	}
	updateFPSAndTPS(n, c)

	return c
}
<|endoftext|>