<commit_before>package tokenstore

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
	"time"

	"github.com/herb-go/herb/cache"
	_ "github.com/herb-go/herb/cache/drivers/freecache"
)

func getStore(ttl time.Duration) *Store {
	c := cache.New()
	err := c.OpenJSON([]byte(testCache))
	if err != nil {
		panic(err)
	}
	err = c.Flush()
	if err != nil {
		panic(err)
	}
	s := New(c, ttl)
	return s
}

func TestField(t *testing.T) {
	var err error
	s := getStore(-1)
	defer s.Cache.Close()
	model := "123456"
	var result string
	testKey := "testkey"
	testOwner := "testowner"
	_, err = s.RegisterField(testKey, model)
	if err != ErrMustRegistePtr {
		t.Fatal(err)
	}
	_, err = s.RegisterField(testKey, nil)
	if err != ErrNilPointer {
		t.Fatal(err)
	}
	field, err := s.RegisterField(testKey, &model)
	if err != nil {
		t.Fatal(err)
	}
	if field.Store != s {
		t.Errorf("Field store error")
	}
	if field.Type != reflect.TypeOf(model) {
		t.Errorf("Field type error")
	}
	td := field.MustLoginTokenData(testOwner, model)
	result = ""
	err = field.LoadFrom(td, &result)
	if err != nil {
		t.Fatal(err)
	}
	if result != model {
		t.Fatal(err)
	}
	result = ""
	err = field.GetFromToken(td.Token(), &result)
	if err != nil {
		t.Fatal(err)
	}
	if result != model {
		t.Errorf("Field GetFromToken error")
	}
}

func TestFieldInRequest(t *testing.T) {
	var err error
	s := getStore(-1)
	defer s.Cache.Close()
	model := "123456"
	modelAfterSet := "set"
	var result string
	testKey := "testkey"
	testOwner := "testowner"
	testHeaderName := "token"
	var token string
	field, err := s.RegisterField(testKey, &model)
	if err != nil {
		t.Fatal(err)
	}
	if field.Store != s {
		t.Errorf("Field store error")
	}
	if field.Type != reflect.TypeOf(model) {
		t.Errorf("Field type error")
	}
	var mux = http.NewServeMux()
	actionTest := func(w http.ResponseWriter, r *http.Request) {
		s.HeaderMiddleware(testHeaderName)(w, r, func(w http.ResponseWriter, r *http.Request) {
			field.Get(r, &result)
			if result != model {
				t.Errorf("Field get error %s", result)
			}
			td, err := field.Store.GetRequestTokenData(r)
			if err != nil {
				t.Fatal(err)
			}
			if token != td.Token() {
				t.Errorf("field.Store.GetRequestTokenData error %s", token)
			}
			tk, err := field.GetToken(r)
			if err != nil {
				t.Fatal(err)
			}
			if tk != token {
				t.Errorf("Field GetToken error %s", tk)
			}
			result = ""
			err = field.GetFromToken(td.Token(), &result)
			if err != nil {
				t.Fatal(err)
			}
			if result != model {
				t.Errorf("Field GetFromToken error %s", tk)
			}
			ex, err := field.ExpiredAt(r)
			if err != nil {
				t.Fatal(err)
			}
			if ex > 0 {
				t.Errorf("Field ExpiredAt error %d", ex)
			}
			mutex, err := field.RwMutex(r)
			if err != nil {
				t.Fatal(err)
			}
			if mutex != td.Mutex {
				t.Errorf("Field mutex error")
			}
			err = field.Set(r, modelAfterSet)
			if err != nil {
				t.Fatal(err)
			}
			result = ""
			err = field.Get(r, &result)
			if err != nil {
				t.Fatal(err)
			}
			if result != modelAfterSet {
				t.Errorf("field.Set error %s", result)
			}
			w.Write([]byte("ok"))
		})
	}
	actionLogin := func(w http.ResponseWriter, r *http.Request) {
		s.HeaderMiddleware(testHeaderName)(w, r, func(w http.ResponseWriter, r *http.Request) {
			td := field.MustLogin(r, testOwner, model)
			w.Write([]byte(td.Token()))
		})
	}
	mux.HandleFunc("/login", actionLogin)
	mux.HandleFunc("/test", actionTest)
	hs := httptest.NewServer(mux)
	c := &http.Client{}
	LoginRequest, err := http.NewRequest("POST", hs.URL+"/login", nil)
	if err != nil {
		t.Fatal(err)
	}
	rep, err := c.Do(LoginRequest)
	if err != nil {
		t.Fatal(err)
	}
	body, err := ioutil.ReadAll(rep.Body)
	if err != nil {
		t.Fatal(err)
	}
	token = string(body)
	TestRequest, err := http.NewRequest("POST", hs.URL+"/test", nil)
	TestRequest.Header.Set(testHeaderName, token)
	rep, err = c.Do(TestRequest)
	if err != nil {
		t.Fatal(err)
	}
	if rep.StatusCode != 200 {
		t.Errorf("HeaderMiddle status error %d", rep.StatusCode)
	}
}
<commit_msg>add more data type<commit_after>package tokenstore

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
	"time"

	"github.com/herb-go/herb/cache"
	_ "github.com/herb-go/herb/cache/drivers/freecache"
)

func getStore(ttl time.Duration) *Store {
	c := cache.New()
	err := c.OpenJSON([]byte(testCache))
	if err != nil {
		panic(err)
	}
	err = c.Flush()
	if err != nil {
		panic(err)
	}
	s := New(c, ttl)
	return s
}

func TestField(t *testing.T) {
	var err error
	s := getStore(-1)
	defer s.Cache.Close()
	model := "123456"
	var result string
	testKey := "testkey"
	type modelStruct struct {
		data string
	}
	structModel := modelStruct{
		data: "test",
	}
	var resutStruct = modelStruct{}
	var testStructKey = "teststructkey"
	var modelInt = 123456
	var resultInt int
	var testIntKey = "testintkey"
	var modelBytes = []byte("testbytes")
	var resultBytes []byte
	var testBytesKey = "testbyteskey"
	var modelMap = map[string]string{
		"test": "test",
	}
	var resultMap map[string]string
	var testMapKey = "testmapkey"
	testOwner := "testowner"
	_, err = s.RegisterField(testKey, model)
	if err != ErrMustRegistePtr {
		t.Fatal(err)
	}
	_, err = s.RegisterField(testKey, nil)
	if err != ErrNilPointer {
		t.Fatal(err)
	}
	field, err := s.RegisterField(testKey, &model)
	if err != nil {
		t.Fatal(err)
	}
	if field.Store != s {
		t.Errorf("Field store error")
	}
	if field.Type != reflect.TypeOf(model) {
		t.Errorf("Field type error")
	}
	td := field.MustLoginTokenData(testOwner, model)
	result = ""
	err = field.LoadFrom(td, &result)
	if err != nil {
		t.Fatal(err)
	}
	if result != model {
		t.Fatal(err)
	}
	result = ""
	err = field.GetFromToken(td.Token(), &result)
	if err != nil {
		t.Fatal(err)
	}
	if result != model {
		t.Errorf("Field GetFromToken error")
	}
	fieldStruct, err := s.RegisterField(testIntKey, &modelStruct{})
	if err != nil {
		t.Fatal(err)
	}
	err = fieldStruct.SaveTo(td, structModel)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldStruct.LoadFrom(td, &resutStruct)
	if err != nil {
		t.Fatal(err)
	}
	if resutStruct.data != structModel.data {
		t.Errorf("field Struct error %s", resutStruct.data)
	}

	fieldInt, err := s.RegisterField(testStructKey, &resultInt)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldInt.SaveTo(td, modelInt)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldInt.LoadFrom(td, &resultInt)
	if err != nil {
		t.Fatal(err)
	}
	if resultInt != modelInt {
		t.Errorf("field int error %d", resultInt)
	}
	fieldBytes, err := s.RegisterField(testBytesKey, &resultBytes)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldBytes.SaveTo(td, modelBytes)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldBytes.LoadFrom(td, &resultBytes)
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Compare(resultBytes, modelBytes) != 0 {
		t.Errorf("field Bytes error %s", string(resultBytes))
	}

	fieldMap, err := s.RegisterField(testMapKey, &resultMap)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldMap.SaveTo(td, modelMap)
	if err != nil {
		t.Fatal(err)
	}
	err = fieldMap.LoadFrom(td, &resultMap)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(resultMap, modelMap) {
		t.Error("field Maps error")
	}
}

func TestFieldInRequest(t *testing.T) {
	var err error
	s := getStore(-1)
	defer s.Cache.Close()
	model := "123456"
	modelAfterSet := "set"
	var result string
	testKey := "testkey"
	testOwner := "testowner"
	testHeaderName := "token"
	var token string
	field, err := s.RegisterField(testKey, &model)
	if err != nil {
		t.Fatal(err)
	}
	if field.Store != s {
		t.Errorf("Field store error")
	}
	if field.Type != reflect.TypeOf(model) {
		t.Errorf("Field type error")
	}
	var mux = http.NewServeMux()
	actionTest := func(w http.ResponseWriter, r *http.Request) {
		s.HeaderMiddleware(testHeaderName)(w, r, func(w http.ResponseWriter, r *http.Request) {
			field.Get(r, &result)
			if result != model {
				t.Errorf("Field get error %s", result)
			}
			td, err := field.Store.GetRequestTokenData(r)
			if err != nil {
				t.Fatal(err)
			}
			if token != td.Token() {
				t.Errorf("field.Store.GetRequestTokenData error %s", token)
			}
			tk, err := field.GetToken(r)
			if err != nil {
				t.Fatal(err)
			}
			if tk != token {
				t.Errorf("Field GetToken error %s", tk)
			}
			result = ""
			err = field.GetFromToken(td.Token(), &result)
			if err != nil {
				t.Fatal(err)
			}
			if result != model {
				t.Errorf("Field GetFromToken error %s", tk)
			}
			ex, err := field.ExpiredAt(r)
			if err != nil {
				t.Fatal(err)
			}
			if ex > 0 {
				t.Errorf("Field ExpiredAt error %d", ex)
			}
			mutex, err := field.RwMutex(r)
			if err != nil {
				t.Fatal(err)
			}
			if mutex != td.Mutex {
				t.Errorf("Field mutex error")
			}
			err = field.Set(r, modelAfterSet)
			if err != nil {
				t.Fatal(err)
			}
			result = ""
			err = field.Get(r, &result)
			if err != nil {
				t.Fatal(err)
			}
			if result != modelAfterSet {
				t.Errorf("field.Set error %s", result)
			}
			w.Write([]byte("ok"))
		})
	}
	actionLogin := func(w http.ResponseWriter, r *http.Request) {
		s.HeaderMiddleware(testHeaderName)(w, r, func(w http.ResponseWriter, r *http.Request) {
			td := field.MustLogin(r, testOwner, model)
			w.Write([]byte(td.Token()))
		})
	}
	mux.HandleFunc("/login", actionLogin)
	mux.HandleFunc("/test", actionTest)
	hs := httptest.NewServer(mux)
	c := &http.Client{}
	LoginRequest, err := http.NewRequest("POST", hs.URL+"/login", nil)
	if err != nil {
		t.Fatal(err)
	}
	rep, err := c.Do(LoginRequest)
	if err != nil {
		t.Fatal(err)
	}
	body, err := ioutil.ReadAll(rep.Body)
	if err != nil {
		t.Fatal(err)
	}
	token = string(body)
	TestRequest, err := http.NewRequest("POST", hs.URL+"/test", nil)
	TestRequest.Header.Set(testHeaderName, token)
	rep, err = c.Do(TestRequest)
	if err != nil {
		t.Fatal(err)
	}
	if rep.StatusCode != 200 {
		t.Errorf("HeaderMiddle status error %d", rep.StatusCode)
	}
}
<|endoftext|>


<commit_before>package pagination

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

	"github.com/rackspace/gophercloud"
)

var (
	// ErrPageNotAvailable is returned from a Pager when a next or previous page is requested, but does not exist.
	ErrPageNotAvailable = errors.New("The requested page does not exist.")
)

// Page must be satisfied by the result type of any resource collection.
// It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated.
// Generally, rather than implementing this interface directly, implementors should embed one of the concrete PageBase structs,
// instead.
// Depending on the pagination strategy of a particular resource, there may be an additional subinterface that the result type
// will need to implement.
type Page interface {

	// NextPageURL generates the URL for the page of data that follows this collection.
	// Return "" if no such page exists.
	NextPageURL() (string, error)

	// IsEmpty returns true if this Page has no items in it.
	IsEmpty() (bool, error)

	// GetBody returns the Page Body. This is used in the `AllPages`.
	GetBody() interface{}
}

// Pager knows how to advance through a specific resource collection, one page at a time.
type Pager struct {
	client *gophercloud.ServiceClient

	initialURL string

	createPage func(r PageResult) Page

	Err error

	// Headers supplies additional HTTP headers to populate on each paged request.
	Headers map[string]string

	PageType Page
}

// NewPager constructs a manually-configured pager.
// Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page.
func NewPager(client *gophercloud.ServiceClient, initialURL string, createPage func(r PageResult) Page) Pager {
	return Pager{
		client:     client,
		initialURL: initialURL,
		createPage: createPage,
	}
}

// WithPageCreator returns a new Pager that substitutes a different page creation function. This is
// useful for overriding List functions in delegation.
func (p Pager) WithPageCreator(createPage func(r PageResult) Page) Pager {
	return Pager{
		client:     p.client,
		initialURL: p.initialURL,
		createPage: createPage,
	}
}

func (p Pager) fetchNextPage(url string) (Page, error) {
	resp, err := Request(p.client, p.Headers, url)
	if err != nil {
		return nil, err
	}

	remembered, err := PageResultFrom(resp)
	if err != nil {
		return nil, err
	}

	return p.createPage(remembered), nil
}

// EachPage iterates over each page returned by a Pager, yielding one at a time to a handler function.
// Return "false" from the handler to prematurely stop iterating.
func (p Pager) EachPage(handler func(Page) (bool, error)) error {
	if p.Err != nil {
		return p.Err
	}
	currentURL := p.initialURL
	for {
		currentPage, err := p.fetchNextPage(currentURL)
		if err != nil {
			return err
		}

		empty, err := currentPage.IsEmpty()
		if err != nil {
			return err
		}
		if empty {
			return nil
		}

		ok, err := handler(currentPage)
		if err != nil {
			return err
		}
		if !ok {
			return nil
		}

		currentURL, err = currentPage.NextPageURL()
		if err != nil {
			return err
		}
		if currentURL == "" {
			return nil
		}
	}
}

// AllPages returns all the pages from a `List` operation in a single page,
// allowing the user to retrieve all the pages at once.
func (p Pager) AllPages() (Page, error) {
	// Having a value of `nil` for `p.PageType` will cause a run-time error.
	if p.PageType == nil {
		return nil, fmt.Errorf("Pager field PageType must be set to successfully call pagination.AllPages method.")
	}
	// pagesSlice holds all the pages until they get converted into as Page Body.
	var pagesSlice []interface{}
	// body will contain the final concatenated Page body.
	var body reflect.Value

	// Grab a test page to ascertain the page body type.
	testPage, err := p.fetchNextPage(p.initialURL)
	if err != nil {
		return nil, err
	}

	// Switch on the page body type. Recognized types are `map[string]interface{}`,
	// `[]byte`, and `[]interface{}`.
	switch testPage.GetBody().(type) {
	case map[string]interface{}:
		// key is the map key for the page body if the body type is `map[string]interface{}`.
		var key string
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().(map[string]interface{})
			for k := range b {
				// If it's a linked page, we don't want the `links`, we want the other one.
				if k != "links" {
					key = k
				}
			}
			pagesSlice = append(pagesSlice, b[key].([]interface{})...)
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Set body to value of type `map[string]interface{}`
		body = reflect.MakeMap(reflect.MapOf(reflect.TypeOf(key), reflect.TypeOf(pagesSlice)))
		body.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(pagesSlice))
	case []byte:
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().([]byte)
			pagesSlice = append(pagesSlice, b)
			// seperate pages with a comma
			pagesSlice = append(pagesSlice, []byte{10})
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Remove the trailing comma.
		pagesSlice = pagesSlice[:len(pagesSlice)-1]
		var b []byte
		// Combine the slice of slices in to a single slice.
		for _, slice := range pagesSlice {
			b = append(b, slice.([]byte)...)
		}
		// Set body to value of type `bytes`.
		body = reflect.New(reflect.TypeOf(b)).Elem()
		body.SetBytes(b)
	case []interface{}:
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().([]interface{})
			pagesSlice = append(pagesSlice, b...)
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Set body to value of type `[]interface{}`
		body = reflect.MakeSlice(reflect.TypeOf(pagesSlice), len(pagesSlice), len(pagesSlice))
		for i, s := range pagesSlice {
			body.Index(i).Set(reflect.ValueOf(s))
		}
	default:
		return nil, fmt.Errorf("Page body has unrecognized type.")
	}

	// Each `Extract*` function is expecting a specific type of page coming back,
	// otherwise the type assertion in those functions will fail. PageType is needed
	// to create a type in this method that has the same type that the `Extract*`
	// function is expecting and set the Body of that object to the concatenated
	// pages.
	page := reflect.New(reflect.TypeOf(p.PageType))
	// Set the page body to be the concatenated pages.
	page.Elem().FieldByName("Body").Set(body)
	// Set any additional headers that were pass along. The `objectstorage` pacakge,
	// for example, passes a Content-Type header.
	h := make(http.Header)
	for k, v := range p.Headers {
		h.Add(k, v)
	}
	page.Elem().FieldByName("Header").Set(reflect.ValueOf(h))
	// Type assert the page to a Page interface so that the type assertion in the
	// `Extract*` methods will work.
	return page.Elem().Interface().(Page), err
}
<commit_msg>add comment for Pager.PageType<commit_after>package pagination

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

	"github.com/rackspace/gophercloud"
)

var (
	// ErrPageNotAvailable is returned from a Pager when a next or previous page is requested, but does not exist.
	ErrPageNotAvailable = errors.New("The requested page does not exist.")
)

// Page must be satisfied by the result type of any resource collection.
// It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated.
// Generally, rather than implementing this interface directly, implementors should embed one of the concrete PageBase structs,
// instead.
// Depending on the pagination strategy of a particular resource, there may be an additional subinterface that the result type
// will need to implement.
type Page interface {

	// NextPageURL generates the URL for the page of data that follows this collection.
	// Return "" if no such page exists.
	NextPageURL() (string, error)

	// IsEmpty returns true if this Page has no items in it.
	IsEmpty() (bool, error)

	// GetBody returns the Page Body. This is used in the `AllPages`.
	GetBody() interface{}
}

// Pager knows how to advance through a specific resource collection, one page at a time.
type Pager struct {
	client *gophercloud.ServiceClient

	initialURL string

	createPage func(r PageResult) Page

	Err error

	// Headers supplies additional HTTP headers to populate on each paged request.
	Headers map[string]string

	// PageType is the type of `Page` the `Extract*` function expects back. This is
	// needed because a type assertion occurs in each `Extract*` function and it will
	// fail if the `Page` doesn't have the expected type.
	PageType Page
}

// NewPager constructs a manually-configured pager.
// Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page.
func NewPager(client *gophercloud.ServiceClient, initialURL string, createPage func(r PageResult) Page) Pager {
	return Pager{
		client:     client,
		initialURL: initialURL,
		createPage: createPage,
	}
}

// WithPageCreator returns a new Pager that substitutes a different page creation function. This is
// useful for overriding List functions in delegation.
func (p Pager) WithPageCreator(createPage func(r PageResult) Page) Pager {
	return Pager{
		client:     p.client,
		initialURL: p.initialURL,
		createPage: createPage,
	}
}

func (p Pager) fetchNextPage(url string) (Page, error) {
	resp, err := Request(p.client, p.Headers, url)
	if err != nil {
		return nil, err
	}

	remembered, err := PageResultFrom(resp)
	if err != nil {
		return nil, err
	}

	return p.createPage(remembered), nil
}

// EachPage iterates over each page returned by a Pager, yielding one at a time to a handler function.
// Return "false" from the handler to prematurely stop iterating.
func (p Pager) EachPage(handler func(Page) (bool, error)) error {
	if p.Err != nil {
		return p.Err
	}
	currentURL := p.initialURL
	for {
		currentPage, err := p.fetchNextPage(currentURL)
		if err != nil {
			return err
		}

		empty, err := currentPage.IsEmpty()
		if err != nil {
			return err
		}
		if empty {
			return nil
		}

		ok, err := handler(currentPage)
		if err != nil {
			return err
		}
		if !ok {
			return nil
		}

		currentURL, err = currentPage.NextPageURL()
		if err != nil {
			return err
		}
		if currentURL == "" {
			return nil
		}
	}
}

// AllPages returns all the pages from a `List` operation in a single page,
// allowing the user to retrieve all the pages at once.
func (p Pager) AllPages() (Page, error) {
	// Having a value of `nil` for `p.PageType` will cause a run-time error.
	if p.PageType == nil {
		return nil, fmt.Errorf("Pager field PageType must be set to successfully call pagination.AllPages method.")
	}
	// pagesSlice holds all the pages until they get converted into as Page Body.
	var pagesSlice []interface{}
	// body will contain the final concatenated Page body.
	var body reflect.Value

	// Grab a test page to ascertain the page body type.
	testPage, err := p.fetchNextPage(p.initialURL)
	if err != nil {
		return nil, err
	}

	// Switch on the page body type. Recognized types are `map[string]interface{}`,
	// `[]byte`, and `[]interface{}`.
	switch testPage.GetBody().(type) {
	case map[string]interface{}:
		// key is the map key for the page body if the body type is `map[string]interface{}`.
		var key string
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().(map[string]interface{})
			for k := range b {
				// If it's a linked page, we don't want the `links`, we want the other one.
				if k != "links" {
					key = k
				}
			}
			pagesSlice = append(pagesSlice, b[key].([]interface{})...)
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Set body to value of type `map[string]interface{}`
		body = reflect.MakeMap(reflect.MapOf(reflect.TypeOf(key), reflect.TypeOf(pagesSlice)))
		body.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(pagesSlice))
	case []byte:
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().([]byte)
			pagesSlice = append(pagesSlice, b)
			// seperate pages with a comma
			pagesSlice = append(pagesSlice, []byte{10})
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Remove the trailing comma.
		pagesSlice = pagesSlice[:len(pagesSlice)-1]
		var b []byte
		// Combine the slice of slices in to a single slice.
		for _, slice := range pagesSlice {
			b = append(b, slice.([]byte)...)
		}
		// Set body to value of type `bytes`.
		body = reflect.New(reflect.TypeOf(b)).Elem()
		body.SetBytes(b)
	case []interface{}:
		// Iterate over the pages to concatenate the bodies.
		err := p.EachPage(func(page Page) (bool, error) {
			b := page.GetBody().([]interface{})
			pagesSlice = append(pagesSlice, b...)
			return true, nil
		})
		if err != nil {
			return nil, err
		}
		// Set body to value of type `[]interface{}`
		body = reflect.MakeSlice(reflect.TypeOf(pagesSlice), len(pagesSlice), len(pagesSlice))
		for i, s := range pagesSlice {
			body.Index(i).Set(reflect.ValueOf(s))
		}
	default:
		return nil, fmt.Errorf("Page body has unrecognized type.")
	}

	// Each `Extract*` function is expecting a specific type of page coming back,
	// otherwise the type assertion in those functions will fail. PageType is needed
	// to create a type in this method that has the same type that the `Extract*`
	// function is expecting and set the Body of that object to the concatenated
	// pages.
	page := reflect.New(reflect.TypeOf(p.PageType))
	// Set the page body to be the concatenated pages.
	page.Elem().FieldByName("Body").Set(body)
	// Set any additional headers that were pass along. The `objectstorage` pacakge,
	// for example, passes a Content-Type header.
	h := make(http.Header)
	for k, v := range p.Headers {
		h.Add(k, v)
	}
	page.Elem().FieldByName("Header").Set(reflect.ValueOf(h))
	// Type assert the page to a Page interface so that the type assertion in the
	// `Extract*` methods will work.
	return page.Elem().Interface().(Page), err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/mail"
	"os"

	"github.com/adrianduke/configr"
)

const (
	EmailFromAddressKey = "email.fromAddress"
	EmailSubjectKey     = "email.subject"
	EmailRetryOnFailKey = "email.retryOnFail"
	EmailMaxRetriesKey  = "email.maxRetries"
)

type Email struct {
	FromAddress string
	Subject     string
	MaxRetries  int  // Note env vars are string
	RetryOnFail bool // Note env vars are string
}

func init() {
	configr.RequireKey(EmailFromAddressKey, "Email from address", func(v interface{}) error {
		_, err := mail.ParseAddress(v.(string))
		return err
	})
	configr.RequireKey(EmailSubjectKey, "Email subject")
	configr.RegisterKey(EmailRetryOnFailKey, "Retry sending email if it fails", false)
	configr.RegisterKey(EmailMaxRetriesKey, "How many times to retry email resending", 3)
}

func main() {
	configr.AddSource(configr.NewEnvVars("configr"))

	if err := configr.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fromAddress, err := configr.String(EmailFromAddressKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	emailSubject, err := configr.String(EmailSubjectKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	retryOnFail, err := configr.Bool(EmailRetryOnFailKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	maxRetries, err := configr.Int(EmailMaxRetriesKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	email := Email{
		FromAddress: fromAddress,
		Subject:     emailSubject,
		MaxRetries:  maxRetries,
		RetryOnFail: retryOnFail,
	}

	fmt.Printf("Values:\n\t%#v\n\n", email)

	// Un-polute environment
	os.Unsetenv("CONFIGR_EMAIL_FROMADDRESS")
	os.Unsetenv("CONFIGR_EMAIL_SUBJECT")
	os.Unsetenv("CONFIGR_EMAIL_RETRYONFAIL")
	os.Unsetenv("CONFIGR_EMAIL_MAXRETRIES")
}
<commit_msg>Go1.3 doesn't support os.Unsetenv, better off leaving the environment poluted with harmless values than write another shim complicating the example<commit_after>package main

import (
	"fmt"
	"net/mail"
	"os"

	"github.com/adrianduke/configr"
)

const (
	EmailFromAddressKey = "email.fromAddress"
	EmailSubjectKey     = "email.subject"
	EmailRetryOnFailKey = "email.retryOnFail"
	EmailMaxRetriesKey  = "email.maxRetries"
)

type Email struct {
	FromAddress string
	Subject     string
	MaxRetries  int  // Note env vars are string
	RetryOnFail bool // Note env vars are string
}

func init() {
	configr.RequireKey(EmailFromAddressKey, "Email from address", func(v interface{}) error {
		_, err := mail.ParseAddress(v.(string))
		return err
	})
	configr.RequireKey(EmailSubjectKey, "Email subject")
	configr.RegisterKey(EmailRetryOnFailKey, "Retry sending email if it fails", false)
	configr.RegisterKey(EmailMaxRetriesKey, "How many times to retry email resending", 3)
}

func main() {
	configr.AddSource(configr.NewEnvVars("configr"))

	if err := configr.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fromAddress, err := configr.String(EmailFromAddressKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	emailSubject, err := configr.String(EmailSubjectKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	retryOnFail, err := configr.Bool(EmailRetryOnFailKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	maxRetries, err := configr.Int(EmailMaxRetriesKey)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	email := Email{
		FromAddress: fromAddress,
		Subject:     emailSubject,
		MaxRetries:  maxRetries,
		RetryOnFail: retryOnFail,
	}

	fmt.Printf("Values:\n\t%#v\n\n", email)
}
<|endoftext|>


<commit_before>package blobstore_test

import (
	"os"
	"path"
	"reflect"
	"sort"
	"testing"

	tu "github.com/nyaxt/otaru/testutils"
)

func TestFileBlobStore_TotalSize(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_totalsize")

	w, err := bs.OpenWriter("hoge")
	if err != nil {
		t.Errorf("Failed to open writer: %v", err)
		return
	}
	if _, err := w.Write([]byte("01234567")); err != nil {
		t.Errorf("Failed to write: %v", err)
		return
	}
	if err := w.Close(); err != nil {
		t.Errorf("Failed to close: %v", err)
		return
	}

	n, err := bs.TotalSize()
	if err != nil {
		t.Errorf("TotalSize() err: %v", err)
	}
	if n != 8 {
		t.Errorf("TotalSize returned unexpected result: %v", n)
	}
}

func TestFileBlobStore_ListBlobs(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_list")

	if err := tu.WriteVersionedBlob(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := tu.WriteVersionedBlob(bs, "fuga", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := os.Mkdir(path.Join(bs.GetBase(), "piyo"), 0755); err != nil {
		t.Errorf("Failed to mkdir dummy blob: %v", err)
		return
	}

	blobs, err := bs.ListBlobs()
	if err != nil {
		t.Errorf("ListBlobs failed: %v", err)
		return
	}
	sort.Strings(blobs)
	if !reflect.DeepEqual(blobs, []string{"fuga", "hoge"}) {
		t.Errorf("ListBlobs wrong result: %v", blobs)
	}
}

func TestFileBlobStore_RemoveBlob(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_rm")

	if err := tu.WriteVersionedBlob(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := tu.AssertBlobVersion(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to read back blob: %v", err)
		return
	}
	if err := tu.WriteVersionedBlob(bs, "safe", 3); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}

	if err := bs.RemoveBlob("hoge"); err != nil {
		t.Errorf("Failed to remove blob: %v", err)
	}

	blobs, err := bs.ListBlobs()
	if err != nil {
		t.Errorf("ListBlobs failed: %v", err)
		return
	}
	if !reflect.DeepEqual(blobs, []string{"safe"}) {
		t.Errorf("ListBlobs wrong result: %v", blobs)
	}

	if _, err := bs.OpenReader("hoge"); err == nil {
		t.Errorf("Open removed file succeeded???")
	}
}
<commit_msg>add test TestFileBlobStore_MultiPRead<commit_after>package blobstore_test

import (
	"os"
	"path"
	"reflect"
	"sort"
	"testing"

	tu "github.com/nyaxt/otaru/testutils"
)

func TestFileBlobStore_MultiPRead(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_multipread")

	w, err := bs.OpenWriter("hoge")
	if err != nil {
		t.Errorf("Failed to open writer: %v", err)
		return
	}
	for i := byte(0); i < 128; i++ {
		if _, err := w.Write([]byte{i}); err != nil {
			t.Errorf("Failed to write: %v", err)
			return
		}
	}
	if err := w.Close(); err != nil {
		t.Errorf("Failed to close: %v", err)
		return
	}

	r, err := bs.OpenReader("hoge")
	if err != nil {
		t.Errorf("Failed to open reader: %v", err)
		return
	}
	r2, err := bs.OpenReader("hoge")
	if err != nil {
		t.Errorf("Failed to open reader: %v", err)
		return
	}
	buf := make([]byte, 1)
	for i := byte(0); i < 64; i++ {
		if _, err := r.Read(buf); err != nil {
			t.Errorf("Failed to read: %v", err)
			return
		}
		if buf[0] != i {
			t.Errorf("mismatch! read %d, expected %d", buf[0], i)
		}
	}
	for i := byte(0); i < 64; i++ {
		if _, err := r2.Read(buf); err != nil {
			t.Errorf("Failed to read: %v", err)
			return
		}
		if buf[0] != i {
			t.Errorf("mismatch! read %d, expected %d", buf[0], i)
		}
	}
	for i := byte(64); i < 128; i++ {
		if _, err := r.Read(buf); err != nil {
			t.Errorf("Failed to read: %v", err)
			return
		}
		if buf[0] != i {
			t.Errorf("mismatch! read %d, expected %d", buf[0], i)
		}
	}

	if err := r.Close(); err != nil {
		t.Errorf("Failed to close: %v", err)
		return
	}
	if err := r2.Close(); err != nil {
		t.Errorf("Failed to close: %v", err)
		return
	}
}

func TestFileBlobStore_TotalSize(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_totalsize")

	w, err := bs.OpenWriter("hoge")
	if err != nil {
		t.Errorf("Failed to open writer: %v", err)
		return
	}
	if _, err := w.Write([]byte("01234567")); err != nil {
		t.Errorf("Failed to write: %v", err)
		return
	}
	if err := w.Close(); err != nil {
		t.Errorf("Failed to close: %v", err)
		return
	}

	n, err := bs.TotalSize()
	if err != nil {
		t.Errorf("TotalSize() err: %v", err)
	}
	if n != 8 {
		t.Errorf("TotalSize returned unexpected result: %v", n)
	}
}

func TestFileBlobStore_ListBlobs(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_list")

	if err := tu.WriteVersionedBlob(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := tu.WriteVersionedBlob(bs, "fuga", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := os.Mkdir(path.Join(bs.GetBase(), "piyo"), 0755); err != nil {
		t.Errorf("Failed to mkdir dummy blob: %v", err)
		return
	}

	blobs, err := bs.ListBlobs()
	if err != nil {
		t.Errorf("ListBlobs failed: %v", err)
		return
	}
	sort.Strings(blobs)
	if !reflect.DeepEqual(blobs, []string{"fuga", "hoge"}) {
		t.Errorf("ListBlobs wrong result: %v", blobs)
	}
}

func TestFileBlobStore_RemoveBlob(t *testing.T) {
	bs := tu.TestFileBlobStoreOfName("filebstest_rm")

	if err := tu.WriteVersionedBlob(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}
	if err := tu.AssertBlobVersion(bs, "hoge", 5); err != nil {
		t.Errorf("Failed to read back blob: %v", err)
		return
	}
	if err := tu.WriteVersionedBlob(bs, "safe", 3); err != nil {
		t.Errorf("Failed to write blob: %v", err)
		return
	}

	if err := bs.RemoveBlob("hoge"); err != nil {
		t.Errorf("Failed to remove blob: %v", err)
	}

	blobs, err := bs.ListBlobs()
	if err != nil {
		t.Errorf("ListBlobs failed: %v", err)
		return
	}
	if !reflect.DeepEqual(blobs, []string{"safe"}) {
		t.Errorf("ListBlobs wrong result: %v", blobs)
	}

	if _, err := bs.OpenReader("hoge"); err == nil {
		t.Errorf("Open removed file succeeded???")
	}
}
<|endoftext|>


<commit_before>//Author: Gary Connelly
//date 29/09/2017<commit_msg>adding main method<commit_after>//Author: Gary Connelly
//date 29/09/2017

package main

import (
	"fmt"
	"strings"
)

func main() {

}<|endoftext|>


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

package main

import (
	"github.com/jacobsa/aws/exp/sdb"
	. "github.com/jacobsa/ogletest"
	"sync"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type integrationTest struct {
	db sdb.SimpleDB

	mutex           sync.Mutex
	itemsToDelete   map[sdb.Domain]sdb.ItemName  // Protected by mutex
	domainsToDelete []string                     // Protected by mutex
}

func (t *integrationTest) SetUp(i *TestInfo) {
	var err error

	// Open a connection.
	t.db, err = sdb.NewSimpleDB(sdb.Region(*g_region), g_accessKey)
	AssertEq(nil, err)
}

func (t *integrationTest) TearDown() {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	AssertEq("", "TODO: Delete domains and items as specified")
}

////////////////////////////////////////////////////////////////////////
// Domains
////////////////////////////////////////////////////////////////////////

type DomainsTest struct {
	integrationTest
}

func init() { RegisterTestSuite(&DomainsTest{}) }

func (t *DomainsTest) InvalidAccessKey() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) DomainsHaveIndependentItems() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) DeleteDomain() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) OpeningTwiceDoesntDeleteExistingItems() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// Items
////////////////////////////////////////////////////////////////////////

type ItemsTest struct {
	integrationTest
}

func init() { RegisterTestSuite(&ItemsTest{}) }

func (t *ItemsTest) WrongAccessKeySecret() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8ItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8AttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8AttributeValue() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongAttributeValue() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) PutThenGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchPutThenGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchPutThenBatchGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetForNonExistentItem() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetForNonExistentItems() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetNonExistentAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetNonExistentAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedValuePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedExistencePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedNonExistencePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SuccessfulPreconditions() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) DeleteParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) DeleteAllAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchDelete() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidSelectQuery() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectAll() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectCount() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithPredicates() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithSortOrder() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithLimit() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectEmptyResultSet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectLargeResultSet() {
	ExpectEq("TODO", "")
}
<commit_msg>Added more names.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"github.com/jacobsa/aws/exp/sdb"
	. "github.com/jacobsa/ogletest"
	"sync"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type integrationTest struct {
	db sdb.SimpleDB

	mutex           sync.Mutex
	itemsToDelete   map[sdb.Domain]sdb.ItemName  // Protected by mutex
	domainsToDelete []Domain                     // Protected by mutex
}

func (t *integrationTest) SetUp(i *TestInfo) {
	var err error

	// Open a connection.
	t.db, err = sdb.NewSimpleDB(sdb.Region(*g_region), g_accessKey)
	AssertEq(nil, err)
}

func (t *integrationTest) TearDown() {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	AssertEq("", "TODO: Delete domains and items as specified")
}

////////////////////////////////////////////////////////////////////////
// Domains
////////////////////////////////////////////////////////////////////////

type DomainsTest struct {
	integrationTest
}

func init() { RegisterTestSuite(&DomainsTest{}) }

func (t *DomainsTest) InvalidAccessKey() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) DomainsHaveIndependentItems() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) Delete() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) OpeningTwiceDoesntDeleteExistingItems() {
	ExpectEq("TODO", "")
}

func (t *DomainsTest) DeleteTwice() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// Items
////////////////////////////////////////////////////////////////////////

type ItemsTest struct {
	integrationTest
}

func init() { RegisterTestSuite(&ItemsTest{}) }

func (t *ItemsTest) WrongAccessKeySecret() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8ItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8AttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidUtf8AttributeValue() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) LongAttributeValue() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) PutThenGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchPutThenGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchPutThenBatchGet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetForNonExistentItem() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetForNonExistentItems() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) GetNonExistentAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchGetNonExistentAttributeName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedValuePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedExistencePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) FailedNonExistencePrecondition() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SuccessfulPreconditions() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) DeleteParticularAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) DeleteAllAttributes() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) BatchDelete() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) InvalidSelectQuery() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectAll() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectItemName() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectCount() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithPredicates() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithSortOrder() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectWithLimit() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectEmptyResultSet() {
	ExpectEq("TODO", "")
}

func (t *ItemsTest) SelectLargeResultSet() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package cluster

import (
	"github.com/smancke/guble/protocol"

	log "github.com/Sirupsen/logrus"
	"github.com/hashicorp/memberlist"

	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
)

// Config is a struct used by the local node when creating and running the guble cluster
type Config struct {
	ID                   int
	Host                 string
	Port                 int
	Remotes              []*net.TCPAddr
	HealthScoreThreshold int
}

type MessageHandler interface {
	HandleMessage(message *protocol.Message) error
}

// Cluster is a struct for managing the `local view` of the guble cluster, as seen by a node.
type Cluster struct {
	// Pointer to a Config struct, based on which the Cluster node is created and runs.
	Config *Config

	// MessageHandler is used for dispatching messages received by this node.
	// Should be set after the node is created with New(), and before Start().
	MessageHandler MessageHandler

	name       string
	memberlist *memberlist.Memberlist
	broadcasts [][]byte
}

//New returns a new instance of the cluster, created using the given Config.
func New(config *Config) (*Cluster, error) {
	c := &Cluster{Config: config, name: fmt.Sprintf("%d", config.ID)}

	memberlistConfig := memberlist.DefaultLANConfig()
	memberlistConfig.Name = c.name
	memberlistConfig.BindAddr = config.Host
	memberlistConfig.BindPort = config.Port
	memberlistConfig.Events = &eventDelegate{}

	//TODO Cosmin temporarily disabling any logging from memberlist, we might want to enable it again using logrus?
	memberlistConfig.LogOutput = ioutil.Discard

	memberlist, err := memberlist.Create(memberlistConfig)
	if err != nil {
		logger.WithField("error", err).Error("Error when creating the internal memberlist of the cluster")
		return nil, err
	}
	c.memberlist = memberlist
	memberlistConfig.Delegate = c
	memberlistConfig.Conflict = c
	return c, nil
}

// Start the cluster module.
func (cluster *Cluster) Start() error {
	logger.WithField("remotes", cluster.Config.Remotes).Debug("Starting Cluster")
	if cluster.MessageHandler == nil {
		errorMessage := "There should be a valid MessageHandler already set-up"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	num, err := cluster.memberlist.Join(cluster.remotesAsStrings())
	if err != nil {
		logger.WithField("error", err).Error("Error when this node wanted to join the cluster")
		return err
	}
	if num == 0 {
		errorMessage := "No remote hosts were successfuly contacted when this node wanted to join the cluster"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	logger.Debug("Started Cluster")
	return nil
}

// Stop the cluster module.
func (cluster *Cluster) Stop() error {
	return cluster.memberlist.Shutdown()
}

// Check returns a non-nil error if the health status of the cluster (as seen by this node) is not perfect.
func (cluster *Cluster) Check() error {
	if healthScore := cluster.memberlist.GetHealthScore(); healthScore > cluster.Config.HealthScoreThreshold {
		errorMessage := "Cluster Health Score is not perfect"
		logger.WithField("healthScore", healthScore).Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

// NotifyMsg is invoked each time a message is received by this node of the cluster; it decodes and dispatches the messages.
func (cluster *Cluster) NotifyMsg(msg []byte) {
	logger.WithField("msgAsBytes", msg).Debug("NotifyMsg")

	cmsg, err := decode(msg)
	if err != nil {
		logger.WithField("err", err).Error("Decoding of cluster message failed")
		return
	}
	logger.WithFields(log.Fields{
		"senderNodeID": cmsg.NodeID,
		"type":         cmsg.Type,
		"body":         string(cmsg.Body),
	}).Debug("NotifyMsg: Received cluster message")

	if cluster.MessageHandler != nil && cmsg.Type == gubleMessage {
		pMessage, err := protocol.ParseMessage(cmsg.Body)
		if err != nil {
			logger.WithField("err", err).Error("Parsing of guble-message contained in cluster-message failed")
			return
		}
		cluster.MessageHandler.HandleMessage(pMessage)
	}
}

func (cluster *Cluster) GetBroadcasts(overhead, limit int) [][]byte {
	b := cluster.broadcasts
	cluster.broadcasts = nil
	return b
}

func (cluster *Cluster) NodeMeta(limit int) []byte {
	return nil
}

func (cluster *Cluster) LocalState(join bool) []byte {
	return nil
}

func (cluster *Cluster) MergeRemoteState(s []byte, join bool) {
}

func (cluster *Cluster) NotifyConflict(existing, other *memberlist.Node) {
	logger.WithFields(log.Fields{
		"existing": *existing,
		"other":    *other,
	}).Panic("NotifyConflict")
}

// BroadcastString broadcasts a string to all the other nodes in the guble cluster
func (cluster *Cluster) BroadcastString(sMessage *string) error {
	logger.WithField("string", sMessage).Debug("BroadcastString")
	cMessage := &message{
		NodeID: cluster.Config.ID,
		Type:   stringMessage,
		Body:   []byte(*sMessage),
	}
	return cluster.broadcastClusterMessage(cMessage)
}

// BroadcastMessage broadcasts a guble-protocol-message to all the other nodes in the guble cluster
func (cluster *Cluster) BroadcastMessage(pMessage *protocol.Message) error {
	logger.WithField("message", pMessage).Debug("BroadcastMessage")
	cMessage := &message{
		NodeID: cluster.Config.ID,
		Type:   gubleMessage,
		Body:   pMessage.Bytes(),
	}
	return cluster.broadcastClusterMessage(cMessage)
}

func (cluster *Cluster) broadcastClusterMessage(cMessage *message) error {
	if cMessage == nil {
		errorMessage := "Could not broadcast a nil cluster-message"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	cMessageBytes, err := cMessage.encode()
	if err != nil {
		logger.WithField("err", err).Error("Could not encode and broadcast cluster-message")
		return err
	}
	for _, node := range cluster.memberlist.Members() {
		if cluster.name == node.Name {
			continue
		}
		logger.WithField("nodeName", node.Name).Debug("Sending cluster-message to a node")
		err := cluster.memberlist.SendToTCP(node, cMessageBytes)
		if err != nil {
			logger.WithFields(log.Fields{
				"err":  err,
				"node": node,
			}).Error("Error sending cluster-message to a node")
			return err
		}
	}
	return nil
}

func (cluster *Cluster) remotesAsStrings() (strings []string) {
	for _, remote := range cluster.Config.Remotes {
		strings = append(strings, remote.IP.String()+":"+strconv.Itoa(remote.Port))
	}
	return
}
<commit_msg>sendToTCP in separate goroutine per node<commit_after>package cluster

import (
	"github.com/smancke/guble/protocol"

	log "github.com/Sirupsen/logrus"
	"github.com/hashicorp/memberlist"

	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
)

// Config is a struct used by the local node when creating and running the guble cluster
type Config struct {
	ID                   int
	Host                 string
	Port                 int
	Remotes              []*net.TCPAddr
	HealthScoreThreshold int
}

type MessageHandler interface {
	HandleMessage(message *protocol.Message) error
}

// Cluster is a struct for managing the `local view` of the guble cluster, as seen by a node.
type Cluster struct {
	// Pointer to a Config struct, based on which the Cluster node is created and runs.
	Config *Config

	// MessageHandler is used for dispatching messages received by this node.
	// Should be set after the node is created with New(), and before Start().
	MessageHandler MessageHandler

	name       string
	memberlist *memberlist.Memberlist
	broadcasts [][]byte
}

//New returns a new instance of the cluster, created using the given Config.
func New(config *Config) (*Cluster, error) {
	c := &Cluster{Config: config, name: fmt.Sprintf("%d", config.ID)}

	memberlistConfig := memberlist.DefaultLANConfig()
	memberlistConfig.Name = c.name
	memberlistConfig.BindAddr = config.Host
	memberlistConfig.BindPort = config.Port
	memberlistConfig.Events = &eventDelegate{}

	//TODO Cosmin temporarily disabling any logging from memberlist, we might want to enable it again using logrus?
	memberlistConfig.LogOutput = ioutil.Discard

	memberlist, err := memberlist.Create(memberlistConfig)
	if err != nil {
		logger.WithField("error", err).Error("Error when creating the internal memberlist of the cluster")
		return nil, err
	}
	c.memberlist = memberlist
	memberlistConfig.Delegate = c
	memberlistConfig.Conflict = c
	return c, nil
}

// Start the cluster module.
func (cluster *Cluster) Start() error {
	logger.WithField("remotes", cluster.Config.Remotes).Debug("Starting Cluster")
	if cluster.MessageHandler == nil {
		errorMessage := "There should be a valid MessageHandler already set-up"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	num, err := cluster.memberlist.Join(cluster.remotesAsStrings())
	if err != nil {
		logger.WithField("error", err).Error("Error when this node wanted to join the cluster")
		return err
	}
	if num == 0 {
		errorMessage := "No remote hosts were successfuly contacted when this node wanted to join the cluster"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	logger.Debug("Started Cluster")
	return nil
}

// Stop the cluster module.
func (cluster *Cluster) Stop() error {
	return cluster.memberlist.Shutdown()
}

// Check returns a non-nil error if the health status of the cluster (as seen by this node) is not perfect.
func (cluster *Cluster) Check() error {
	if healthScore := cluster.memberlist.GetHealthScore(); healthScore > cluster.Config.HealthScoreThreshold {
		errorMessage := "Cluster Health Score is not perfect"
		logger.WithField("healthScore", healthScore).Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

// NotifyMsg is invoked each time a message is received by this node of the cluster; it decodes and dispatches the messages.
func (cluster *Cluster) NotifyMsg(msg []byte) {
	logger.WithField("msgAsBytes", msg).Debug("NotifyMsg")

	cmsg, err := decode(msg)
	if err != nil {
		logger.WithField("err", err).Error("Decoding of cluster message failed")
		return
	}
	logger.WithFields(log.Fields{
		"senderNodeID": cmsg.NodeID,
		"type":         cmsg.Type,
		"body":         string(cmsg.Body),
	}).Debug("NotifyMsg: Received cluster message")

	if cluster.MessageHandler != nil && cmsg.Type == gubleMessage {
		pMessage, err := protocol.ParseMessage(cmsg.Body)
		if err != nil {
			logger.WithField("err", err).Error("Parsing of guble-message contained in cluster-message failed")
			return
		}
		cluster.MessageHandler.HandleMessage(pMessage)
	}
}

func (cluster *Cluster) GetBroadcasts(overhead, limit int) [][]byte {
	b := cluster.broadcasts
	cluster.broadcasts = nil
	return b
}

func (cluster *Cluster) NodeMeta(limit int) []byte {
	return nil
}

func (cluster *Cluster) LocalState(join bool) []byte {
	return nil
}

func (cluster *Cluster) MergeRemoteState(s []byte, join bool) {
}

func (cluster *Cluster) NotifyConflict(existing, other *memberlist.Node) {
	logger.WithFields(log.Fields{
		"existing": *existing,
		"other":    *other,
	}).Panic("NotifyConflict")
}

// BroadcastString broadcasts a string to all the other nodes in the guble cluster
func (cluster *Cluster) BroadcastString(sMessage *string) error {
	logger.WithField("string", sMessage).Debug("BroadcastString")
	cMessage := &message{
		NodeID: cluster.Config.ID,
		Type:   stringMessage,
		Body:   []byte(*sMessage),
	}
	return cluster.broadcastClusterMessage(cMessage)
}

// BroadcastMessage broadcasts a guble-protocol-message to all the other nodes in the guble cluster
func (cluster *Cluster) BroadcastMessage(pMessage *protocol.Message) error {
	logger.WithField("message", pMessage).Debug("BroadcastMessage")
	cMessage := &message{
		NodeID: cluster.Config.ID,
		Type:   gubleMessage,
		Body:   pMessage.Bytes(),
	}
	return cluster.broadcastClusterMessage(cMessage)
}

func (cluster *Cluster) broadcastClusterMessage(cMessage *message) error {
	if cMessage == nil {
		errorMessage := "Could not broadcast a nil cluster-message"
		logger.Error(errorMessage)
		return errors.New(errorMessage)
	}
	cMessageBytes, err := cMessage.encode()
	if err != nil {
		logger.WithField("err", err).Error("Could not encode and broadcast cluster-message")
		return err
	}
	for _, node := range cluster.memberlist.Members() {
		if cluster.name == node.Name {
			continue
		}
		go cluster.sendToNode(node, cMessageBytes)
	}
	return nil
}

func (cluster *Cluster) sendToNode(node *memberlist.Node, msgBytes []byte) {
	logger.WithField("nodeName", node.Name).Debug("Sending cluster-message to a node")
	err := cluster.memberlist.SendToTCP(node, msgBytes)
	if err != nil {
		logger.WithFields(log.Fields{
			"err":  err,
			"node": node,
		}).Error("Error sending cluster-message to a node")
	}
}

func (cluster *Cluster) remotesAsStrings() (strings []string) {
	for _, remote := range cluster.Config.Remotes {
		strings = append(strings, remote.IP.String()+":"+strconv.Itoa(remote.Port))
	}
	return
}
<|endoftext|>


<commit_before>package dht

import "sync"

// RoutingTableSimple ...
type RoutingTableSimple struct {
	mx    sync.RWMutex
	store map[ID]*Peer
}

// Add ...
func (rt *RoutingTableSimple) Add(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; ok {
		return ErrPeerAlreadyExists
	}
	rt.store[peer.ID] = &peer

	return nil
}

// Remove ...
func (rt *RoutingTableSimple) Remove(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; !ok {
		return ErrPeerNotFound
	}
	delete(rt.store, peer.ID)

	return nil
}

// Get ...
func (rt *RoutingTableSimple) Get(id ID) (Peer, error) {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	pr, ok := rt.store[id]
	if !ok {
		return Peer{}, ErrPeerNotFound
	}

	return *pr, nil
}

// Update ...
func (rt *RoutingTableSimple) Update(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; !ok {
		return ErrPeerNotFound
	}
	rt.store[peer.ID] = &peer

	return nil
}

func (rt *RoutingTableSimple) GetPeerIDs() ([]ID, error) {
	rt.mx.Lock()
	defer rt.mx.Unlock()
	ids := make([]ID, len(rt.store))
	for _, peer := range rt.store {
		ids = append(ids, peer.ID)
	}
	return ids, nil
}

func NewSimpleRoutingTable() *RoutingTableSimple {
	return &RoutingTableSimple{
		store: make(map[ID]*Peer),
	}
}
<commit_msg>Fix return correct number of peer ids<commit_after>package dht

import "sync"

// RoutingTableSimple ...
type RoutingTableSimple struct {
	mx    sync.RWMutex
	store map[ID]*Peer
}

// Add ...
func (rt *RoutingTableSimple) Add(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; ok {
		return ErrPeerAlreadyExists
	}
	rt.store[peer.ID] = &peer

	return nil
}

// Remove ...
func (rt *RoutingTableSimple) Remove(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; !ok {
		return ErrPeerNotFound
	}
	delete(rt.store, peer.ID)

	return nil
}

// Get ...
func (rt *RoutingTableSimple) Get(id ID) (Peer, error) {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	pr, ok := rt.store[id]
	if !ok {
		return Peer{}, ErrPeerNotFound
	}

	return *pr, nil
}

// Update ...
func (rt *RoutingTableSimple) Update(peer Peer) error {
	rt.mx.Lock()
	defer rt.mx.Unlock()

	if _, ok := rt.store[peer.ID]; !ok {
		return ErrPeerNotFound
	}
	rt.store[peer.ID] = &peer

	return nil
}

func (rt *RoutingTableSimple) GetPeerIDs() ([]ID, error) {
	rt.mx.Lock()
	defer rt.mx.Unlock()
	ids := make([]ID, len(rt.store))
	i := 0
	for _, peer := range rt.store {
		ids[i] = peer.ID
		i++
	}
	return ids, nil
}

func NewSimpleRoutingTable() *RoutingTableSimple {
	return &RoutingTableSimple{
		store: make(map[ID]*Peer),
	}
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"time"
	"strings"

	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

var marbleIndexStr = "_marbleindex"				//name for the key/value that will store a list of all known marbles
var openTradesStr = "_opentrades"				//name for the key/value that will store all open trades

type Marble struct{
	Name string `json:"name"`					//the fieldtags are needed to keep case from bouncing around
	Color string `json:"color"`
	Size int `json:"size"`
	Balance int `json:"balance"
	User string `json:"user"`
}

type Description struct{
	Color string `json:"color"`
	Size int `json:"size"`
        Balance int `json:"balance"`
}

type AnOpenTrade struct{
	User string `json:"user"`					//user who created the open trade order
	Timestamp int64 `json:"timestamp"`			//utc timestamp of creation
	Want Description  `json:"want"`				//description of desired marble
	Willing []Description `json:"willing"`		//array of marbles willing to trade away
}

type AllTrades struct{
	OpenTrades []AnOpenTrade `json:"open_trades"`
}

// ============================================================================================================================
// Init - reset all the things
// ============================================================================================================================
func (t *SimpleChaincode) init(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var Aval int
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	// Initialize the chaincode
	Aval, err = strconv.Atoi(args[0])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}

	// Write the state to the ledger
	err = stub.PutState("abc", []byte(strconv.Itoa(Aval)))				//making a test var "abc", I find it handy to read/write to it right away to test the network
	if err != nil {
		return nil, err
	}

	var empty []string
	jsonAsBytes, _ := json.Marshal(empty)								//marshal an emtpy array of strings to clear the index
	err = stub.PutState(marbleIndexStr, jsonAsBytes)
	if err != nil {
		return nil, err
	}

	var trades AllTrades
	jsonAsBytes, _ = json.Marshal(trades)								//clear the open trade struct
	err = stub.PutState(openTradesStr, jsonAsBytes)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Run - Our entry point
// ============================================================================================================================
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	fmt.Println("run is running " + function)

	// Handle different functions
	if function == "init" {													//initialize the chaincode state, used as reset
		return t.init(stub, args)
	} else if function == "delete" {										//deletes an entity from its state
		res, err := t.Delete(stub, args)
		cleanTrades(stub)													//lets make sure all open trades are still valid
		return res, err
	} else if function == "write" {											//writes a value to the chaincode state
		return t.Write(stub, args)
	} else if function == "init_marble1" {									//create a new marble
		return t.init_marble1(stub, args)
	} else if function == "set_user" {										//change owner of a marble
		res, err := t.set_user(stub, args)
		cleanTrades(stub)													//lets make sure all open trades are still valid
		return res, err
	} else if function == "open_trade" {									//create a new trade order
		return t.open_trade(stub, args)
	} else if function == "perform_trade" {									//forfill an open trade order
		res, err := t.perform_trade(stub, args)
		cleanTrades(stub)													//lets clean just in case
		return res, err
	} else if function == "remove_trade" {									//cancel an open trade order
		return t.remove_trade(stub, args)
	}
	fmt.Println("run did not find func: " + function)						//error

	return nil, errors.New("Received unknown function invocation")
}

// ============================================================================================================================
// Delete - remove a key/value pair from state
// ============================================================================================================================
func (t *SimpleChaincode) Delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	name := args[0]
	err := stub.DelState(name)													//remove the key from chaincode state
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	//get the marble index
	marblesAsBytes, err := stub.GetState(marbleIndexStr)
	if err != nil {
		return nil, errors.New("Failed to get marble index")
	}
	var marbleIndex []string
	json.Unmarshal(marblesAsBytes, &marbleIndex)								//un stringify it aka JSON.parse()

	//remove marble from index
	for i,val := range marbleIndex{
		fmt.Println(strconv.Itoa(i) + " - looking at " + val + " for " + name)
		if val == name{															//find the correct marble
			fmt.Println("found marble")
			marbleIndex = append(marbleIndex[:i], marbleIndex[i+1:]...)			//remove it
			for x:= range marbleIndex{											//debug prints...
				fmt.Println(string(x) + " - " + marbleIndex[x])
			}
			break
		}
	}
	jsonAsBytes, _ := json.Marshal(marbleIndex)									//save new index
	err = stub.PutState(marbleIndexStr, jsonAsBytes)
	return nil, nil
}

// ============================================================================================================================
// Query - read a variable from chaincode state - (aka read)
// ============================================================================================================================
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var name, jsonResp string
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	name = args[0]
	valAsbytes, err := stub.GetState(name)									//get the var from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
		return nil, errors.New(jsonResp)
	}

	return valAsbytes, nil													//send it onward
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// ============================================================================================================================
// Write - write variable into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) Write(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var name, value string // Entities
	var err error
	fmt.Println("running write()")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2. name of the variable and value to set")
	}

	name = args[0]															//rename for funsies
	value = args[1]
	err = stub.PutState(name, []byte(value))								//write the variable into the chaincode state
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// ============================================================================================================================
// Init Marble - create a new marble, store into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) init_marble1(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//   0       1       2     3       4
	// "asdf", "blue", "35", "bob"     "100"
	if len(args) != 5 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	fmt.Println("- start init marble")
	if len(args[0]) <= 0 {
		return nil, errors.New("1st argument must be a non-empty string")
	}
	if len(args[1]) <= 0 {
		return nil, errors.New("2nd argument must be a non-empty string")
	}
	if len(args[2]) <= 0 {
		return nil, errors.New("3rd argument must be a non-empty string")
	}
	if len(args[3]) <= 0 {
		return nil, errors.New("4th argument must be a non-empty string")
	}
		if len(args[4]) <= 0 {
		return nil, errors.New("5th argument must be a non-empty string")
	}
	size, err := strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("3rd argument must be a numeric string")
	}

	color := strings.ToLower(args[1])
	user := strings.ToLower(args[3])

	str := `{"name": "` + args[0] + `", "color": "` + color + `", "size": ` + strconv.Itoa(size) + `, "user": "` + user + ` + `, "balance": "` + balance + `"}`
	err = stub.PutState(args[0], []byte(str))								//store marble with id as key
	if err != nil {
		return nil, err
	}

	//get the marble index
	marblesAsBytes, err := stub.GetState(marbleIndexStr)
	if err != nil {
		return nil, errors.New("Failed to get marble index")
	}
	var marbleIndex []string
	json.Unmarshal(marblesAsBytes, &marbleIndex)							//un stringify it aka JSON.parse()

	//append
	marbleIndex = append(marbleIndex, args[0])								//add marble name to index list
	fmt.Println("! marble index: ", marbleIndex)
	jsonAsBytes, _ := json.Marshal(marbleIndex)
	err = stub.PutState(marbleIndexStr, jsonAsBytes)						//store name of marble

	fmt.Println("- end init marble")
	return nil, nil
}

// ============================================================================================================================
// Set User Permission on Marble
// ============================================================================================================================
func (t *SimpleChaincode) set_user(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//   0       1
	// "name", "bob"
	if len(args) < 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	fmt.Println("- start set user")
	fmt.Println(args[0] + " - " + args[1])
	marbleAsBytes, err := stub.GetState(args[0])
	if err != nil {
		return nil, errors.New("Failed to get thing")
	}
	res := Marble{}
	json.Unmarshal(marbleAsBytes, &res)										//un stringify it aka JSON.parse()
	res.User = args[1]														//change the user

	jsonAsBytes, _ := json.Marshal(res)
	err = stub.PutState(args[0], jsonAsBytes)								//rewrite the marble with id as key
	if err != nil {
		return nil, err
	}

	fmt.Println("- end set user")
	return nil, nil
}

// ============================================================================================================================
// Open Trade - create an open trade for a marble you want with marbles you have
// ============================================================================================================================
func (t *SimpleChaincode) open_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error
	var will_size int
	var trade_away Description

	//	0        1      2     3      4      5       6   7
	//["bob", "blue", "16","100" , "red", "16","100"] *"blue", "35" ,"100*
	if len(args) < 7 {
		return nil, errors.New("Incorrect number of arguments. Expecting like 7?")
	}
	if len(args)%2 == 0{
		return nil, errors.New("Incorrect number of arguments. Expecting an odd number")
	}

	size1, err := strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("3rd argument must be a numeric string")
	}

	open := AnOpenTrade{}
	open.User = args[0]
	open.Timestamp = makeTimestamp()											//use timestamp as an ID
	open.Want.Color = args[1]
	open.Want.Size =  size1
	open.Want.Balance =  args[3]
	fmt.Println("- start open trade")
	jsonAsBytes, _ := json.Marshal(open)
	err = stub.PutState("_debug1", jsonAsBytes)

	for i:=4; i < len(args); i++ {												//create and append each willing trade
		will_size, err = strconv.Atoi(args[i + 1])
		if err != nil {
			msg := "is not a numeric string " + args[i + 1]
			fmt.Println(msg)
			return nil, errors.New(msg)
		}

		trade_away = Description{}
		trade_away.Color = args[i]
		trade_away.Size =  will_size
		trade_away.Size =  args[i + 2]
		fmt.Println("! created trade_away: " + args[i])
		jsonAsBytes, _ = json.Marshal(trade_away)
		err = stub.PutState("_debug2", jsonAsBytes)

		open.Willing = append(open.Willing, trade_away)
		fmt.Println("! appended willing to open")
		i++;
	}

	//get the open trade struct
	tradesAsBytes, err := stub.GetState(openTradesStr)
	if err != nil {
		return nil, errors.New("Failed to get opentrades")
	}
	var trades AllTrades
	json.Unmarshal(tradesAsBytes, &trades)										//un stringify it aka JSON.parse()

	trades.OpenTrades = append(trades.OpenTrades, open);						//append to open trades
	fmt.Println("! appended open to trades")
	jsonAsBytes, _ = json.Marshal(trades)
	err = stub.PutState(openTradesStr, jsonAsBytes)								//rewrite open orders
	if err != nil {
		return nil, err
	}
	fmt.Println("- end open trade")
	return nil, nil
}

// ============================================================================================================================
// Perform Trade - close an open trade and move ownership
// ============================================================================================================================
func (t *SimpleChaincode) perform_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//	0		1					2					3				4					5
	//[data.id, data.closer.user, data.closer.name, data.opener.user, data.opener.color, data.opener.size,data.opener.balance]
	if len(args) < 7 {
		return nil, errors.New("Incorrect number of arguments. Expecting 7")
	}

	fmt.Println("- start close trade")
	timestamp, err := strconv.ParseInt(args[0], 10, 64)
	if err != nil {
		return nil, errors.New("1st argument must be a numeric string")
	}

	size, err := strconv.Atoi(args[5])
	if err != nil {
		return nil, errors.New("6th argument must be a numeric string")
	}

	//get the open trade struct
	tradesAsBytes, err := stub.GetState(openTradesStr)
	if err != nil {
		return nil, errors.New("Failed to get opentrades")
	}
	var trades AllTrades
	json.Unmarshal(tradesAsBytes, &trades)																//un stringify it aka JSON.parse()

	for i := range trades.OpenTrades{																		//look for the trade
		fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10))
		if trades.OpenTrades[i].Timestamp == timestamp{
			fmt.Println("found the trade");

			marble, e := findMarble4Trade(stub, trades.OpenTrades[i].User, args[4], size)					//find a marble that is suitable from opener
			if(e == nil){
				fmt.Println("! no errors, proceeding")

				t.set_user(stub, []string{args[2], trades.OpenTrades[i].User})								//change owner of selected marble, closer -> opener
				t.set_user(stub, []string{marble.Name, args[1]})											//change owner of selected marble, opener -> closer

				trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...)				//remove trade
				jsonAsBytes, _ := json.Marshal(trades)
				err = stub.PutState(openTradesStr, jsonAsBytes)												//rewrite open orders
				if err != nil {
					return nil, err
				}
			}
		}
	}
	fmt.Println("- end close trade")
	return nil, nil
}

// ============================================================================================================================
// findMarble4Trade - look for a matching marble that this user owns and return it
// ============================================================================================================================
func findMarble4Trade(stub *shim.ChaincodeStub, user string, color string, size int )(m Marble, err error){
	var fail Marble;
	fmt.Println("- start find marble 4 trade")
	fmt.Println("looking for " + user + ", " + color + ", " + strconv.Itoa(size));

	//get the marble index
	marblesAsBytes, err := stub.GetState(marbleIndexStr)
	if err != nil {
		return fail, errors.New("Failed to get marble index")
	}
	var marbleIndex []string
	json.Unmarshal(marblesAsBytes, &marbleIndex)								//un stringify it aka JSON.parse()

	for i:= range marbleIndex{													//iter through all the marbles
		//fmt.Println("looking @ marble name: " + marbleIndex[i]);

		marbleAsBytes, err := stub.GetState(marbleIndex[i])						//grab this marble
		if err != nil {
			return fail, errors.New("Failed to get marble")
		}
		res := Marble{}
		json.Unmarshal(marbleAsBytes, &res)										//un stringify it aka JSON.parse()
		//fmt.Println("looking @ " + res.User + ", " + res.Color + ", " + strconv.Itoa(res.Size));

		//check for user && color && size
		if strings.ToLower(res.User) == strings.ToLower(user) && strings.ToLower(res.Color) == strings.ToLower(color) && res.Size == size && && res.Balance == balance

		{
			fmt.Println("found a marble: " + res.Name)
			fmt.Println("! end find marble 4 trade")
			return res, nil
		}
	}

	fmt.Println("- end find marble 4 trade - error")
	return fail, errors.New("Did not find marble to use in this trade")
}

// ============================================================================================================================
// Make Timestamp - create a timestamp in ms
// ============================================================================================================================
func makeTimestamp() int64 {
    return time.Now().UnixNano() / (int64(time.Millisecond)/int64(time.Nanosecond))
}

// ============================================================================================================================
// Remove Open Trade - close an open trade
// ============================================================================================================================
func (t *SimpleChaincode) remove_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//	0
	//[data.id]
	if len(args) < 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	fmt.Println("- start remove trade")
	timestamp, err := strconv.ParseInt(args[0], 10, 64)
	if err != nil {
		return nil, errors.New("1st argument must be a numeric string")
	}

	//get the open trade struct
	tradesAsBytes, err := stub.GetState(openTradesStr)
	if err != nil {
		return nil, errors.New("Failed to get opentrades")
	}
	var trades AllTrades
	json.Unmarshal(tradesAsBytes, &trades)																//un stringify it aka JSON.parse()

	for i := range trades.OpenTrades{																	//look for the trade
		//fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10))
		if trades.OpenTrades[i].Timestamp == timestamp{
			fmt.Println("found the trade");
			trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...)				//remove this trade
			jsonAsBytes, _ := json.Marshal(trades)
			err = stub.PutState(openTradesStr, jsonAsBytes)												//rewrite open orders
			if err != nil {
				return nil, err
			}
			break
		}
	}

	fmt.Println("- end remove trade")
	return nil, nil
}

// ============================================================================================================================
// Clean Up Open Trades - make sure open trades are still possible, remove choices that are no longer possible, remove trades that have no valid choices
// ============================================================================================================================
func cleanTrades(stub *shim.ChaincodeStub)(err error){
	var didWork = false
	fmt.Println("- start clean trades")

	//get the open trade struct
	tradesAsBytes, err := stub.GetState(openTradesStr)
	if err != nil {
		return errors.New("Failed to get opentrades")
	}
	var trades AllTrades
	json.Unmarshal(tradesAsBytes, &trades)																		//un stringify it aka JSON.parse()

	fmt.Println("# trades " + strconv.Itoa(len(trades.OpenTrades)))
	for i:=0; i<len(trades.OpenTrades); {																		//iter over all the known open trades
		fmt.Println(strconv.Itoa(i) + ": looking at trade " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10))

		fmt.Println("# options " + strconv.Itoa(len(trades.OpenTrades[i].Willing)))
		for x:=0; x<len(trades.OpenTrades[i].Willing); {														//find a marble that is suitable
			fmt.Println("! on next option " + strconv.Itoa(i) + ":" + strconv.Itoa(x))
			_, e := findMarble4Trade(stub, trades.OpenTrades[i].User, trades.OpenTrades[i].Willing[x].Color, trades.OpenTrades[i].Willing[x].Size,trades.OpenTrades[i].Willing[x].Balance)
			if(e != nil){
				fmt.Println("! errors with this option, removing option")
				didWork = true
				trades.OpenTrades[i].Willing = append(trades.OpenTrades[i].Willing[:x], trades.OpenTrades[i].Willing[x+1:]...)	//remove this option
				x--;
			}else{
				fmt.Println("! this option is fine")
			}

			x++
			fmt.Println("! x:" + strconv.Itoa(x))
			if x >= len(trades.OpenTrades[i].Willing) {														//things might have shifted, recalcuate
				break
			}
		}

		if len(trades.OpenTrades[i].Willing) == 0 {
			fmt.Println("! no more options for this trade, removing trade")
			didWork = true
			trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...)					//remove this trade
			i--;
		}

		i++
		fmt.Println("! i:" + strconv.Itoa(i))
		if i >= len(trades.OpenTrades) {																	//things might have shifted, recalcuate
			break
		}
	}

	if(didWork){
		fmt.Println("! saving open trade changes")
		jsonAsBytes, _ := json.Marshal(trades)
		err = stub.PutState(openTradesStr, jsonAsBytes)														//rewrite open orders
		if err != nil {
			return err
		}
	}else{
		fmt.Println("! all open trades are fine")
	}

	fmt.Println("- end clean trades")
	return nil
}
<commit_msg>Delete chaincode1_ex2.go<commit_after><|endoftext|>


<commit_before>package channels

import (
	"flag"
	"fmt"
	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/config"
	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/logger"
	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/utils"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/websocket"
	"github.com/spf13/cobra"
)

func init() {
	channelsCmd.AddCommand(listenChannelCmd)
}

//processWSMessage is the function that processes a WebSocket channel.
func processWSMessage(c *websocket.Conn, done chan struct{}) {
	defer close(done)
	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			logger.Warn("Websocket read:", err)
			return
		}
		utils.Render(string(message))
	}
}

//waitForWSClose waits for an operating system interrupt to stop the websocket and cleanly close it down.
func waitForWSClose(c *websocket.Conn, done chan struct{}) {
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-done:
			return
		case t := <-ticker.C:
			err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
			if err != nil {
				logger.Warn("Websocket write:", err)
				return
			}
		case <-interrupt:
			logger.Warn("interrupt")

			// Cleanly close the connection by sending a close message and then
			// waiting (with timeout) for the server to close the connection.
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				logger.Warn("Websocket write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			return
		}
	}
}

var listenChannelCmd = &cobra.Command{
	Use:   "listen [channel id]",
	Short: "Listens to a channel and sends messages to standard out",
	Long:  `Listens to a channel and sends messages to standard out`,
	Args:  cobra.ExactArgs(1),

	Run: func(cmd *cobra.Command, args []string) {
		profileName, _ := cmd.Root().Flags().GetString("profile")
		config, err := config.GetConfig(profileName)

		if err != nil {
			logger.Fatal(err)
		}

		flag.Parse()

		//Set up the websocket connection
		targetURI := fmt.Sprintf("wss://streaming.%s/channels/%s", config.Environment(), args[0])
		c, _, err := websocket.DefaultDialer.Dial(targetURI, nil)
		if err != nil {
			logger.Fatal("Unable to connect to web socket:", err)
		}
		defer c.Close()
		done := make(chan struct{})

		//Spin off the function as an independently running go func
		go func() {
			processWSMessage(c, done)
		}()

		//Causes the CLI to wait for
		waitForWSClose(c, done)
	},
}
<commit_msg>Removing unnecessary flag.Parse() to fix profile flag bug<commit_after>package channels

import (
	"fmt"
	"os"
	"os/signal"
	"time"

	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/config"
	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/logger"
	"github.com/mypurecloud/platform-client-sdk-cli/build/gc/utils"

	"github.com/gorilla/websocket"
	"github.com/spf13/cobra"
)

func init() {
	channelsCmd.AddCommand(listenChannelCmd)
}

//processWSMessage is the function that processes a WebSocket channel.
func processWSMessage(c *websocket.Conn, done chan struct{}) {
	defer close(done)
	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			logger.Warn("Websocket read:", err)
			return
		}
		utils.Render(string(message))
	}
}

//waitForWSClose waits for an operating system interrupt to stop the websocket and cleanly close it down.
func waitForWSClose(c *websocket.Conn, done chan struct{}) {
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-done:
			return
		case t := <-ticker.C:
			err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
			if err != nil {
				logger.Warn("Websocket write:", err)
				return
			}
		case <-interrupt:
			logger.Warn("interrupt")

			// Cleanly close the connection by sending a close message and then
			// waiting (with timeout) for the server to close the connection.
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				logger.Warn("Websocket write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			return
		}
	}
}

var listenChannelCmd = &cobra.Command{
	Use:   "listen [channel id]",
	Short: "Listens to a channel and sends messages to standard out",
	Long:  `Listens to a channel and sends messages to standard out`,
	Args:  cobra.ExactArgs(1),

	Run: func(cmd *cobra.Command, args []string) {
		profileName, _ := cmd.Root().Flags().GetString("profile")
		config, err := config.GetConfig(profileName)

		if err != nil {
			logger.Fatal(err)
		}

		//Set up the websocket connection
		targetURI := fmt.Sprintf("wss://streaming.%s/channels/%s", config.Environment(), args[0])
		c, _, err := websocket.DefaultDialer.Dial(targetURI, nil)
		if err != nil {
			logger.Fatal("Unable to connect to web socket:", err)
		}
		defer c.Close()
		done := make(chan struct{})

		//Spin off the function as an independently running go func
		go func() {
			processWSMessage(c, done)
		}()

		//Causes the CLI to wait for
		waitForWSClose(c, done)
	},
}
<|endoftext|>


<commit_before>package services

import (
	"fmt"
	"github.com/jbrodriguez/mlog"
	"github.com/jbrodriguez/pubsub"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"jbrodriguez/unbalance/server/dto"
	"jbrodriguez/unbalance/server/lib"
	"jbrodriguez/unbalance/server/model"
	"jbrodriguez/unbalance/server/net"
	// "os"
	"path/filepath"
)

const (
	API_VERSION = "/api/v1"
	CAPACITY    = 3
)

type Server struct {
	Service

	bus      *pubsub.PubSub
	settings *lib.Settings

	engine  *echo.Echo
	mailbox chan *pubsub.Mailbox

	pool map[*net.Connection]bool
}

func NewServer(bus *pubsub.PubSub, settings *lib.Settings) *Server {
	server := &Server{
		bus:      bus,
		settings: settings,
		pool:     make(map[*net.Connection]bool),
	}
	server.init()
	return server
}

func (s *Server) Start() {
	mlog.Info("Starting service Server ...")

	locations := []string{
		".",
		"/usr/local/share/unbalance",
	}

	location := lib.SearchFile("index.html", locations)
	if location == "" {
		msg := ""
		for _, loc := range locations {
			msg += fmt.Sprintf("%s, ", loc)
		}
		mlog.Fatalf("Unable to find index.html. Exiting now. (searched in %s)", msg)
	}

	mlog.Info("Serving files from %s", location)

	s.engine = echo.New()

	s.engine.Use(mw.Logger())
	s.engine.Use(mw.Recover())

	s.engine.Index(filepath.Join(location, "index.html"))
	s.engine.Static("/app", filepath.Join(location, "app"))
	s.engine.Static("/img", filepath.Join(location, "img"))

	s.engine.WebSocket("/skt", s.handleWs)

	api := s.engine.Group(API_VERSION)
	api.Put("/config/folder", s.addFolder)
	api.Get("/config", s.getConfig)
	api.Get("/storage", s.getStorage)

	go s.engine.Run(":6237")

	s.mailbox = s.register(s.bus, "storage:broadcast", s.broadcast)
	go s.react()

	mlog.Info("Server started listening on :6237")
}

func (s *Server) Stop() {
	mlog.Info("stopped service Server ...")
}

func (s *Server) react() {
	for mbox := range s.mailbox {
		// mlog.Info("Core:Topic: %s", mbox.Topic)
		s.dispatch(mbox.Topic, mbox.Content)
	}
}

func (s *Server) getConfig(c *echo.Context) (err error) {
	msg := &pubsub.Message{Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/get/config")

	reply := <-msg.Reply
	resp := reply.(*lib.Config)
	c.JSON(200, &resp)

	return nil
}

func (s *Server) addFolder(c *echo.Context) (err error) {
	var packet dto.Packet

	err = c.Bind(&packet)
	if err != nil {
		mlog.Warning("error binding: %s", err)
	}

	msg := &pubsub.Message{Payload: packet.Payload, Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/config/add/folder")

	reply := <-msg.Reply
	resp := reply.(*lib.Config)
	c.JSON(200, &resp)

	return nil
}

// func (s *Server) saveConfig(c *echo.Context) (err error) {
// 	var config lib.Config

// 	c.Bind(&config)

// 	msg := &pubsub.Message{Payload: &config, Reply: make(chan interface{}, CAPACITY)}
// 	s.bus.Pub(msg, "/set/config")

// 	reply := <-msg.Reply
// 	resp := reply.(*lib.Config)
// 	c.JSON(200, &resp)

// 	return nil
// }

func (s *Server) getStorage(c *echo.Context) (err error) {
	msg := &pubsub.Message{Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/get/storage")

	reply := <-msg.Reply
	resp := reply.(*model.Unraid)
	c.JSON(200, &resp)

	return nil
}

func (s *Server) handleWs(c *echo.Context) (err error) {
	conn := net.NewConnection(c.Socket(), s.onMessage, s.onClose)
	s.pool[conn] = true
	err = conn.Read()
	return err
}

func (s *Server) onMessage(packet *dto.Packet) {
	s.bus.Pub(&pubsub.Message{Payload: packet.Payload}, packet.Topic)
}

func (s *Server) onClose(c *net.Connection, err error) {
	mlog.Warning("closing socket (%+v): %s", c, err)
	if _, ok := s.pool[c]; ok {
		delete(s.pool, c)
	}
}

func (s *Server) broadcast(msg *pubsub.Message) {
	packet := msg.Payload.(*dto.Packet)
	for conn, _ := range s.pool {
		conn.Write(packet)
	}
}

// func (s *Server) noRoute(c *gin.Context) {
// 	var path string
// 	if _, err := os.Stat("./index.html"); err == nil {
// 		path = "./"
// 	} else if _, err := os.Stat(filepath.Join(guiLocation, "index.html")); err == nil {
// 		path = guiLocation
// 	} else {
// 		slashdot, _ := filepath.Abs("./")
// 		mlog.Fatalf("Looked for web ui files in \n %s \n %s \n but didn\\'t find them", slashdot, guiLocation)
// 	}

// 	c.File(filepath.Join(path, "index.html"))
// }
<commit_msg>(back) Fix name of broadcast message<commit_after>package services

import (
	"fmt"
	"github.com/jbrodriguez/mlog"
	"github.com/jbrodriguez/pubsub"
	"github.com/labstack/echo"
	mw "github.com/labstack/echo/middleware"
	"jbrodriguez/unbalance/server/dto"
	"jbrodriguez/unbalance/server/lib"
	"jbrodriguez/unbalance/server/model"
	"jbrodriguez/unbalance/server/net"
	// "os"
	"path/filepath"
)

const (
	API_VERSION = "/api/v1"
	CAPACITY    = 3
)

type Server struct {
	Service

	bus      *pubsub.PubSub
	settings *lib.Settings

	engine  *echo.Echo
	mailbox chan *pubsub.Mailbox

	pool map[*net.Connection]bool
}

func NewServer(bus *pubsub.PubSub, settings *lib.Settings) *Server {
	server := &Server{
		bus:      bus,
		settings: settings,
		pool:     make(map[*net.Connection]bool),
	}
	server.init()
	return server
}

func (s *Server) Start() {
	mlog.Info("Starting service Server ...")

	locations := []string{
		".",
		"/usr/local/share/unbalance",
	}

	location := lib.SearchFile("index.html", locations)
	if location == "" {
		msg := ""
		for _, loc := range locations {
			msg += fmt.Sprintf("%s, ", loc)
		}
		mlog.Fatalf("Unable to find index.html. Exiting now. (searched in %s)", msg)
	}

	mlog.Info("Serving files from %s", location)

	s.engine = echo.New()

	s.engine.Use(mw.Logger())
	s.engine.Use(mw.Recover())

	s.engine.Index(filepath.Join(location, "index.html"))
	s.engine.Static("/app", filepath.Join(location, "app"))
	s.engine.Static("/img", filepath.Join(location, "img"))

	s.engine.WebSocket("/skt", s.handleWs)

	api := s.engine.Group(API_VERSION)
	api.Put("/config/folder", s.addFolder)
	api.Get("/config", s.getConfig)
	api.Get("/storage", s.getStorage)

	go s.engine.Run(":6237")

	s.mailbox = s.register(s.bus, "socket:broadcast", s.broadcast)
	go s.react()

	mlog.Info("Server started listening on :6237")
}

func (s *Server) Stop() {
	mlog.Info("stopped service Server ...")
}

func (s *Server) react() {
	for mbox := range s.mailbox {
		// mlog.Info("Core:Topic: %s", mbox.Topic)
		s.dispatch(mbox.Topic, mbox.Content)
	}
}

func (s *Server) getConfig(c *echo.Context) (err error) {
	msg := &pubsub.Message{Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/get/config")

	reply := <-msg.Reply
	resp := reply.(*lib.Config)
	c.JSON(200, &resp)

	return nil
}

func (s *Server) addFolder(c *echo.Context) (err error) {
	var packet dto.Packet

	err = c.Bind(&packet)
	if err != nil {
		mlog.Warning("error binding: %s", err)
	}

	msg := &pubsub.Message{Payload: packet.Payload, Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/config/add/folder")

	reply := <-msg.Reply
	resp := reply.(*lib.Config)
	c.JSON(200, &resp)

	return nil
}

// func (s *Server) saveConfig(c *echo.Context) (err error) {
// 	var config lib.Config

// 	c.Bind(&config)

// 	msg := &pubsub.Message{Payload: &config, Reply: make(chan interface{}, CAPACITY)}
// 	s.bus.Pub(msg, "/set/config")

// 	reply := <-msg.Reply
// 	resp := reply.(*lib.Config)
// 	c.JSON(200, &resp)

// 	return nil
// }

func (s *Server) getStorage(c *echo.Context) (err error) {
	msg := &pubsub.Message{Reply: make(chan interface{}, CAPACITY)}
	s.bus.Pub(msg, "/get/storage")

	reply := <-msg.Reply
	resp := reply.(*model.Unraid)
	c.JSON(200, &resp)

	return nil
}

func (s *Server) handleWs(c *echo.Context) (err error) {
	conn := net.NewConnection(c.Socket(), s.onMessage, s.onClose)
	s.pool[conn] = true
	err = conn.Read()
	return err
}

func (s *Server) onMessage(packet *dto.Packet) {
	s.bus.Pub(&pubsub.Message{Payload: packet.Payload}, packet.Topic)
}

func (s *Server) onClose(c *net.Connection, err error) {
	mlog.Warning("closing socket (%+v): %s", c, err)
	if _, ok := s.pool[c]; ok {
		delete(s.pool, c)
	}
}

func (s *Server) broadcast(msg *pubsub.Message) {
	packet := msg.Payload.(*dto.Packet)
	for conn, _ := range s.pool {
		conn.Write(packet)
	}
}

// func (s *Server) noRoute(c *gin.Context) {
// 	var path string
// 	if _, err := os.Stat("./index.html"); err == nil {
// 		path = "./"
// 	} else if _, err := os.Stat(filepath.Join(guiLocation, "index.html")); err == nil {
// 		path = guiLocation
// 	} else {
// 		slashdot, _ := filepath.Abs("./")
// 		mlog.Fatalf("Looked for web ui files in \n %s \n %s \n but didn\\'t find them", slashdot, guiLocation)
// 	}

// 	c.File(filepath.Join(path, "index.html"))
// }
<|endoftext|>