<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/patrickmn/go-cache"
)

const (
	roleLowerBody        = "legislatorLowerBody"
	roleUpperBody        = "legislatorUpperBody"
	roleHeadOfGovernment = "headOfGovernment"
	roleLevelCountry     = "country"
	roleLevelState       = "administrativeArea1"
	areaHouse            = "House"
	areaSenate           = "Senate"
	areaGovernor         = "Governor"
)

var baseURL = "https://www.googleapis.com/civicinfo/v2/representatives"
var phoneRegex = regexp.MustCompile(`\((\d{3})\)\s+(\d{3})[\s\-](\d{4})`)
var roleLevel = [2]string{"country", "administrativeArea1"}

// RepFinder provides a mechanism to find local reps given an address.
type RepFinder interface {
	GetReps(address string) (*LocalReps, *Address, error)
}

// APIError is an error returned by the Google civic API, which also
// implements the error interface.
type APIError struct {
	Code    int
	Message string
	Errors  []struct {
		Domain  string
		Reason  string
		Message string
	}
}

func (ae *APIError) Error() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%d %s", ae.Code, ae.Message)
	for _, e := range ae.Errors {
		if e.Message != ae.Message { // don't duplicate messages
			fmt.Fprintf(&buf, ";[domain=%s, reason=%s: %s]", e.Domain, e.Reason, e.Message)
		}
	}
	return buf.String()
}

type Office struct {
	Name            string
	DivisionId      string
	Levels          []string
	Roles           []string
	OfficialIndices []int
}

type Official struct {
	Name     string
	Address  []Address
	Party    string
	Phones   []string
	PhotoUrl string
	Channels []struct {
		Id   string
		Type string
	}
}

// apiResponse is the response from the civic API. It encapsulates valid
// responses that set the normalized input, offices and officials,
// as well as error responses.
type apiResponse struct {
	NormalizedInput *Address
	Offices         []Office
	Officials       []Official
	Error           *APIError
}

// toLocalReps converts an API response to a set of local reps. In addition,
// it also returns the normalized address for which the response is valid.
func (r *apiResponse) toLocalReps() (*LocalReps, *Address, error) {
	if r.Error != nil {
		return nil, nil, r.Error
	}
	if len(r.Offices) == 0 {
		return nil, nil, fmt.Errorf("no offices found ")
	}
	ret := &LocalReps{}
	for _, o := range r.Offices {
		var area string
	AreaLoop:
		for _, level := range o.Levels {
			for _, role := range o.Roles {
				switch {
				case level == roleLevelCountry && role == roleLowerBody:
					area = areaHouse
					continue AreaLoop
				case level == roleLevelCountry && role == roleUpperBody:
					area = areaSenate
					continue AreaLoop
				// Civic API returns governor and deputy governor under same
				// role level and role, comparing the name is the best we can do
				// with this dataset
				case level == roleLevelState && role == roleHeadOfGovernment && o.Name == "Governor":
					area = areaGovernor
					continue AreaLoop
				}
			}
		}
		if area != "" {
			for _, i := range o.OfficialIndices {
				official := r.Officials[i]
				var phone string
				if len(official.Phones) > 0 {
					phone = official.Phones[0]
				} else {
					continue
				}
				c := &Contact{
					ID:       fmt.Sprintf("%s-%s", r.NormalizedInput.State, strings.Replace(official.Name, " ", "", -1)),
					Name:     official.Name,
					Phone:    reformattedPhone(phone),
					PhotoURL: official.PhotoUrl,
					Party:    official.Party,
					State:    r.NormalizedInput.State,
					Area:     area,
				}
				switch area {
				case areaHouse:
					ret.HouseRep = c
				case areaSenate:
					ret.Senators = append(ret.Senators, c)
				case areaGovernor:
					ret.Governor = c
				}
			}
		}
	}
	return ret, r.NormalizedInput, nil
}

// civicAPI provides a semantic interface to the Google civic API.
type civicAPI struct {
	key string
	c   *http.Client
}

// NewCivicAPI returns an instance of the civic API.
func NewCivicAPI(key string, client *http.Client) RepFinder {
	return &civicAPI{
		key: key,
		c:   client,
	}
}

// GetReps returns local representatives for the supplied address.
func (c *civicAPI) GetReps(address string) (*LocalReps, *Address, error) {
	var u, _ = url.Parse(baseURL)
	q := u.Query()
	for _, l := range roleLevel {
		q.Add("levels", l)
	}
	q.Set("key", c.key)
	q.Set("address", url.QueryEscape(address))
	u.RawQuery = q.Encode()
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, nil, err
	}
	res, err := c.c.Do(req)
	if err != nil {
		return nil, nil, err
	}
	defer res.Body.Close()
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, nil, err
	}
	var ar apiResponse
	err = json.Unmarshal(b, &ar)
	if err != nil {
		return nil, nil, err
	}
	return ar.toLocalReps()
}

// repCache implements a cache layer on top of a delegate rep finder.
type repCache struct {
	delegate RepFinder
	cache    *cache.Cache
}

type cacheItem struct {
	reps LocalReps
	addr Address
}

func NewRepCache(delegate RepFinder, ttl time.Duration, gc time.Duration) RepFinder {
	return &repCache{
		delegate: delegate,
		cache:    cache.New(ttl, gc),
	}
}

// reformat phone numbers that come from the google civic API
func reformattedPhone(civicPhone string) string {
	result := phoneRegex.FindStringSubmatch(civicPhone)

	if len(result) >= 3 {
		return fmt.Sprintf("%s-%s-%s", result[1], result[2], result[3])
	}

	return civicPhone
}

// GetReps returns local representatives for the supplied address.
func (r *repCache) GetReps(address string) (*LocalReps, *Address, error) {
	data, ok := r.cache.Get(address)
	if ok {
		ci := data.(*cacheItem)
		reps := ci.reps
		addr := ci.addr
		return &reps, &addr, nil
	}
	reps, addr, err := r.delegate.GetReps(address)
	if err != nil {
		return nil, nil, err
	}
	ci := &cacheItem{reps: *reps, addr: *addr}
	r.cache.Set(address, ci, cache.DefaultExpiration)
	return reps, addr, nil
}
<commit_msg>Refactor out Office.Area<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/patrickmn/go-cache"
)

const (
	roleLowerBody        = "legislatorLowerBody"
	roleUpperBody        = "legislatorUpperBody"
	roleHeadOfGovernment = "headOfGovernment"
	roleLevelCountry     = "country"
	roleLevelState       = "administrativeArea1"
	areaHouse            = "House"
	areaSenate           = "Senate"
	areaGovernor         = "Governor"
)

var baseURL = "https://www.googleapis.com/civicinfo/v2/representatives"
var phoneRegex = regexp.MustCompile(`\((\d{3})\)\s+(\d{3})[\s\-](\d{4})`)
var roleLevel = [2]string{"country", "administrativeArea1"}

// RepFinder provides a mechanism to find local reps given an address.
type RepFinder interface {
	GetReps(address string) (*LocalReps, *Address, error)
}

// APIError is an error returned by the Google civic API, which also
// implements the error interface.
type APIError struct {
	Code    int
	Message string
	Errors  []struct {
		Domain  string
		Reason  string
		Message string
	}
}

func (ae *APIError) Error() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%d %s", ae.Code, ae.Message)
	for _, e := range ae.Errors {
		if e.Message != ae.Message { // don't duplicate messages
			fmt.Fprintf(&buf, ";[domain=%s, reason=%s: %s]", e.Domain, e.Reason, e.Message)
		}
	}
	return buf.String()
}

type Office struct {
	Name            string
	DivisionId      string
	Levels          []string
	Roles           []string
	OfficialIndices []int
}

type Official struct {
	Name     string
	Address  []Address
	Party    string
	Phones   []string
	PhotoUrl string
	Channels []struct {
		Id   string
		Type string
	}
}

// apiResponse is the response from the civic API. It encapsulates valid
// responses that set the normalized input, offices and officials,
// as well as error responses.
type apiResponse struct {
	NormalizedInput *Address
	Offices         []Office
	Officials       []Official
	Error           *APIError
}

// toLocalReps converts an API response to a set of local reps. In addition,
// it also returns the normalized address for which the response is valid.
func (r *apiResponse) toLocalReps() (*LocalReps, *Address, error) {
	if r.Error != nil {
		return nil, nil, r.Error
	}
	if len(r.Offices) == 0 {
		return nil, nil, fmt.Errorf("no offices found ")
	}
	ret := &LocalReps{}
	for _, o := range r.Offices {
		area := o.Area()
		if area == "" {
			continue
		}
		for _, i := range o.OfficialIndices {
			official := r.Officials[i]
			var phone string
			if len(official.Phones) > 0 {
				phone = official.Phones[0]
			} else {
				continue
			}
			c := &Contact{
				ID:       fmt.Sprintf("%s-%s", r.NormalizedInput.State, strings.Replace(official.Name, " ", "", -1)),
				Name:     official.Name,
				Phone:    reformattedPhone(phone),
				PhotoURL: official.PhotoUrl,
				Party:    official.Party,
				State:    r.NormalizedInput.State,
				Area:     area,
			}
			switch area {
			case areaHouse:
				ret.HouseRep = c
			case areaSenate:
				ret.Senators = append(ret.Senators, c)
			case areaGovernor:
				ret.Governor = c
			}
		}
	}
	return ret, r.NormalizedInput, nil
}

func (x *Office) Area() string {
	for _, level := range x.Levels {
		for _, role := range x.Roles {
			switch {
			case level == roleLevelCountry && role == roleLowerBody:
				return areaHouse
			case level == roleLevelCountry && role == roleUpperBody:
				return areaSenate
			// Civic API returns governor and deputy governor under same
			// role level and role, comparing the name is the best we can do
			// with this dataset
			case level == roleLevelState && role == roleHeadOfGovernment && x.Name == "Governor":
				return areaGovernor
			}
		}
	}
	return ""
}

// civicAPI provides a semantic interface to the Google civic API.
type civicAPI struct {
	key string
	c   *http.Client
}

// NewCivicAPI returns an instance of the civic API.
func NewCivicAPI(key string, client *http.Client) RepFinder {
	return &civicAPI{
		key: key,
		c:   client,
	}
}

// GetReps returns local representatives for the supplied address.
func (c *civicAPI) GetReps(address string) (*LocalReps, *Address, error) {
	var u, _ = url.Parse(baseURL)
	q := u.Query()
	for _, l := range roleLevel {
		q.Add("levels", l)
	}
	q.Set("key", c.key)
	q.Set("address", url.QueryEscape(address))
	u.RawQuery = q.Encode()
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, nil, err
	}
	res, err := c.c.Do(req)
	if err != nil {
		return nil, nil, err
	}
	defer res.Body.Close()
	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, nil, err
	}
	var ar apiResponse
	err = json.Unmarshal(b, &ar)
	if err != nil {
		return nil, nil, err
	}
	return ar.toLocalReps()
}

// repCache implements a cache layer on top of a delegate rep finder.
type repCache struct {
	delegate RepFinder
	cache    *cache.Cache
}

type cacheItem struct {
	reps LocalReps
	addr Address
}

func NewRepCache(delegate RepFinder, ttl time.Duration, gc time.Duration) RepFinder {
	return &repCache{
		delegate: delegate,
		cache:    cache.New(ttl, gc),
	}
}

// reformat phone numbers that come from the google civic API
func reformattedPhone(civicPhone string) string {
	result := phoneRegex.FindStringSubmatch(civicPhone)

	if len(result) >= 3 {
		return fmt.Sprintf("%s-%s-%s", result[1], result[2], result[3])
	}

	return civicPhone
}

// GetReps returns local representatives for the supplied address.
func (r *repCache) GetReps(address string) (*LocalReps, *Address, error) {
	data, ok := r.cache.Get(address)
	if ok {
		ci := data.(*cacheItem)
		reps := ci.reps
		addr := ci.addr
		return &reps, &addr, nil
	}
	reps, addr, err := r.delegate.GetReps(address)
	if err != nil {
		return nil, nil, err
	}
	ci := &cacheItem{reps: *reps, addr: *addr}
	r.cache.Set(address, ci, cache.DefaultExpiration)
	return reps, addr, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 ENDOH takanao.
// <https://github.com/MiCHiLU/go-gob-http>
//
// Copyright 2014 Orchestrate, Inc.
// <https://github.com/orchestrate-io/dvr>
//
// 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 dvr

import (
	"bytes"
	"encoding/gob"
	"errors"
	"io/ioutil"
	"net/http"
	"reflect"
	"testing"

	"github.com/liquidgecka/testlib"
)

// An error implementation that is unknown to the decoder.
type customError string

func (p customError) Error() string {
	return string(p)
}

func TestGobError_GobEncode(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()

	// Test 1: An unencodable error.

	g := &gobError{Error: customError("Unexpected")}

	// Encode the error.
	buffer := &bytes.Buffer{}
	encoder := gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 := new(gobError)
	decoder := gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Make sure that the two encoded objects types are NOT the same.
	T.NotEqual(g, g2)

	// Ensure that the type of g2.Error is actually a gobSafeError
	if _, ok := g2.Error.(*gobSafeError); !ok {
		T.Fatalf("g2.Error is not a gobSafeEror, its a %T", g2.Error)
	}

	// Test 2: An encodable error.

	g = &gobError{Error: &http.ProtocolError{ErrorString: "Expected"}}

	// Encode the error.
	buffer = &bytes.Buffer{}
	encoder = gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 = new(gobError)
	decoder = gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Ensure that the two encoded objects ARE the same.
	T.Equal(g, g2)

	// Ensure that the type of g2.Error is actually a *http.ProtocolError
	if _, ok := g2.Error.(*http.ProtocolError); !ok {
		T.Fatalf("g2.Error is not a *http.ProtocolError, its a %T", g2.Error)
	}

	// Test 3: An errors.stringError object.

	g = &gobError{Error: errors.New("Expected")}

	// Encode the error.
	buffer = &bytes.Buffer{}
	encoder = gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 = new(gobError)
	decoder = gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Ensure that the two encoded objects ARE the same.
	T.Equal(g, g2)

	// Ensure that the type of g2.Error is actually a *http.ProtocolError
	if reflect.TypeOf(g.Error) != reflect.TypeOf(g2.Error) {
		T.Fatalf("g2.Error is not a *http.ProtocolError, its a %T", g2.Error)
	}
}

func TestGobError_GobDecode(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()
	// Most of the Decoding tests are in TestGobError_GobEncode other than
	// a simple bogus data check.
	g := &gobError{}
	T.ExpectError(g.GobDecode([]byte{0, 1, 2, 3}))
}

func TestSimpleCoverage(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()
	T.Equal(newGobRequest(nil), nil)
	T.Equal(newGobResponse(nil), nil)
}
<commit_msg>remove un used package<commit_after>// Copyright 2015 ENDOH takanao.
// <https://github.com/MiCHiLU/go-gob-http>
//
// Copyright 2014 Orchestrate, Inc.
// <https://github.com/orchestrate-io/dvr>
//
// 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 dvr

import (
	"bytes"
	"encoding/gob"
	"errors"
	"net/http"
	"reflect"
	"testing"

	"github.com/liquidgecka/testlib"
)

// An error implementation that is unknown to the decoder.
type customError string

func (p customError) Error() string {
	return string(p)
}

func TestGobError_GobEncode(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()

	// Test 1: An unencodable error.

	g := &gobError{Error: customError("Unexpected")}

	// Encode the error.
	buffer := &bytes.Buffer{}
	encoder := gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 := new(gobError)
	decoder := gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Make sure that the two encoded objects types are NOT the same.
	T.NotEqual(g, g2)

	// Ensure that the type of g2.Error is actually a gobSafeError
	if _, ok := g2.Error.(*gobSafeError); !ok {
		T.Fatalf("g2.Error is not a gobSafeEror, its a %T", g2.Error)
	}

	// Test 2: An encodable error.

	g = &gobError{Error: &http.ProtocolError{ErrorString: "Expected"}}

	// Encode the error.
	buffer = &bytes.Buffer{}
	encoder = gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 = new(gobError)
	decoder = gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Ensure that the two encoded objects ARE the same.
	T.Equal(g, g2)

	// Ensure that the type of g2.Error is actually a *http.ProtocolError
	if _, ok := g2.Error.(*http.ProtocolError); !ok {
		T.Fatalf("g2.Error is not a *http.ProtocolError, its a %T", g2.Error)
	}

	// Test 3: An errors.stringError object.

	g = &gobError{Error: errors.New("Expected")}

	// Encode the error.
	buffer = &bytes.Buffer{}
	encoder = gob.NewEncoder(buffer)
	T.ExpectSuccess(encoder.Encode(g))

	// Decode the byte array to see what was returned.
	g2 = new(gobError)
	decoder = gob.NewDecoder(buffer)
	T.ExpectSuccess(decoder.Decode(g2))

	// Ensure that the two encoded objects ARE the same.
	T.Equal(g, g2)

	// Ensure that the type of g2.Error is actually a *http.ProtocolError
	if reflect.TypeOf(g.Error) != reflect.TypeOf(g2.Error) {
		T.Fatalf("g2.Error is not a *http.ProtocolError, its a %T", g2.Error)
	}
}

func TestGobError_GobDecode(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()
	// Most of the Decoding tests are in TestGobError_GobEncode other than
	// a simple bogus data check.
	g := &gobError{}
	T.ExpectError(g.GobDecode([]byte{0, 1, 2, 3}))
}

func TestSimpleCoverage(t *testing.T) {
	T := testlib.NewT(t)
	defer T.Finish()
	T.Equal(newGobRequest(nil), nil)
	T.Equal(newGobResponse(nil), nil)
}
<|endoftext|>


<commit_before>// This executable provides an HTTP server that watches for file system changes
// to .go files within the working directory (and all nested go packages).
// Navigating to the configured host and port will show a web UI showing the
// results of running `go test` in each go package.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/smartystreets/goconvey/web/server/api"
	"github.com/smartystreets/goconvey/web/server/contract"
	exec "github.com/smartystreets/goconvey/web/server/executor"
	parse "github.com/smartystreets/goconvey/web/server/parser"
	"github.com/smartystreets/goconvey/web/server/system"
	watch "github.com/smartystreets/goconvey/web/server/watcher"
)

func init() {
	flags()
	folders()
}
func flags() {
	flag.IntVar(&port, "port", 8080, "The port at which to serve http.")
	flag.StringVar(&host, "host", "127.0.0.1", "The host at which to serve http.")
	flag.DurationVar(&nap, "poll", quarterSecond, "The interval to wait between polling the file system for changes (default: 250ms).")
	flag.IntVar(&packages, "packages", 10, "The number of packages to test in parallel. Higher == faster but more costly in terms of computing. (default: 10)")
	flag.StringVar(&gobin, "gobin", "go", "The path to the 'go' binary (default: search on the PATH).")
	flag.BoolVar(&cover, "cover", true, "Enable package-level coverage statistics. Warning: this will obfuscate line number reporting on panics and build failures! Requires Go 1.2+ and the go cover tool. (default: true)")
	flag.IntVar(&depth, "depth", -1, "The directory scanning depth. If -1, scan infinitely deep directory structures. 0: scan working directory. 1+: Scan into nested directories, limited to value. (default: -1)")
	flag.StringVar(&testflags, "testflags", "", "Any extra flags to be passed to go test tool (default: '') (example: '-testflags="-test.short=true")`")

	log.SetOutput(os.Stdout)
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}
func folders() {
	_, file, _, _ := runtime.Caller(0)
	here := filepath.Dir(file)
	static = filepath.Join(here, "/web/client")
	reports = filepath.Join(static, "reports")
}

func main() {
	flag.Parse()
	log.Printf("Initial configuration: [host: %s] [port: %d] [poll: %v] [cover: %v] [testflags: %v]\n", host, port, nap, cover, testflags)

	monitor, server := wireup()

	go monitor.ScanForever()

	serveHTTP(server)
}

func serveHTTP(server contract.Server) {
	serveStaticResources()
	serveAjaxMethods(server)
	activateServer()
}

func serveStaticResources() {
	http.Handle("/", http.FileServer(http.Dir(static)))
}

func serveAjaxMethods(server contract.Server) {
	http.HandleFunc("/watch", server.Watch)
	http.HandleFunc("/ignore", server.Ignore)
	http.HandleFunc("/reinstate", server.Reinstate)
	http.HandleFunc("/latest", server.Results)
	http.HandleFunc("/execute", server.Execute)
	http.HandleFunc("/status", server.Status)
	http.HandleFunc("/status/poll", server.LongPollStatus)
}

func activateServer() {
	log.Printf("Serving HTTP at: http://%s:%d\n", host, port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	if err != nil {
		fmt.Println(err)
	}
}

func wireup() (*contract.Monitor, contract.Server) {
	log.Println("Constructing components...")
	working, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	// Ensure testflags does not contain any disallowed flags
	for _, a := range strings.Fields(testflags) {
		if a == "-test.parallel" || a == "-parallel" {
			log.Fatal("GoConvey does not support the parallel test flag")
		}
	}

	depthLimit := system.NewDepthLimit(system.NewFileSystem(), depth)
	shell := system.NewShell(gobin, testflags, cover, reports)

	watcher := watch.NewWatcher(depthLimit, shell)
	watcher.Adjust(working)

	parser := parse.NewParser(parse.ParsePackageResults)
	tester := exec.NewConcurrentTester(shell)
	tester.SetBatchSize(packages)

	statusNotif := make(chan bool, 1)
	executor := exec.NewExecutor(tester, parser, statusNotif)
	server := api.NewHTTPServer(watcher, executor, statusNotif)
	scanner := watch.NewScanner(depthLimit, watcher)
	monitor := contract.NewMonitor(scanner, watcher, executor, server, sleeper)

	return monitor, server
}

func sleeper() {
	time.Sleep(nap)
}

var (
	port      int
	host      string
	gobin     string
	nap       time.Duration
	packages  int
	cover     bool
	depth     int
	testflags string

	static  string
	reports string

	quarterSecond = time.Millisecond * 250
)
<commit_msg>Fixed syntax.<commit_after>// This executable provides an HTTP server that watches for file system changes
// to .go files within the working directory (and all nested go packages).
// Navigating to the configured host and port will show a web UI showing the
// results of running `go test` in each go package.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/smartystreets/goconvey/web/server/api"
	"github.com/smartystreets/goconvey/web/server/contract"
	exec "github.com/smartystreets/goconvey/web/server/executor"
	parse "github.com/smartystreets/goconvey/web/server/parser"
	"github.com/smartystreets/goconvey/web/server/system"
	watch "github.com/smartystreets/goconvey/web/server/watcher"
)

func init() {
	flags()
	folders()
}
func flags() {
	flag.IntVar(&port, "port", 8080, "The port at which to serve http.")
	flag.StringVar(&host, "host", "127.0.0.1", "The host at which to serve http.")
	flag.DurationVar(&nap, "poll", quarterSecond, "The interval to wait between polling the file system for changes (default: 250ms).")
	flag.IntVar(&packages, "packages", 10, "The number of packages to test in parallel. Higher == faster but more costly in terms of computing. (default: 10)")
	flag.StringVar(&gobin, "gobin", "go", "The path to the 'go' binary (default: search on the PATH).")
	flag.BoolVar(&cover, "cover", true, "Enable package-level coverage statistics. Warning: this will obfuscate line number reporting on panics and build failures! Requires Go 1.2+ and the go cover tool. (default: true)")
	flag.IntVar(&depth, "depth", -1, "The directory scanning depth. If -1, scan infinitely deep directory structures. 0: scan working directory. 1+: Scan into nested directories, limited to value. (default: -1)")
	flag.StringVar(&testflags, "testflags", "", `Any extra flags to be passed to go test tool (default: '') (example: '-testflags="-test.short=true")`)

	log.SetOutput(os.Stdout)
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}
func folders() {
	_, file, _, _ := runtime.Caller(0)
	here := filepath.Dir(file)
	static = filepath.Join(here, "/web/client")
	reports = filepath.Join(static, "reports")
}

func main() {
	flag.Parse()
	log.Printf("Initial configuration: [host: %s] [port: %d] [poll: %v] [cover: %v] [testflags: %v]\n", host, port, nap, cover, testflags)

	monitor, server := wireup()

	go monitor.ScanForever()

	serveHTTP(server)
}

func serveHTTP(server contract.Server) {
	serveStaticResources()
	serveAjaxMethods(server)
	activateServer()
}

func serveStaticResources() {
	http.Handle("/", http.FileServer(http.Dir(static)))
}

func serveAjaxMethods(server contract.Server) {
	http.HandleFunc("/watch", server.Watch)
	http.HandleFunc("/ignore", server.Ignore)
	http.HandleFunc("/reinstate", server.Reinstate)
	http.HandleFunc("/latest", server.Results)
	http.HandleFunc("/execute", server.Execute)
	http.HandleFunc("/status", server.Status)
	http.HandleFunc("/status/poll", server.LongPollStatus)
}

func activateServer() {
	log.Printf("Serving HTTP at: http://%s:%d\n", host, port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	if err != nil {
		fmt.Println(err)
	}
}

func wireup() (*contract.Monitor, contract.Server) {
	log.Println("Constructing components...")
	working, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	// Ensure testflags does not contain any disallowed flags
	for _, a := range strings.Fields(testflags) {
		if a == "-test.parallel" || a == "-parallel" {
			log.Fatal("GoConvey does not support the parallel test flag")
		}
	}

	depthLimit := system.NewDepthLimit(system.NewFileSystem(), depth)
	shell := system.NewShell(gobin, testflags, cover, reports)

	watcher := watch.NewWatcher(depthLimit, shell)
	watcher.Adjust(working)

	parser := parse.NewParser(parse.ParsePackageResults)
	tester := exec.NewConcurrentTester(shell)
	tester.SetBatchSize(packages)

	statusNotif := make(chan bool, 1)
	executor := exec.NewExecutor(tester, parser, statusNotif)
	server := api.NewHTTPServer(watcher, executor, statusNotif)
	scanner := watch.NewScanner(depthLimit, watcher)
	monitor := contract.NewMonitor(scanner, watcher, executor, server, sleeper)

	return monitor, server
}

func sleeper() {
	time.Sleep(nap)
}

var (
	port      int
	host      string
	gobin     string
	nap       time.Duration
	packages  int
	cover     bool
	depth     int
	testflags string

	static  string
	reports string

	quarterSecond = time.Millisecond * 250
)
<|endoftext|>


<commit_before>package gofakes3

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

type GoFakeS3 struct {
	storage *bolt.DB
}
type Content struct {
	Key          string    `xml:"Key"`
	LastModified time.Time `xml:"LastModified"`
	ETag         string    `xml:"ETag"`
	Size         int       `xml:"Size"`
	StorageClass string    `xml:"StorageClass"`
}
type Bucket struct {
	XMLName  xml.Name   `xml:"ListBucketResult"`
	Xmlns    string     `xml:"xmlns,attr"`
	Name     string     `xml:"Name"`
	Prefix   string     `xml:"Prefix"`
	Marker   string     `xml:"Marker"`
	Contents []*Content `xml:"Contents"`
}
type Object struct {
	Metadata map[string]string
	Obj      []byte
}

// Setup a new fake object storage
func New(dbname string) *GoFakeS3 {
	db, err := bolt.Open(dbname, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("locals3 db created or opened")
	return &GoFakeS3{storage: db}
}

// Create the AWS S3 API
func (g *GoFakeS3) Server() http.Handler {
	r := mux.NewRouter()
	r.Queries("marker", "prefix")
	// BUCKET
	r.HandleFunc("/{BucketName}", g.GetBucket).Methods("GET")
	r.HandleFunc("/{BucketName}", g.CreateBucket).Methods("PUT")
	//r.HandleFunc("/{BucketName}", g.CreateBucket).Methods("PUT")
	r.HandleFunc("/{BucketName}", g.DeleteBucket).Methods("DELETE")
	r.HandleFunc("/{BucketName}", g.HeadBucket).Methods("HEAD")
	// OBJECT
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.GetObject).Methods("GET")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.CreateObject).Methods("PUT")
	r.HandleFunc("/{BucketName}/{ObjectName:.{0,}}", g.CreateObject).Methods("POST")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.DeleteObject).Methods("DELETE")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.HeadObject).Methods("HEAD")

	return &WithCORS{r}
}

type WithCORS struct {
	r *mux.Router
}

func (s *WithCORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD")
	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Amz-User-Agent, X-Amz-Date, x-amz-meta-from, x-amz-meta-to, x-amz-meta-filename")
	if r.Method == "OPTIONS" {
		return
	}
	// Bucket name rewriting
	// this is due to some inconsistencies in the AWS SDKs
	re := regexp.MustCompile("(127.0.0.1:\\d{1,7})|(.localhost:\\d{1,7})")
	bucket := re.ReplaceAllString(r.Host, "")
	if len(bucket) > 0 {
		p := r.URL.Path
		r.URL.Path = "/" + bucket
		if p != "/" {
			r.URL.Path += p
		}
	}
	log.Println("=>", r.URL)

	s.r.ServeHTTP(w, r)
}

// GetBucket lists the contents of a bucket.
func (g *GoFakeS3) GetBucket(w http.ResponseWriter, r *http.Request) {
	log.Println("GET BUCKET")

	bucketName := strings.Replace(r.Host, ".localhost:9000", "", -1)

	log.Println("bucketname:", bucketName)
	log.Println("prefix    :", r.URL.Query().Get("prefix"))

	g.storage.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			http.Error(w, "No bucket", http.StatusInternalServerError)
			return nil
		}
		c := b.Cursor()
		bucketc := &Bucket{
			Xmlns:    "http://s3.amazonaws.com/doc/2006-03-01/",
			Name:     "crowdpatent.com",
			Prefix:   r.URL.Query().Get("prefix"),
			Marker:   "",
			Contents: []*Content{},
		}

		for k, v := c.First(); k != nil; k, v = c.Next() {
			if strings.Contains(string(k), r.URL.Query().Get("prefix")) {
				hash := md5.Sum(v)
				bucketc.Contents = append(bucketc.Contents, &Content{
					Key:          string(k),
					LastModified: time.Now(),
					ETag:         "\"" + hex.EncodeToString(hash[:]) + "\"",
					Size:         len(v),
					StorageClass: "STANDARD",
				})
				t := Object{}
				err := bson.Unmarshal(v, &t)
				if err != nil {
					panic(err)
				}
			}
		}

		x, err := xml.MarshalIndent(bucketc, "", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return nil
		}
		w.Write(x)
		return nil
	})
}

// CreateBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) CreateBucket(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	var bucketName string
	log.Println("CREATE BUCKET:", bucketName)
	if len(vars["BucketName"]) > 0 {
		bucketName = vars["BucketName"]
	} else {
		bucketName = strings.Replace(r.Host, ".localhost:9000", "", -1)
	}

	g.storage.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucket([]byte(bucketName))
		if err != nil {
			http.Error(w, "bucket existed", http.StatusBadRequest)
			return err
		}
		log.Println("bucket created")
		w.Header().Set("Host", r.Header.Get("Host"))
		w.Header().Set("Location", "/"+bucketName)
		w.Write([]byte{})
		return nil
	})
}

// DeleteBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) DeleteBucket(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "delete bucket")
}

// HeadBucket checks whether a bucket exists.
func (g *GoFakeS3) HeadBucket(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	bucketName := vars["BucketName"]
	log.Println("HEAD BUCKET", bucketName)
	log.Println("bucketname:", bucketName)
	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})
}

// GetObject retrievs a bucket object.
func (g *GoFakeS3) GetObject(w http.ResponseWriter, r *http.Request) {
	log.Println("GET OBJECT")
	vars := mux.Vars(r)
	bucketName := vars["BucketName"]
	log.Println("Bucket:", bucketName)
	log.Println("└── Object:", vars["ObjectName"])

	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		v := b.Get([]byte(vars["ObjectName"]))

		if v == nil {
			log.Println("no object")
			http.Error(w, "object does not exist", http.StatusInternalServerError)
			return nil
		}
		t := Object{}
		err := bson.Unmarshal(v, &t)
		if err != nil {
			panic(err)
		}
		hash := md5.Sum(t.Obj)
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		for mk, mv := range t.Metadata {
			w.Header().Set(mk, mv)
		}
		w.Header().Set("Last-Modified", time.Now().Format("Mon, 2 Jan 2006 15:04:05 MST"))
		w.Header().Set("ETag", "\""+hex.EncodeToString(hash[:])+"\"")
		w.Header().Set("Server", "AmazonS3")
		w.Header().Set("Content-Length", fmt.Sprintf("%v", len(t.Obj)))
		w.Header().Set("Connection", "close")
		w.Write(t.Obj)
		return nil
	})
}

// CreateObject creates a new S3 object.
func (g *GoFakeS3) CreateObject(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	var bucketName string
	if len(vars["BucketName"]) > 0 {
		bucketName = vars["BucketName"]
	} else {
		bucketName = strings.Replace(r.Host, ".localhost:9000", "", -1)
	}
	log.Println("CREATE OBJECT:", bucketName, vars["ObjectName"])
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(err)
	}

	meta := make(map[string]string)
	for hk, hv := range r.Header {
		if strings.Contains(hk, "X-Amz-") {
			meta[hk] = hv[0]
		}
	}
	meta["Last-Modified"] = time.Now().Format("Mon, 2 Jan 2006 15:04:05 MST")

	obj := &Object{meta, body}

	g.storage.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
			return nil
		}
		log.Println("bucket", bucketName, "found")
		data, err := bson.Marshal(obj)
		if err != nil {
			panic(err)
		}
		err = b.Put([]byte(vars["ObjectName"]), data)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return fmt.Errorf("error while creating")
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		w.Header().Set("ETag", "\"fbacf535f27731c9771645a39863328\"")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})
}

// DeleteObject deletes a S3 object from the bucket.
func (g *GoFakeS3) DeleteObject(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "delete object")
}

// HeadObject retrieves only meta information of an object and not the whole.
func (g *GoFakeS3) HeadObject(w http.ResponseWriter, r *http.Request) {
	log.Println("HEAD OBJECT")
	vars := mux.Vars(r)
	bucketName := strings.Replace(r.Host, ".localhost:9000", "", -1)
	log.Println("Bucket:", bucketName)
	log.Println("└── Object:", vars["ObjectName"])

	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		v := b.Get([]byte(vars["ObjectName"]))

		if v == nil {
			log.Println("no object")
			http.Error(w, "object does not exist", http.StatusInternalServerError)
		}
		t := Object{}
		err := bson.Unmarshal(v, &t)
		if err != nil {
			panic(err)
		}
		hash := md5.Sum(t.Obj)
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		for mk, mv := range t.Metadata {
			w.Header().Set(mk, mv)
		}
		w.Header().Set("Last-Modified", t.Metadata["Last-Modified"])
		w.Header().Set("ETag", "\""+hex.EncodeToString(hash[:])+"\"")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})

}
<commit_msg>Change bucket interaction<commit_after>package gofakes3

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

type GoFakeS3 struct {
	storage *bolt.DB
}
type Content struct {
	Key          string    `xml:"Key"`
	LastModified time.Time `xml:"LastModified"`
	ETag         string    `xml:"ETag"`
	Size         int       `xml:"Size"`
	StorageClass string    `xml:"StorageClass"`
}
type Bucket struct {
	XMLName  xml.Name   `xml:"ListBucketResult"`
	Xmlns    string     `xml:"xmlns,attr"`
	Name     string     `xml:"Name"`
	Prefix   string     `xml:"Prefix"`
	Marker   string     `xml:"Marker"`
	Contents []*Content `xml:"Contents"`
}
type Object struct {
	Metadata map[string]string
	Obj      []byte
}

// Setup a new fake object storage
func New(dbname string) *GoFakeS3 {
	db, err := bolt.Open(dbname, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("locals3 db created or opened")
	return &GoFakeS3{storage: db}
}

// Create the AWS S3 API
func (g *GoFakeS3) Server() http.Handler {
	r := mux.NewRouter()
	r.Queries("marker", "prefix")
	// BUCKET
	r.HandleFunc("/{BucketName}", g.GetBucket).Methods("GET")
	r.HandleFunc("/{BucketName}", g.CreateBucket).Methods("PUT")
	r.HandleFunc("/{BucketName}", g.DeleteBucket).Methods("DELETE")
	r.HandleFunc("/{BucketName}", g.HeadBucket).Methods("HEAD")
	// OBJECT
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.GetObject).Methods("GET")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.CreateObject).Methods("PUT")
	r.HandleFunc("/{BucketName}/{ObjectName:.{0,}}", g.CreateObject).Methods("POST")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.DeleteObject).Methods("DELETE")
	r.HandleFunc("/{BucketName}/{ObjectName:.{1,}}", g.HeadObject).Methods("HEAD")

	return &WithCORS{r}
}

type WithCORS struct {
	r *mux.Router
}

func (s *WithCORS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD")
	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Amz-User-Agent, X-Amz-Date, x-amz-meta-from, x-amz-meta-to, x-amz-meta-filename, x-amz-meta-private")
	if r.Method == "OPTIONS" {
		return
	}
	// Bucket name rewriting
	// this is due to some inconsistencies in the AWS SDKs
	re := regexp.MustCompile("(127.0.0.1:\\d{1,7})|(.localhost:\\d{1,7})")
	bucket := re.ReplaceAllString(r.Host, "")
	if len(bucket) > 0 {
		p := r.URL.Path
		r.URL.Path = "/" + bucket
		if p != "/" {
			r.URL.Path += p
		}
	}
	log.Println("=>", r.URL)

	s.r.ServeHTTP(w, r)
}

// GetBucket lists the contents of a bucket.
func (g *GoFakeS3) GetBucket(w http.ResponseWriter, r *http.Request) {
	log.Println("GET BUCKET")

	bucketName := strings.Replace(r.Host, ".localhost:9000", "", -1)

	log.Println("bucketname:", bucketName)
	log.Println("prefix    :", r.URL.Query().Get("prefix"))

	g.storage.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			http.Error(w, "No bucket", http.StatusInternalServerError)
			return nil
		}
		c := b.Cursor()
		bucketc := &Bucket{
			Xmlns:    "http://s3.amazonaws.com/doc/2006-03-01/",
			Name:     "crowdpatent.com",
			Prefix:   r.URL.Query().Get("prefix"),
			Marker:   "",
			Contents: []*Content{},
		}

		for k, v := c.First(); k != nil; k, v = c.Next() {
			if strings.Contains(string(k), r.URL.Query().Get("prefix")) {
				hash := md5.Sum(v)
				bucketc.Contents = append(bucketc.Contents, &Content{
					Key:          string(k),
					LastModified: time.Now(),
					ETag:         "\"" + hex.EncodeToString(hash[:]) + "\"",
					Size:         len(v),
					StorageClass: "STANDARD",
				})
				t := Object{}
				err := bson.Unmarshal(v, &t)
				if err != nil {
					panic(err)
				}
			}
		}

		x, err := xml.MarshalIndent(bucketc, "", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return nil
		}
		w.Write(x)
		return nil
	})
}

// CreateBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) CreateBucket(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	var bucketName string
	log.Println("CREATE BUCKET:", bucketName)
	if len(vars["BucketName"]) > 0 {
		bucketName = vars["BucketName"]
	} else {
		bucketName = strings.Replace(r.Host, ".localhost:9000", "", -1)
	}

	g.storage.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucket([]byte(bucketName))
		if err != nil {
			http.Error(w, "bucket existed", http.StatusBadRequest)
			return err
		}
		log.Println("bucket created")
		w.Header().Set("Host", r.Header.Get("Host"))
		w.Header().Set("Location", "/"+bucketName)
		w.Write([]byte{})
		return nil
	})
}

// DeleteBucket creates a new S3 bucket in the BoltDB storage.
func (g *GoFakeS3) DeleteBucket(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "delete bucket")
}

// HeadBucket checks whether a bucket exists.
func (g *GoFakeS3) HeadBucket(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	bucketName := vars["BucketName"]
	log.Println("HEAD BUCKET", bucketName)
	log.Println("bucketname:", bucketName)
	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})
}

// GetObject retrievs a bucket object.
func (g *GoFakeS3) GetObject(w http.ResponseWriter, r *http.Request) {
	log.Println("GET OBJECT")
	vars := mux.Vars(r)
	bucketName := vars["BucketName"]
	log.Println("Bucket:", bucketName)
	log.Println("└── Object:", vars["ObjectName"])

	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		v := b.Get([]byte(vars["ObjectName"]))

		if v == nil {
			log.Println("no object")
			http.Error(w, "object does not exist", http.StatusInternalServerError)
			return nil
		}
		t := Object{}
		err := bson.Unmarshal(v, &t)
		if err != nil {
			panic(err)
		}
		hash := md5.Sum(t.Obj)
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		for mk, mv := range t.Metadata {
			w.Header().Set(mk, mv)
		}
		w.Header().Set("Last-Modified", time.Now().Format("Mon, 2 Jan 2006 15:04:05 MST"))
		w.Header().Set("ETag", "\""+hex.EncodeToString(hash[:])+"\"")
		w.Header().Set("Server", "AmazonS3")
		w.Header().Set("Content-Length", fmt.Sprintf("%v", len(t.Obj)))
		w.Header().Set("Connection", "close")
		w.Write(t.Obj)
		return nil
	})
}

// CreateObject creates a new S3 object.
func (g *GoFakeS3) CreateObject(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	var bucketName string
	if len(vars["BucketName"]) > 0 {
		bucketName = vars["BucketName"]
	} else {
		bucketName = strings.Replace(r.Host, ".localhost:9000", "", -1)
	}
	log.Println("CREATE OBJECT:", bucketName, vars["ObjectName"])
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(err)
	}

	meta := make(map[string]string)
	for hk, hv := range r.Header {
		if strings.Contains(hk, "X-Amz-") {
			meta[hk] = hv[0]
		}
	}
	meta["Last-Modified"] = time.Now().Format("Mon, 2 Jan 2006 15:04:05 MST")

	obj := &Object{meta, body}

	g.storage.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
			return nil
		}
		log.Println("bucket", bucketName, "found")
		data, err := bson.Marshal(obj)
		if err != nil {
			panic(err)
		}
		err = b.Put([]byte(vars["ObjectName"]), data)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return fmt.Errorf("error while creating")
		}
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		w.Header().Set("ETag", "\"fbacf535f27731c9771645a39863328\"")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})
}

// DeleteObject deletes a S3 object from the bucket.
func (g *GoFakeS3) DeleteObject(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "delete object")
}

// HeadObject retrieves only meta information of an object and not the whole.
func (g *GoFakeS3) HeadObject(w http.ResponseWriter, r *http.Request) {
	log.Println("HEAD OBJECT")
	vars := mux.Vars(r)
	bucketName := strings.Replace(r.Host, ".localhost:9000", "", -1)
	log.Println("Bucket:", bucketName)
	log.Println("└── Object:", vars["ObjectName"])

	g.storage.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucketName))
		if b == nil {
			log.Println("no bucket")
			http.Error(w, "bucket does not exist", http.StatusInternalServerError)
		}
		v := b.Get([]byte(vars["ObjectName"]))

		if v == nil {
			log.Println("no object")
			http.Error(w, "object does not exist", http.StatusInternalServerError)
		}
		t := Object{}
		err := bson.Unmarshal(v, &t)
		if err != nil {
			panic(err)
		}
		hash := md5.Sum(t.Obj)
		w.Header().Set("x-amz-id-2", "LriYPLdmOdAiIfgSm/F1YsViT1LW94/xUQxMsF7xiEb1a0wiIOIxl+zbwZ163pt7")
		w.Header().Set("x-amz-request-id", "0A49CE4060975EAC")
		for mk, mv := range t.Metadata {
			w.Header().Set(mk, mv)
		}
		w.Header().Set("Last-Modified", t.Metadata["Last-Modified"])
		w.Header().Set("ETag", "\""+hex.EncodeToString(hash[:])+"\"")
		w.Header().Set("Server", "AmazonS3")
		w.Write([]byte{})
		return nil
	})

}
<|endoftext|>


<commit_before>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// GoRewind is an event store server written in Go that talks ZeroMQ.
package main

import (
	"flag"
	"log"
	"os"
	"./server"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

var (
	eventStorePath = flag.String("datadir", "data",
	"directory path where incoming events will be stored. Created"+
	" if non-existent.")
	commandSocketZPath = flag.String("commandsocket",
	"tcp://127.0.0.1:9002", "Command socket. Handles new eventsand"+
	" queries.")
	eventPublishZPath = flag.String("evpubsocket",
	"tcp://127.0.0.1:9003", "ZeroMQ event publishing socket.")
)

// Main method. Will panic if things are so bad that the application
// will not start.
func main() {
	flag.Parse()

	log.Println("Event store to use:", *eventStorePath)
	log.Println("Command socket path:", *commandSocketZPath)
	log.Println("Event publishing socket path:", *eventPublishZPath)
	log.Println()

	stor, err := storage.OpenFile(*eventStorePath)
	if err != nil {
		log.Panicln("could not create DB storage")
	}
	defer stor.Close()

	estore, err := server.NewEventStore(stor)
	if err != nil {
		log.Panicln(os.Stderr, "could not create event store")
	}
	defer estore.Close()

	initParams := server.InitParams{
		Store: estore,
		CommandSocketZPath: commandSocketZPath,
		EvPubSocketZPath: eventPublishZPath,
	}
	serv, err := server.New(&initParams)
	if err != nil {
		panic(err.Error())
	}

	// FIXME: Handle SIGINT correctly and smoothly.

	serv.Run()
}
<commit_msg>Bugfix: Fix broken import<commit_after>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// GoRewind is an event store server written in Go that talks ZeroMQ.
package main

import (
	"flag"
	"log"
	"os"
	"github.com/JensRantil/gorewind/server"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

var (
	eventStorePath = flag.String("datadir", "data",
	"directory path where incoming events will be stored. Created"+
	" if non-existent.")
	commandSocketZPath = flag.String("commandsocket",
	"tcp://127.0.0.1:9002", "Command socket. Handles new eventsand"+
	" queries.")
	eventPublishZPath = flag.String("evpubsocket",
	"tcp://127.0.0.1:9003", "ZeroMQ event publishing socket.")
)

// Main method. Will panic if things are so bad that the application
// will not start.
func main() {
	flag.Parse()

	log.Println("Event store to use:", *eventStorePath)
	log.Println("Command socket path:", *commandSocketZPath)
	log.Println("Event publishing socket path:", *eventPublishZPath)
	log.Println()

	stor, err := storage.OpenFile(*eventStorePath)
	if err != nil {
		log.Panicln("could not create DB storage")
	}
	defer stor.Close()

	estore, err := server.NewEventStore(stor)
	if err != nil {
		log.Panicln(os.Stderr, "could not create event store")
	}
	defer estore.Close()

	initParams := server.InitParams{
		Store: estore,
		CommandSocketZPath: commandSocketZPath,
		EvPubSocketZPath: eventPublishZPath,
	}
	serv, err := server.New(&initParams)
	if err != nil {
		panic(err.Error())
	}

	// FIXME: Handle SIGINT correctly and smoothly.

	serv.Run()
}
<|endoftext|>


<commit_before>// Package gotwilio is a library for interacting with http://www.twilio.com/ API.
package gotwilio

import (
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	baseURL       = "https://api.twilio.com/2010-04-01"
	clientTimeout = time.Second * 30
)

// Twilio stores basic information important for connecting to the
// twilio.com REST api such as AccountSid and AuthToken.
type Twilio struct {
	AccountSid string
	AuthToken  string
	BaseUrl    string
	HTTPClient *http.Client
}

// Exception is a representation of a twilio exception.
type Exception struct {
	Status   int    `json:"status"`    // HTTP specific error code
	Message  string `json:"message"`   // HTTP error message
	Code     int    `json:"code"`      // Twilio specific error code
	MoreInfo string `json:"more_info"` // Additional info from Twilio
}

// Create a new Twilio struct.
func NewTwilioClient(accountSid, authToken string) *Twilio {
	return NewTwilioClientCustomHTTP(accountSid, authToken, nil)
}

// Create a new Twilio client, optionally using a custom http.Client
func NewTwilioClientCustomHTTP(accountSid, authToken string, HTTPClient *http.Client) *Twilio {
	if HTTPClient == nil {
		HTTPClient = defaultClient()
	}

	return &Twilio{accountSid, authToken, baseURL, HTTPClient}
}

func (twilio *Twilio) post(formValues url.Values, twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("POST", twilioUrl, strings.NewReader(formValues.Encode()))
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient()
	}

	return client.Do(req)
}

func (twilio *Twilio) get(twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("GET", twilioUrl, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient()
	}

	return client.Do(req)
}

func (twilio *Twilio) delete(twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("DELETE", twilioUrl, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient()
	}

	return client.Do(req)
}

func defaultClient() *http.Client {
	client := http.Client{
		Timeout: clientTimeout,
	}

	return &client
}
<commit_msg>Move the default http client to a variable<commit_after>// Package gotwilio is a library for interacting with http://www.twilio.com/ API.
package gotwilio

import (
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	baseURL       = "https://api.twilio.com/2010-04-01"
	clientTimeout = time.Second * 30
)

// The default http.Client that is used if none is specified
var defaultClient = &http.Client{
	Timeout: time.Second * 30,
}

// Twilio stores basic information important for connecting to the
// twilio.com REST api such as AccountSid and AuthToken.
type Twilio struct {
	AccountSid string
	AuthToken  string
	BaseUrl    string
	HTTPClient *http.Client
}

// Exception is a representation of a twilio exception.
type Exception struct {
	Status   int    `json:"status"`    // HTTP specific error code
	Message  string `json:"message"`   // HTTP error message
	Code     int    `json:"code"`      // Twilio specific error code
	MoreInfo string `json:"more_info"` // Additional info from Twilio
}

// Create a new Twilio struct.
func NewTwilioClient(accountSid, authToken string) *Twilio {
	return NewTwilioClientCustomHTTP(accountSid, authToken, nil)
}

// Create a new Twilio client, optionally using a custom http.Client
func NewTwilioClientCustomHTTP(accountSid, authToken string, HTTPClient *http.Client) *Twilio {
	if HTTPClient == nil {
		HTTPClient = defaultClient
	}

	return &Twilio{accountSid, authToken, baseURL, HTTPClient}
}

func (twilio *Twilio) post(formValues url.Values, twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("POST", twilioUrl, strings.NewReader(formValues.Encode()))
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient
	}

	return client.Do(req)
}

func (twilio *Twilio) get(twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("GET", twilioUrl, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient
	}

	return client.Do(req)
}

func (twilio *Twilio) delete(twilioUrl string) (*http.Response, error) {
	req, err := http.NewRequest("DELETE", twilioUrl, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(twilio.AccountSid, twilio.AuthToken)
	client := twilio.HTTPClient
	if client == nil {
		client = defaultClient
	}

	return client.Do(req)
}
<|endoftext|>


<commit_before>package core

import (
	"github.com/MG-RAST/AWE/lib/conf"
	"time"
)

//job info
type Info struct {
	Name          string            `bson:"name" json:"name"`
	Xref          string            `bson:"xref" json:"xref"`
	Project       string            `bson:"project" json:"project"`
	User          string            `bson:"user" json:"user"`
	Pipeline      string            `bson:"pipeline" json:"pipeline"`
	ClientGroups  string            `bson:"clientgroups" json:"clientgroups"`
	SubmitTime    time.Time         `bson:"submittime" json:"submittime"`
	StartedTme    time.Time         `bson:"startedtime" json:"startedtime"`
	CompletedTime time.Time         `bson:"completedtime" json:"completedtime"`
	Priority      int               `bson:"priority" json:"priority"`
	Auth          bool              `bson:"auth" json:"auth"`
	DataToken     string            `bson:"datatoken" json:"-"`
	NoRetry       bool              `bson:"noretry" json:"noretry"`
	UserAttr      map[string]string `bson:"userattr" json:"userattr"`
}

func NewInfo() *Info {
	return &Info{
		SubmitTime: time.Now(),
		Priority:   conf.BasePriority,
	}
}
<commit_msg>add two fields in job info: service and description<commit_after>package core

import (
	"github.com/MG-RAST/AWE/lib/conf"
	"time"
)

//job info
type Info struct {
	Name          string            `bson:"name" json:"name"`
	Xref          string            `bson:"xref" json:"xref"`
	Service       string            `bson:"service" json:"service"`
	Project       string            `bson:"project" json:"project"`
	User          string            `bson:"user" json:"user"`
	Pipeline      string            `bson:"pipeline" json:"pipeline"`
	ClientGroups  string            `bson:"clientgroups" json:"clientgroups"`
	SubmitTime    time.Time         `bson:"submittime" json:"submittime"`
	StartedTme    time.Time         `bson:"startedtime" json:"startedtime"`
	CompletedTime time.Time         `bson:"completedtime" json:"completedtime"`
	Priority      int               `bson:"priority" json:"priority"`
	Auth          bool              `bson:"auth" json:"auth"`
	DataToken     string            `bson:"datatoken" json:"-"`
	NoRetry       bool              `bson:"noretry" json:"noretry"`
	UserAttr      map[string]string `bson:"userattr" json:"userattr"`
	Description   string            `bson:"discription" json:"discription"`
}

func NewInfo() *Info {
	return &Info{
		SubmitTime: time.Now(),
		Priority:   conf.BasePriority,
	}
}
<|endoftext|>


<commit_before>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016-2018
	All Rights Reserved
	Documentation http://djthorpe.github.io/gopi/
	For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import (
	"image/color"
	"strings"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

// SurfaceType of surface (which API it's bound to)
type SurfaceType uint

// SurfaceFlags are flags associated with surface
// usually during operations
type SurfaceFlags uint32

// SurfaceManagerCallback is a function callback for
// performing surface operations
type SurfaceManagerCallback func(SurfaceManager) error

// SurfaceCallback is a function callback for
// performing drawing operations. If it's a bitmap
// the second argument will contain the bitmap
// resource
type SurfaceCallback func(Surface, Bitmap) error

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

// SurfaceManager allows you to open, close and move
// surfaces around an open display
type SurfaceManager interface {
	Driver
	//SurfaceManagerSurfaceMethods
	//SurfaceManagerBitmapMethods

	// Return the display associated with the surface manager
	Display() Display

	// Return the name of the surface manager. It's basically the
	// GPU driver
	Name() string

	// Return capabilities for the GPU
	Types() []SurfaceType
}

type SurfaceManagerSurfaceMethods interface {
	// Perform surface operations (create, destroy, move, set) within
	// a 'Do' method to ensure atomic updates to the display
	Do(SurfaceManagerCallback) error

	// Create & destroy surfaces
	CreateSurface(api SurfaceType, flags SurfaceFlags, opacity float32, layer uint16, origin Point, size Size) (Surface, error)
	CreateSurfaceWithBitmap(bitmap Bitmap, flags SurfaceFlags, opacity float32, layer uint16, origin Point, size Size) (Surface, error)
	DestroySurface(Surface) error

	/*
		// Create background, surface and cursors
		CreateBackground(api SurfaceType, flags SurfaceFlags, opacity float32) (Surface, error)
		CreateCursor(api SurfaceType, flags SurfaceFlags, opacity float32, origin Point, cursor SurfaceCursor) (Surface, error)
	*/

	// Change surface properties (size, position, etc)
	SetLayer(Surface, SurfaceFlags, uint16) error
	SetOrigin(Surface, SurfaceFlags, Point) error
	SetOpacity(Surface, SurfaceFlags, float32) error
	/*
		MoveOriginBy(Surface, SurfaceFlags, Point)
		SetSize(Surface, SurfaceFlags, Size)
		SetBitmap(Bitmap) error
	*/
}

type SurfaceManagerBitmapMethods interface {
	// Create and destroy bitmaps
	CreateBitmap(SurfaceType, Size) (Bitmap, error)
	DestroyBitmap(Bitmap) error
}

// Surface is manipulated by surface manager, and used by
// a GPU API (bitmap or vector drawing mostly)
type Surface interface {
	Type() SurfaceType
	Size() Size
	Origin() Point
	Opacity() float32
	Layer() uint16

	//Perform drawing operations on a surface - if it's a bitmap
	//then this reads the bitmap data from the GPU ready to draw on
	//Do(SurfaceCallback) error
}

// Bitmap defines a rectangular bitmap which can be used
// by the GPU
type Bitmap interface {
	Type() SurfaceType
	Size() Size

	// Bitmap operations - requires you to use Do() on
	// the surface in order to operate on the bitmap
	ClearToColorRGBA(color color.RGBA) error
}

/*
type SurfaceCursor interface {
	API()
	Hotspot()
	Size()
}
*/

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	// SurfaceType
	SURFACE_TYPE_NONE SurfaceType = iota
	SURFACE_TYPE_OPENGL
	SURFACE_TYPE_OPENGL_ES
	SURFACE_TYPE_OPENGL_ES2
	SURFACE_TYPE_OPENVG
	SURFACE_TYPE_RGBA32
)

const (
	// SurfaceType
	SURFACE_FLAG_NONE              SurfaceFlags = (1 << iota)
	SURFACE_FLAG_ALPHA_FROM_SOURCE              = (1 << iota)
)

const (
	// SurfaceLayer
	SURFACE_LAYER_BACKGROUND uint16 = 0x0000
	SURFACE_LAYER_DEFAULT    uint16 = 0x0001
	SURFACE_LAYER_MAX        uint16 = 0xFFFE
	SURFACE_LAYER_CURSOR     uint16 = 0xFFFF
)

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (t SurfaceType) String() string {
	switch t {
	case SURFACE_TYPE_OPENGL:
		return "SURFACE_TYPE_OPENGL"
	case SURFACE_TYPE_OPENGL_ES:
		return "SURFACE_TYPE_OPENGL_ES"
	case SURFACE_TYPE_OPENGL_ES2:
		return "SURFACE_TYPE_OPENGL_ES2"
	case SURFACE_TYPE_OPENVG:
		return "SURFACE_TYPE_OPENVG"
	case SURFACE_TYPE_RGBA32:
		return "SURFACE_TYPE_RGBA32"
	default:
		return "[Invalid SurfaceType value]"
	}
}

func (f SurfaceFlags) String() string {
	if f == SURFACE_FLAG_NONE {
		return "SURFACE_FLAG_NONE"
	}
	flags := ""
	// Add flags here
	return strings.Trim(flags, "|")
}
<commit_msg>Added back in surface methods<commit_after>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016-2018
	All Rights Reserved
	Documentation http://djthorpe.github.io/gopi/
	For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import (
	"image/color"
	"strings"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

// SurfaceType of surface (which API it's bound to)
type SurfaceType uint

// SurfaceFlags are flags associated with surface
// usually during operations
type SurfaceFlags uint32

// SurfaceManagerCallback is a function callback for
// performing surface operations
type SurfaceManagerCallback func(SurfaceManager) error

// SurfaceCallback is a function callback for
// performing drawing operations. If it's a bitmap
// the second argument will contain the bitmap
// resource
type SurfaceCallback func(Surface, Bitmap) error

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

// SurfaceManager allows you to open, close and move
// surfaces around an open display
type SurfaceManager interface {
	Driver
	SurfaceManagerSurfaceMethods
	//SurfaceManagerBitmapMethods

	// Return the display associated with the surface manager
	Display() Display

	// Return the name of the surface manager. It's basically the
	// GPU driver
	Name() string

	// Return capabilities for the GPU
	Types() []SurfaceType
}

type SurfaceManagerSurfaceMethods interface {
	// Perform surface operations (create, destroy, move, set) within
	// a 'Do' method to ensure atomic updates to the display
	//Do(SurfaceManagerCallback) error

	// Create & destroy surfaces
	CreateSurface(api SurfaceType, flags SurfaceFlags, opacity float32, layer uint16, origin Point, size Size) (Surface, error)
	CreateSurfaceWithBitmap(bitmap Bitmap, flags SurfaceFlags, opacity float32, layer uint16, origin Point, size Size) (Surface, error)
	DestroySurface(Surface) error

	/*
		// Create background, surface and cursors
		CreateBackground(api SurfaceType, flags SurfaceFlags, opacity float32) (Surface, error)
		CreateCursor(api SurfaceType, flags SurfaceFlags, opacity float32, origin Point, cursor SurfaceCursor) (Surface, error)
	*/

	// Change surface properties (size, position, etc)
	//SetLayer(Surface, SurfaceFlags, uint16) error
	//SetOrigin(Surface, SurfaceFlags, Point) error
	//SetOpacity(Surface, SurfaceFlags, float32) error
	/*
		MoveOriginBy(Surface, SurfaceFlags, Point)
		SetSize(Surface, SurfaceFlags, Size)
		SetBitmap(Bitmap) error
	*/
}

type SurfaceManagerBitmapMethods interface {
	// Create and destroy bitmaps
	CreateBitmap(SurfaceType, Size) (Bitmap, error)
	DestroyBitmap(Bitmap) error
}

// Surface is manipulated by surface manager, and used by
// a GPU API (bitmap or vector drawing mostly)
type Surface interface {
	Type() SurfaceType
	Size() Size
	Origin() Point
	Opacity() float32
	Layer() uint16

	//Perform drawing operations on a surface - if it's a bitmap
	//then this reads the bitmap data from the GPU ready to draw on
	//Do(SurfaceCallback) error
}

// Bitmap defines a rectangular bitmap which can be used
// by the GPU
type Bitmap interface {
	Type() SurfaceType
	Size() Size

	// Bitmap operations - requires you to use Do() on
	// the surface in order to operate on the bitmap
	ClearToColorRGBA(color color.RGBA) error
}

/*
type SurfaceCursor interface {
	API()
	Hotspot()
	Size()
}
*/

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	// SurfaceType
	SURFACE_TYPE_NONE SurfaceType = iota
	SURFACE_TYPE_OPENGL
	SURFACE_TYPE_OPENGL_ES
	SURFACE_TYPE_OPENGL_ES2
	SURFACE_TYPE_OPENVG
	SURFACE_TYPE_RGBA32
)

const (
	// SurfaceType
	SURFACE_FLAG_NONE              SurfaceFlags = (1 << iota)
	SURFACE_FLAG_ALPHA_FROM_SOURCE              = (1 << iota)
)

const (
	// SurfaceLayer
	SURFACE_LAYER_BACKGROUND uint16 = 0x0000
	SURFACE_LAYER_DEFAULT    uint16 = 0x0001
	SURFACE_LAYER_MAX        uint16 = 0xFFFE
	SURFACE_LAYER_CURSOR     uint16 = 0xFFFF
)

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (t SurfaceType) String() string {
	switch t {
	case SURFACE_TYPE_OPENGL:
		return "SURFACE_TYPE_OPENGL"
	case SURFACE_TYPE_OPENGL_ES:
		return "SURFACE_TYPE_OPENGL_ES"
	case SURFACE_TYPE_OPENGL_ES2:
		return "SURFACE_TYPE_OPENGL_ES2"
	case SURFACE_TYPE_OPENVG:
		return "SURFACE_TYPE_OPENVG"
	case SURFACE_TYPE_RGBA32:
		return "SURFACE_TYPE_RGBA32"
	default:
		return "[Invalid SurfaceType value]"
	}
}

func (f SurfaceFlags) String() string {
	if f == SURFACE_FLAG_NONE {
		return "SURFACE_FLAG_NONE"
	}
	flags := ""
	// Add flags here
	return strings.Trim(flags, "|")
}
<|endoftext|>


<commit_before>package common

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
)

var gopath string

// GoPath returns GOPATH env variable value. If it is not set, this function
// will try to call `go env GOPATH` subcommand.
func GoPath() string {
	if gopath != "" {
		return gopath
	}

	path := os.Getenv("GOPATH")
	if len(path) == 0 {
		goCmd := exec.Command("go", "env", "GOPATH")
		out, err := goCmd.Output()
		if err != nil {
			panic(fmt.Sprintf("failed to determine gopath: %v", err))
		}
		path = string(out)
	}
	gopath = path
	return path
}

func TrapSignal(cb func()) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		for sig := range c {
			fmt.Printf("captured %v, exiting...\n", sig)
			if cb != nil {
				cb()
			}
			os.Exit(1)
		}
	}()
	select {}
}

func Exit(s string) {
	fmt.Printf(s + "\n")
	os.Exit(1)
}

func EnsureDir(dir string, mode os.FileMode) error {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, mode)
		if err != nil {
			return fmt.Errorf("Could not create directory %v. %v", dir, err)
		}
	}
	return nil
}

func IsDirEmpty(name string) (bool, error) {
	f, err := os.Open(name)
	if err != nil {
		if os.IsNotExist(err) {
			return true, err
		}
		// Otherwise perhaps a permission
		// error or some other error.
		return false, err
	}
	defer f.Close()

	_, err = f.Readdirnames(1) // Or f.Readdir(1)
	if err == io.EOF {
		return true, nil
	}
	return false, err // Either not empty or error, suits both cases
}

func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	return !os.IsNotExist(err)
}

func ReadFile(filePath string) ([]byte, error) {
	return ioutil.ReadFile(filePath)
}

func MustReadFile(filePath string) []byte {
	fileBytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		Exit(Fmt("MustReadFile failed: %v", err))
		return nil
	}
	return fileBytes
}

func WriteFile(filePath string, contents []byte, mode os.FileMode) error {
	return ioutil.WriteFile(filePath, contents, mode)
}

func MustWriteFile(filePath string, contents []byte, mode os.FileMode) {
	err := WriteFile(filePath, contents, mode)
	if err != nil {
		Exit(Fmt("MustWriteFile failed: %v", err))
	}
}

// WriteFileAtomic writes newBytes to temp and atomically moves to filePath
// when everything else succeeds.
func WriteFileAtomic(filePath string, newBytes []byte, mode os.FileMode) error {
	dir := filepath.Dir(filePath)
	f, err := ioutil.TempFile(dir, "")
	if err != nil {
		return err
	}
	_, err = f.Write(newBytes)
	if err == nil {
		err = f.Sync()
	}
	if closeErr := f.Close(); err == nil {
		err = closeErr
	}
	if permErr := os.Chmod(f.Name(), mode); err == nil {
		err = permErr
	}
	if err == nil {
		err = os.Rename(f.Name(), filePath)
	}
	// any err should result in full cleanup
	if err != nil {
		os.Remove(f.Name())
	}
	return err
}

//--------------------------------------------------------------------------------

func Tempfile(prefix string) (*os.File, string) {
	file, err := ioutil.TempFile("", prefix)
	if err != nil {
		PanicCrisis(err)
	}
	return file, file.Name()
}

func Tempdir(prefix string) (*os.File, string) {
	tempDir := os.TempDir() + "/" + prefix + RandStr(12)
	err := EnsureDir(tempDir, 0700)
	if err != nil {
		panic(Fmt("Error creating temp dir: %v", err))
	}
	dir, err := os.Open(tempDir)
	if err != nil {
		panic(Fmt("Error opening temp dir: %v", err))
	}
	return dir, tempDir
}

//--------------------------------------------------------------------------------

func Prompt(prompt string, defaultValue string) (string, error) {
	fmt.Print(prompt)
	reader := bufio.NewReader(os.Stdin)
	line, err := reader.ReadString('\n')
	if err != nil {
		return defaultValue, err
	} else {
		line = strings.TrimSpace(line)
		if line == "" {
			return defaultValue, nil
		}
		return line, nil
	}
}
<commit_msg>cmn: Kill<commit_after>package common

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
)

var gopath string

// GoPath returns GOPATH env variable value. If it is not set, this function
// will try to call `go env GOPATH` subcommand.
func GoPath() string {
	if gopath != "" {
		return gopath
	}

	path := os.Getenv("GOPATH")
	if len(path) == 0 {
		goCmd := exec.Command("go", "env", "GOPATH")
		out, err := goCmd.Output()
		if err != nil {
			panic(fmt.Sprintf("failed to determine gopath: %v", err))
		}
		path = string(out)
	}
	gopath = path
	return path
}

func TrapSignal(cb func()) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		for sig := range c {
			fmt.Printf("captured %v, exiting...\n", sig)
			if cb != nil {
				cb()
			}
			os.Exit(1)
		}
	}()
	select {}
}

// Kill the running process by sending itself SIGTERM
func Kill() error {
	pid := os.Getpid()
	return syscall.Kill(pid, syscall.SIGTERM)
}

func Exit(s string) {
	fmt.Printf(s + "\n")
	os.Exit(1)
}

func EnsureDir(dir string, mode os.FileMode) error {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, mode)
		if err != nil {
			return fmt.Errorf("Could not create directory %v. %v", dir, err)
		}
	}
	return nil
}

func IsDirEmpty(name string) (bool, error) {
	f, err := os.Open(name)
	if err != nil {
		if os.IsNotExist(err) {
			return true, err
		}
		// Otherwise perhaps a permission
		// error or some other error.
		return false, err
	}
	defer f.Close()

	_, err = f.Readdirnames(1) // Or f.Readdir(1)
	if err == io.EOF {
		return true, nil
	}
	return false, err // Either not empty or error, suits both cases
}

func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	return !os.IsNotExist(err)
}

func ReadFile(filePath string) ([]byte, error) {
	return ioutil.ReadFile(filePath)
}

func MustReadFile(filePath string) []byte {
	fileBytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		Exit(Fmt("MustReadFile failed: %v", err))
		return nil
	}
	return fileBytes
}

func WriteFile(filePath string, contents []byte, mode os.FileMode) error {
	return ioutil.WriteFile(filePath, contents, mode)
}

func MustWriteFile(filePath string, contents []byte, mode os.FileMode) {
	err := WriteFile(filePath, contents, mode)
	if err != nil {
		Exit(Fmt("MustWriteFile failed: %v", err))
	}
}

// WriteFileAtomic writes newBytes to temp and atomically moves to filePath
// when everything else succeeds.
func WriteFileAtomic(filePath string, newBytes []byte, mode os.FileMode) error {
	dir := filepath.Dir(filePath)
	f, err := ioutil.TempFile(dir, "")
	if err != nil {
		return err
	}
	_, err = f.Write(newBytes)
	if err == nil {
		err = f.Sync()
	}
	if closeErr := f.Close(); err == nil {
		err = closeErr
	}
	if permErr := os.Chmod(f.Name(), mode); err == nil {
		err = permErr
	}
	if err == nil {
		err = os.Rename(f.Name(), filePath)
	}
	// any err should result in full cleanup
	if err != nil {
		os.Remove(f.Name())
	}
	return err
}

//--------------------------------------------------------------------------------

func Tempfile(prefix string) (*os.File, string) {
	file, err := ioutil.TempFile("", prefix)
	if err != nil {
		PanicCrisis(err)
	}
	return file, file.Name()
}

func Tempdir(prefix string) (*os.File, string) {
	tempDir := os.TempDir() + "/" + prefix + RandStr(12)
	err := EnsureDir(tempDir, 0700)
	if err != nil {
		panic(Fmt("Error creating temp dir: %v", err))
	}
	dir, err := os.Open(tempDir)
	if err != nil {
		panic(Fmt("Error opening temp dir: %v", err))
	}
	return dir, tempDir
}

//--------------------------------------------------------------------------------

func Prompt(prompt string, defaultValue string) (string, error) {
	fmt.Print(prompt)
	reader := bufio.NewReader(os.Stdin)
	line, err := reader.ReadString('\n')
	if err != nil {
		return defaultValue, err
	} else {
		line = strings.TrimSpace(line)
		if line == "" {
			return defaultValue, nil
		}
		return line, nil
	}
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Nicolas Martin <penguwingithub@gmail.com>
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package gitterbee is a Bee that can interface with Gitter
package gitterbee

import (
	"fmt"

	gitter "github.com/sromku/go-gitter"

	"github.com/muesli/beehive/bees"
)

// GitterBee is a Bee that can interface with Gitter
type GitterBee struct {
	bees.Bee

	eventChan chan bees.Event
	client    *gitter.Gitter
	userID    string

	accessToken string
	rooms       []string
	roomChans   map[string]chan interface{}
}

// Action triggers the actions passed to it.
func (mod *GitterBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}
	switch action.Name {

	case "send":
		var room string
		var message string

		action.Options.Bind("room", &room)
		action.Options.Bind("message", &message)

		roomID, err := mod.client.GetRoomId(room)
		if err != nil {
			mod.LogErrorf("Failed to fetch room ID from uri:", err)
			return outs
		}

		if _, err = mod.client.SendMessage(roomID, message); err != nil {
			mod.LogErrorf("Failed to send message:", err)
			return outs
		}

	case "join":
		var room string
		action.Options.Bind("room", &room)

		mod.join(room)

	case "leave":
		var room string
		action.Options.Bind("room", &room)

		err := mod.leave(room)
		if err != nil {
			mod.LogErrorf("Can't leave room:", err)
		} else {
			mod.Logln("Closed room stream", room)
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// Run executes the Bee's event loop.
func (mod *GitterBee) Run(eventChan chan bees.Event) {
	mod.eventChan = eventChan

	mod.roomChans = make(map[string]chan interface{})
	mod.client = gitter.New(mod.accessToken)
	user, err := mod.client.GetUser()
	if err != nil {
		mod.LogErrorf("Failed to fetch current user: %v", err)
		return
	}
	mod.userID = user.ID

	for _, room := range mod.rooms {
		mod.join(room)
	}

	select {
	case <-mod.SigChan:
		for room := range mod.roomChans {
			mod.leave(room)
		}
		return
	}
}

func (mod *GitterBee) join(room string) error {
	mod.Logln("Joining room", room)

	roomID, err := mod.client.GetRoomId(room)
	if err != nil {
		mod.LogErrorf("Failed to fetch room ID: %v", err)
		return err
	}
	r, err := mod.client.JoinRoom(roomID, mod.userID)
	if err != nil {
		mod.LogErrorf("Failed to join room: %v", err)
		return err
	}

	sigchan := make(chan interface{})
	mod.roomChans[room] = sigchan

	stream := mod.client.Stream(r.ID)
	defer stream.Close()
	go mod.client.Listen(stream)

	go func() {
		for {
			select {
			case <-sigchan:
				mod.Logln("Exiting", room)
				return

			case event := <-stream.Event:
				switch ev := event.Data.(type) {
				case *gitter.MessageReceived:
					mod.handleMessage(room, &ev.Message)
				case *gitter.GitterConnectionClosed:
					// connection was closed
					mod.LogErrorf("Connection closed")
					go mod.join(room)
					return
				}
			}
		}
	}()

	return nil
}

func (mod *GitterBee) leave(room string) error {
	ch, ok := mod.roomChans[room]
	if !ok {
		return fmt.Errorf("Unknown room: %s", room)
	}

	mod.Logln("Closing room", room)
	close(ch)
	delete(mod.roomChans, room)
	return nil
}

func (mod *GitterBee) handleMessage(room string, v *gitter.Message) {
	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "message",
		Options: []bees.Placeholder{
			{
				Name:  "id",
				Type:  "string",
				Value: v.ID,
			},
			{
				Name:  "text",
				Type:  "string",
				Value: v.Text,
			},
			{
				Name:  "username",
				Type:  "string",
				Value: v.From.Username,
			},
			{
				Name:  "room",
				Type:  "string",
				Value: room,
			},
			{
				Name:  "read_by",
				Type:  "int",
				Value: v.ReadBy,
			},
		},
	}
	mod.eventChan <- ev
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *GitterBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("access_token", &mod.accessToken)
	options.Bind("rooms", &mod.rooms)
}
<commit_msg>Verbose error log output in GitterBee (#193)<commit_after>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Nicolas Martin <penguwingithub@gmail.com>
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package gitterbee is a Bee that can interface with Gitter
package gitterbee

import (
	"fmt"

	gitter "github.com/sromku/go-gitter"

	"github.com/muesli/beehive/bees"
)

// GitterBee is a Bee that can interface with Gitter
type GitterBee struct {
	bees.Bee

	eventChan chan bees.Event
	client    *gitter.Gitter
	userID    string

	accessToken string
	rooms       []string
	roomChans   map[string]chan interface{}
}

// Action triggers the actions passed to it.
func (mod *GitterBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}
	switch action.Name {

	case "send":
		var room string
		var message string

		action.Options.Bind("room", &room)
		action.Options.Bind("message", &message)

		roomID, err := mod.client.GetRoomId(room)
		if err != nil {
			mod.LogErrorf("Failed to fetch room ID from uri: %v", err)
			return outs
		}

		if _, err = mod.client.SendMessage(roomID, message); err != nil {
			mod.LogErrorf("Failed to send message: %v", err)
			return outs
		}

	case "join":
		var room string
		action.Options.Bind("room", &room)

		if err := mod.join(room); err != nil {
			mod.LogErrorf("Failed to join room: %v", err)
		}

	case "leave":
		var room string
		action.Options.Bind("room", &room)

		err := mod.leave(room)
		if err != nil {
			mod.LogErrorf("Can't leave room: %v", err)
		} else {
			mod.Logln("Left room:", room)
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// Run executes the Bee's event loop.
func (mod *GitterBee) Run(eventChan chan bees.Event) {
	mod.eventChan = eventChan

	mod.roomChans = make(map[string]chan interface{})
	mod.client = gitter.New(mod.accessToken)
	user, err := mod.client.GetUser()
	if err != nil {
		mod.LogErrorf("Failed to fetch current user: %v", err)
		return
	}
	mod.userID = user.ID

	for _, room := range mod.rooms {
		mod.join(room)
	}

	select {
	case <-mod.SigChan:
		for room := range mod.roomChans {
			mod.leave(room)
		}
		return
	}
}

func (mod *GitterBee) join(room string) error {
	mod.Logln("Joining room", room)

	roomID, err := mod.client.GetRoomId(room)
	if err != nil {
		mod.LogErrorf("Failed to fetch room ID: %v", err)
		return err
	}
	r, err := mod.client.JoinRoom(roomID, mod.userID)
	if err != nil {
		mod.LogErrorf("Failed to join room: %v", err)
		return err
	}

	sigchan := make(chan interface{})
	mod.roomChans[room] = sigchan

	stream := mod.client.Stream(r.ID)
	defer stream.Close()
	go mod.client.Listen(stream)

	go func() {
		for {
			select {
			case <-sigchan:
				mod.Logln("Exiting", room)
				return

			case event := <-stream.Event:
				switch ev := event.Data.(type) {
				case *gitter.MessageReceived:
					mod.handleMessage(room, &ev.Message)
				case *gitter.GitterConnectionClosed:
					// connection was closed
					mod.LogErrorf("Connection closed")
					go mod.join(room)
					return
				}
			}
		}
	}()

	return nil
}

func (mod *GitterBee) leave(room string) error {
	ch, ok := mod.roomChans[room]
	if !ok {
		return fmt.Errorf("Unknown room: %s", room)
	}

	mod.Logln("Closing room", room)
	close(ch)
	delete(mod.roomChans, room)
	return nil
}

func (mod *GitterBee) handleMessage(room string, v *gitter.Message) {
	ev := bees.Event{
		Bee:  mod.Name(),
		Name: "message",
		Options: []bees.Placeholder{
			{
				Name:  "id",
				Type:  "string",
				Value: v.ID,
			},
			{
				Name:  "text",
				Type:  "string",
				Value: v.Text,
			},
			{
				Name:  "username",
				Type:  "string",
				Value: v.From.Username,
			},
			{
				Name:  "room",
				Type:  "string",
				Value: room,
			},
			{
				Name:  "read_by",
				Type:  "int",
				Value: v.ReadBy,
			},
		},
	}
	mod.eventChan <- ev
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *GitterBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("access_token", &mod.accessToken)
	options.Bind("rooms", &mod.rooms)
}
<|endoftext|>


<commit_before>package benchmark

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io"
	"math/rand"
	"net"

	quic "github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func init() {
	var _ = Describe("Benchmarks", func() {
		dataLen := size * /* MB */ (1 << 20)
		data := make([]byte, dataLen)
		rand.Seed(GinkgoRandomSeed())
		rand.Read(data) // no need to check for an error. math.Rand.Read never errors

		for i := range protocol.SupportedVersions {
			version := protocol.SupportedVersions[i]

			Context(fmt.Sprintf("with version %d", version), func() {
				Measure(fmt.Sprintf("transferring a %d MB file", size), func(b Benchmarker) {
					var ln quic.Listener
					serverAddr := make(chan net.Addr)
					handshakeChan := make(chan struct{})
					// start the server
					go func() {
						defer GinkgoRecover()
						var err error
						ln, err = quic.ListenAddr(
							"localhost:0",
							testdata.GetTLSConfig(),
							&quic.Config{Versions: []protocol.VersionNumber{version}},
						)
						Expect(err).ToNot(HaveOccurred())
						serverAddr <- ln.Addr()
						sess, err := ln.Accept()
						Expect(err).ToNot(HaveOccurred())
						// wait for the client to complete the handshake before sending the data
						// this should not be necessary, but due to timing issues on the CIs, this is necessary to avoid sending too many undecryptable packets
						<-handshakeChan
						str, err := sess.OpenStream()
						Expect(err).ToNot(HaveOccurred())
						_, err = str.Write(data)
						Expect(err).ToNot(HaveOccurred())
						err = str.Close()
						Expect(err).ToNot(HaveOccurred())
					}()

					// start the client
					addr := <-serverAddr
					sess, err := quic.DialAddr(
						addr.String(),
						&tls.Config{InsecureSkipVerify: true},
						&quic.Config{Versions: []protocol.VersionNumber{version}},
					)
					Expect(err).ToNot(HaveOccurred())
					close(handshakeChan)
					str, err := sess.AcceptStream()
					Expect(err).ToNot(HaveOccurred())

					buf := &bytes.Buffer{}
					// measure the time it takes to download the dataLen bytes
					// note we're measuring the time for the transfer, i.e. excluding the handshake
					runtime := b.Time("transfer time", func() {
						_, err := io.Copy(buf, str)
						Expect(err).NotTo(HaveOccurred())
					})
					Expect(buf.Bytes()).To(Equal(data))

					b.RecordValue("transfer rate [MB/s]", float64(dataLen)/1e6/runtime.Seconds())

					ln.Close()
					sess.Close(nil)
				}, samples)
			})
		}
	})
}
<commit_msg>fix transfer rate calculation<commit_after>package benchmark

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io"
	"math/rand"
	"net"

	quic "github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/internal/protocol"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func init() {
	var _ = Describe("Benchmarks", func() {
		dataLen := size * /* MB */ 1e6
		data := make([]byte, dataLen)
		rand.Seed(GinkgoRandomSeed())
		rand.Read(data) // no need to check for an error. math.Rand.Read never errors

		for i := range protocol.SupportedVersions {
			version := protocol.SupportedVersions[i]

			Context(fmt.Sprintf("with version %d", version), func() {
				Measure(fmt.Sprintf("transferring a %d MB file", size), func(b Benchmarker) {
					var ln quic.Listener
					serverAddr := make(chan net.Addr)
					handshakeChan := make(chan struct{})
					// start the server
					go func() {
						defer GinkgoRecover()
						var err error
						ln, err = quic.ListenAddr(
							"localhost:0",
							testdata.GetTLSConfig(),
							&quic.Config{Versions: []protocol.VersionNumber{version}},
						)
						Expect(err).ToNot(HaveOccurred())
						serverAddr <- ln.Addr()
						sess, err := ln.Accept()
						Expect(err).ToNot(HaveOccurred())
						// wait for the client to complete the handshake before sending the data
						// this should not be necessary, but due to timing issues on the CIs, this is necessary to avoid sending too many undecryptable packets
						<-handshakeChan
						str, err := sess.OpenStream()
						Expect(err).ToNot(HaveOccurred())
						_, err = str.Write(data)
						Expect(err).ToNot(HaveOccurred())
						err = str.Close()
						Expect(err).ToNot(HaveOccurred())
					}()

					// start the client
					addr := <-serverAddr
					sess, err := quic.DialAddr(
						addr.String(),
						&tls.Config{InsecureSkipVerify: true},
						&quic.Config{Versions: []protocol.VersionNumber{version}},
					)
					Expect(err).ToNot(HaveOccurred())
					close(handshakeChan)
					str, err := sess.AcceptStream()
					Expect(err).ToNot(HaveOccurred())

					buf := &bytes.Buffer{}
					// measure the time it takes to download the dataLen bytes
					// note we're measuring the time for the transfer, i.e. excluding the handshake
					runtime := b.Time("transfer time", func() {
						_, err := io.Copy(buf, str)
						Expect(err).NotTo(HaveOccurred())
					})
					Expect(buf.Bytes()).To(Equal(data))

					b.RecordValue("transfer rate [MB/s]", float64(dataLen)/1e6/runtime.Seconds())

					ln.Close()
					sess.Close(nil)
				}, samples)
			})
		}
	})
}
<|endoftext|>