<commit_before>//
// Copyright 2012 Nathan Fiedler. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package core

import (
	"bytes"
)

// Pair represents a pair of items, which themselves may be pairs. Pairs can
// be assembled to form arbitrary tree structures, or more commonly, linked
// lists.
type Pair interface {
	// First returns the car of the pair.
	First() interface{}
	// Second returns the first non-Pair thing in cdr.
	Second() interface{}
	// Third returns the second non-Pair thing in cdr.
	Third() interface{}
	// Rest returns the cdr of the Pair.
	Rest() interface{}
	// Len returns the number of things in the list composed of Pairs.
	Len() int
	// String returns the string representation of the pair.
	String() string
	// Reverse returns the chain of Pairs in reverse order.
	Reverse() Pair
	// Map calls function for each thing in the chained pairs.
	Map(f func(interface{}) interface{}) Pair
	// Append adds the given item to the pair, forming a list. The element
	// to which the new value was added is returned, allowing the caller
	// to chain one append operation onto the next to form a chain.
	Append(a interface{}) Pair
	// Join finds the first available slot in the chained Pairs
	// and attaches the given thing there.
	Join(a interface{})
	// setFirst replaces the car of the pair with a.
	setFirst(a interface{})
	// setRest replaces the cdr of the pair with a.
	setRest(a interface{})
}

// pair is a simple implementation of a Pair.
type pair struct {
	first interface{} // the car of the pair
	rest  interface{} // the cdr of the pair
}

// NewPair returns an instance of Pair to hold the single element a.
func NewPair(a interface{}) Pair {
	return &pair{a, theEmptyList}
}

// NewList constructs a list of pairs from the given inputs.
func NewList(a ...interface{}) Pair {
	var head *pair = nil
	var prev *pair = nil
	for _, v := range a {
		next := &pair{v, theEmptyList}
		if head == nil {
			head = next
		} else {
			prev.rest = next
		}
		prev = next
	}
	return head
}

// Cons constructs a pair to hold item a and b such that they are stored in a
// single instance of Pair. This may form an improper list if b is not already
// a proper list.
func Cons(a, b interface{}) Pair {
	return &pair{a, b}
}

// List constructs a proper list to hold a and b such that a and b are in
// distinct instances of Pair, with the empty list marking the end.
func List(a, b interface{}) Pair {
	return &pair{a, &pair{b, theEmptyList}}
}

// Car returns the first element in a list.
func Car(a interface{}) interface{} {
	if a == theEmptyList {
		return nil
	} else if p, ok := a.(Pair); ok {
		return p.First()
	} else {
		return nil
	}
	panic("unreachable code")
}

// Cdr returns the second element in a list.
func Cdr(a interface{}) interface{} {
	if a == theEmptyList {
		return nil
	} else if p, ok := a.(Pair); ok {
		if p.Rest() == theEmptyList {
			return nil
		}
		return p.Rest()
	} else {
		return nil
	}
	panic("unreachable code")
}

// Cxr implements all of the caar, cadr, ... cddddr procedures defined
// in Scheme, where name is the name of the procedure to process.
func Cxr(name string, a interface{}) interface{} {
	x := a
	for i := len(name) - 2; x != nil && i >= 1; i-- {
		if name[i] == 'a' {
			x = Car(x)
		} else if name[i] == 'd' {
			x = Cdr(x)
		} else {
			panic("unsupported function name: " + name)
		}
	}
	return x
}

// setFirst stores the given item as the first item of the pair.
func (p *pair) setFirst(a interface{}) {
	if p != nil {
		p.first = a
	}
}

// setRest stores the given item as the second item of the pair.
func (p *pair) setRest(a interface{}) {
	if p != nil {
		p.rest = a
	}
}

// Append adds the given item to the pair, forming a list. The element to
// which the new value was added is returned, allowing the caller to chain one
// append operation onto the next to form a chain.
func (p *pair) Append(a interface{}) Pair {
	var r Pair = p
	// find the end of the list and append there
	for r != nil {
		if r.Rest() == theEmptyList {
			newr := Cons(a, r.Rest())
			r.setRest(newr)
			r = newr
			break
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			newr := Cons(r.Rest(), a)
			r.setRest(newr)
			r = newr
			break
		}
	}
	return r
}

// Join connects the given object to this pair, forming one list.
// Unlike Append(), this does not convert the object into a pair.
// This may result in an improper list if a is not a proper list.
func (p *pair) Join(a interface{}) {
	var r Pair = p
	// find the end of the list and attach there
	for r != nil {
		if r.Rest() == theEmptyList {
			r.setRest(a)
			break
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			r.setRest(Cons(r.Rest(), a))
			break
		}
	}
}

// First returns the first item in the pair.
func (p *pair) First() interface{} {
	if p != nil {
		return p.first
	}
	return nil
}

// Rest returns the second item in the pair.
func (p *pair) Rest() interface{} {
	if p != nil {
		return p.rest
	}
	return nil
}

// Second returns the second item in the list, or nil if there is no
// such item.
func (p *pair) Second() interface{} {
	if p != nil {
		if p.rest == theEmptyList {
			return nil
		} else if r, ok := p.rest.(Pair); ok {
			return r.First()
		}
		return p.rest
	}
	return nil
}

// Third returns the third item in the list, or nil if there is no such
// item.
func (p *pair) Third() interface{} {
	if p != nil {
		if r1, ok := p.rest.(Pair); ok {
			if r1.Rest() == theEmptyList {
				return nil
			} else if r2, ok := r1.Rest().(Pair); ok {
				return r2.First()
			}
			return r1.Rest()
		}
	}
	return nil
}

// Reverse returns a new list consisting of the elements in this list in
// reverse order.
func (p *pair) Reverse() Pair {
	if p == nil {
		return nil
	}
	var result *pair = nil
	var penultimate *pair = nil
	var pp Pair = p
	for p != nil {
		if result == nil {
			result = &pair{pp.First(), theEmptyList}
		} else {
			result = &pair{pp.First(), result}
			if penultimate == nil {
				penultimate = result
			}
		}
		if pp.Rest() == theEmptyList {
			p = nil
		} else if r, ok := pp.Rest().(Pair); ok {
			pp = r
		} else {
			result = &pair{pp.Rest(), result}
			p = nil
		}
	}
	// tighten up the end of the list
	if penultimate != nil {
		if r, ok := penultimate.rest.(Pair); ok {
			penultimate.rest = r.First()
		}
	} else if result != nil && result.rest != theEmptyList {
		// special case of a single Pair
		if r, ok := result.rest.(Pair); ok {
			result.rest = r.First()
		}
	}
	return result
}

// Len finds the length of the pair, which may be greater than two if
// the pair is part of a list of items.
func (p *pair) Len() int {
	length := 0
	var r Pair = p
	for p != nil {
		length++
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			length++
			p = nil
		}
	}
	return length
}

// Map calls function f on each element of the pair, returning
// a new pair constructed from the values returned by f().
func (p *pair) Map(f func(interface{}) interface{}) Pair {
	var head *pair = nil
	var prev *pair = nil
	var r Pair = p
	for p != nil {
		q := f(r.First())
		var s interface{} = theEmptyList
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			s = f(r.Rest())
			p = nil
		}
		next := &pair{q, s}
		if head == nil {
			head = next
		} else {
			prev.rest = next
		}
		prev = next
	}
	return head
}

// String returns the string form of the pair.
func (p *pair) String() string {
	buf := new(bytes.Buffer)
	buf.WriteString("(")
	var r Pair = p
	for p != nil {
		stringifyBuffer(r.First(), buf)
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			buf.WriteString(" ")
			r = rr
		} else {
			buf.WriteString(" . ")
			stringifyBuffer(r.Rest(), buf)
			p = nil
		}
	}
	buf.WriteString(")")
	return buf.String()
}

// EmptyList is a type unto itself, representing the "empty" value in
// Scheme, as well as marking the end of lists.
type EmptyList int

// Len returns the length of the empty list, which is always zero.
func (e EmptyList) Len() int {
	return 0
}

// String returns the string representation of the empty list, which is
// always "()".
func (e EmptyList) String() string {
	return "()"
}

// First always returns nil.
func (e EmptyList) First() interface{} {
	return nil
}

// Rest always returns nil.
func (e EmptyList) Rest() interface{} {
	return nil
}

// Second always returns nil.
func (e EmptyList) Second() interface{} {
	return nil
}

// Third always returns nil.
func (e EmptyList) Third() interface{} {
	return nil
}

// Reverse always returns the empty list.
func (e EmptyList) Reverse() Pair {
	return theEmptyList
}

// Map always returns the empty list without calling the function.
func (e EmptyList) Map(f func(interface{}) interface{}) Pair {
	return theEmptyList
}

// Append does nothing on an empty list. EmptyList is empty.
func (e EmptyList) Append(a interface{}) Pair {
	return theEmptyList
}

// Join does nothing on an empty list. EmptyList is empty.
func (e EmptyList) Join(a interface{}) {
}

// setFirst does nothing on an empty list. EmptyList is empty.
func (e EmptyList) setFirst(a interface{}) {
}

// setRest does nothing on an empty list. EmptyList is empty.
func (e EmptyList) setRest(a interface{}) {
}

// theEmptyList represents an empty list and may be used as a place holder
// in expressions that require a certain number of values.
var theEmptyList EmptyList = EmptyList(0)

// PairIterator provides a mechanism for visiting all of the elements in
// a chain of Pairs.
type PairIterator interface {
	// HasNext returns true if there are more elements in the chain.
	HasNext() bool
	// Next returns the next element in the pair chain.
	Next() interface{}
	// IsProper returns true if the list was properly terminated.
	IsProper() bool
}

// pairIterator is an implementation of the PairIterator interface.
type pairIterator struct {
	curr   Pair // curr is the Pair currently under consideration
	proper bool // if true, list was proper (e.g. (a b c))
}

// NewPairIterator constructs an iterator for the given Pair.
func NewPairIterator(pair Pair) PairIterator {
	// assume the list is proper
	if pair == theEmptyList {
		return &pairIterator{nil, true}
	}
	return &pairIterator{pair, true}
}

// HasNext indicates if there is another value in the Pair chain.
func (i *pairIterator) HasNext() bool {
	return i.curr != nil
}

// IsProper indicates that the list was a proper list (e.g. (a b c)) versus an
// improper list (e.g. (a b . c). This function will always return true until
// the end of an improper list has been reached.
func (i *pairIterator) IsProper() bool {
	return i.curr != nil || i.proper
}

// Next returns the next value in the Pair chain, returning nil if the end of
// the list has been reached.
func (i *pairIterator) Next() interface{} {
	var result interface{} = nil
	if i.curr != nil {
		if i.proper {
			result = i.curr.First()
			rest := i.curr.Rest()
			if rest == theEmptyList {
				i.curr = nil
			} else if rp, ok := rest.(Pair); ok {
				i.curr = rp
			} else {
				i.proper = false
			}
		} else {
			result = i.curr.Rest()
			i.curr = nil
		}
	}
	return result
}
<commit_msg>Remove PairIterator interface, use struct type<commit_after>//
// Copyright 2012 Nathan Fiedler. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package core

import (
	"bytes"
)

// Pair represents a pair of items, which themselves may be pairs. Pairs can
// be assembled to form arbitrary tree structures, or more commonly, linked
// lists.
type Pair interface {
	// First returns the car of the pair.
	First() interface{}
	// Second returns the first non-Pair thing in cdr.
	Second() interface{}
	// Third returns the second non-Pair thing in cdr.
	Third() interface{}
	// Rest returns the cdr of the Pair.
	Rest() interface{}
	// Len returns the number of things in the list composed of Pairs.
	Len() int
	// String returns the string representation of the pair.
	String() string
	// Reverse returns the chain of Pairs in reverse order.
	Reverse() Pair
	// Map calls function for each thing in the chained pairs.
	Map(f func(interface{}) interface{}) Pair
	// Append adds the given item to the pair, forming a list. The element
	// to which the new value was added is returned, allowing the caller
	// to chain one append operation onto the next to form a chain.
	Append(a interface{}) Pair
	// Join finds the first available slot in the chained Pairs
	// and attaches the given thing there.
	Join(a interface{})
	// setFirst replaces the car of the pair with a.
	setFirst(a interface{})
	// setRest replaces the cdr of the pair with a.
	setRest(a interface{})
}

// pair is a simple implementation of a Pair.
type pair struct {
	first interface{} // the car of the pair
	rest  interface{} // the cdr of the pair
}

// NewPair returns an instance of Pair to hold the single element a.
func NewPair(a interface{}) Pair {
	return &pair{a, theEmptyList}
}

// NewList constructs a list of pairs from the given inputs.
func NewList(a ...interface{}) Pair {
	var head *pair = nil
	var prev *pair = nil
	for _, v := range a {
		next := &pair{v, theEmptyList}
		if head == nil {
			head = next
		} else {
			prev.rest = next
		}
		prev = next
	}
	return head
}

// Cons constructs a pair to hold item a and b such that they are stored in a
// single instance of Pair. This may form an improper list if b is not already
// a proper list.
func Cons(a, b interface{}) Pair {
	return &pair{a, b}
}

// List constructs a proper list to hold a and b such that a and b are in
// distinct instances of Pair, with the empty list marking the end.
func List(a, b interface{}) Pair {
	return &pair{a, &pair{b, theEmptyList}}
}

// Car returns the first element in a list.
func Car(a interface{}) interface{} {
	if a == theEmptyList {
		return nil
	} else if p, ok := a.(Pair); ok {
		return p.First()
	} else {
		return nil
	}
	panic("unreachable code")
}

// Cdr returns the second element in a list.
func Cdr(a interface{}) interface{} {
	if a == theEmptyList {
		return nil
	} else if p, ok := a.(Pair); ok {
		if p.Rest() == theEmptyList {
			return nil
		}
		return p.Rest()
	} else {
		return nil
	}
	panic("unreachable code")
}

// Cxr implements all of the caar, cadr, ... cddddr procedures defined
// in Scheme, where name is the name of the procedure to process.
func Cxr(name string, a interface{}) interface{} {
	x := a
	for i := len(name) - 2; x != nil && i >= 1; i-- {
		if name[i] == 'a' {
			x = Car(x)
		} else if name[i] == 'd' {
			x = Cdr(x)
		} else {
			panic("unsupported function name: " + name)
		}
	}
	return x
}

// setFirst stores the given item as the first item of the pair.
func (p *pair) setFirst(a interface{}) {
	if p != nil {
		p.first = a
	}
}

// setRest stores the given item as the second item of the pair.
func (p *pair) setRest(a interface{}) {
	if p != nil {
		p.rest = a
	}
}

// Append adds the given item to the pair, forming a list. The element to
// which the new value was added is returned, allowing the caller to chain one
// append operation onto the next to form a chain.
func (p *pair) Append(a interface{}) Pair {
	var r Pair = p
	// find the end of the list and append there
	for r != nil {
		if r.Rest() == theEmptyList {
			newr := Cons(a, r.Rest())
			r.setRest(newr)
			r = newr
			break
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			newr := Cons(r.Rest(), a)
			r.setRest(newr)
			r = newr
			break
		}
	}
	return r
}

// Join connects the given object to this pair, forming one list.
// Unlike Append(), this does not convert the object into a pair.
// This may result in an improper list if a is not a proper list.
func (p *pair) Join(a interface{}) {
	var r Pair = p
	// find the end of the list and attach there
	for r != nil {
		if r.Rest() == theEmptyList {
			r.setRest(a)
			break
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			r.setRest(Cons(r.Rest(), a))
			break
		}
	}
}

// First returns the first item in the pair.
func (p *pair) First() interface{} {
	if p != nil {
		return p.first
	}
	return nil
}

// Rest returns the second item in the pair.
func (p *pair) Rest() interface{} {
	if p != nil {
		return p.rest
	}
	return nil
}

// Second returns the second item in the list, or nil if there is no
// such item.
func (p *pair) Second() interface{} {
	if p != nil {
		if p.rest == theEmptyList {
			return nil
		} else if r, ok := p.rest.(Pair); ok {
			return r.First()
		}
		return p.rest
	}
	return nil
}

// Third returns the third item in the list, or nil if there is no such
// item.
func (p *pair) Third() interface{} {
	if p != nil {
		if r1, ok := p.rest.(Pair); ok {
			if r1.Rest() == theEmptyList {
				return nil
			} else if r2, ok := r1.Rest().(Pair); ok {
				return r2.First()
			}
			return r1.Rest()
		}
	}
	return nil
}

// Reverse returns a new list consisting of the elements in this list in
// reverse order.
func (p *pair) Reverse() Pair {
	if p == nil {
		return nil
	}
	var result *pair = nil
	var penultimate *pair = nil
	var pp Pair = p
	for p != nil {
		if result == nil {
			result = &pair{pp.First(), theEmptyList}
		} else {
			result = &pair{pp.First(), result}
			if penultimate == nil {
				penultimate = result
			}
		}
		if pp.Rest() == theEmptyList {
			p = nil
		} else if r, ok := pp.Rest().(Pair); ok {
			pp = r
		} else {
			result = &pair{pp.Rest(), result}
			p = nil
		}
	}
	// tighten up the end of the list
	if penultimate != nil {
		if r, ok := penultimate.rest.(Pair); ok {
			penultimate.rest = r.First()
		}
	} else if result != nil && result.rest != theEmptyList {
		// special case of a single Pair
		if r, ok := result.rest.(Pair); ok {
			result.rest = r.First()
		}
	}
	return result
}

// Len finds the length of the pair, which may be greater than two if
// the pair is part of a list of items.
func (p *pair) Len() int {
	length := 0
	var r Pair = p
	for p != nil {
		length++
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			length++
			p = nil
		}
	}
	return length
}

// Map calls function f on each element of the pair, returning
// a new pair constructed from the values returned by f().
func (p *pair) Map(f func(interface{}) interface{}) Pair {
	var head *pair = nil
	var prev *pair = nil
	var r Pair = p
	for p != nil {
		q := f(r.First())
		var s interface{} = theEmptyList
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			r = rr
		} else {
			s = f(r.Rest())
			p = nil
		}
		next := &pair{q, s}
		if head == nil {
			head = next
		} else {
			prev.rest = next
		}
		prev = next
	}
	return head
}

// String returns the string form of the pair.
func (p *pair) String() string {
	buf := new(bytes.Buffer)
	buf.WriteString("(")
	var r Pair = p
	for p != nil {
		stringifyBuffer(r.First(), buf)
		if r.Rest() == theEmptyList {
			p = nil
		} else if rr, ok := r.Rest().(Pair); ok {
			buf.WriteString(" ")
			r = rr
		} else {
			buf.WriteString(" . ")
			stringifyBuffer(r.Rest(), buf)
			p = nil
		}
	}
	buf.WriteString(")")
	return buf.String()
}

// EmptyList is a type unto itself, representing the "empty" value in
// Scheme, as well as marking the end of lists.
type EmptyList int

// Len returns the length of the empty list, which is always zero.
func (e EmptyList) Len() int {
	return 0
}

// String returns the string representation of the empty list, which is
// always "()".
func (e EmptyList) String() string {
	return "()"
}

// First always returns nil.
func (e EmptyList) First() interface{} {
	return nil
}

// Rest always returns nil.
func (e EmptyList) Rest() interface{} {
	return nil
}

// Second always returns nil.
func (e EmptyList) Second() interface{} {
	return nil
}

// Third always returns nil.
func (e EmptyList) Third() interface{} {
	return nil
}

// Reverse always returns the empty list.
func (e EmptyList) Reverse() Pair {
	return theEmptyList
}

// Map always returns the empty list without calling the function.
func (e EmptyList) Map(f func(interface{}) interface{}) Pair {
	return theEmptyList
}

// Append does nothing on an empty list. EmptyList is empty.
func (e EmptyList) Append(a interface{}) Pair {
	return theEmptyList
}

// Join does nothing on an empty list. EmptyList is empty.
func (e EmptyList) Join(a interface{}) {
}

// setFirst does nothing on an empty list. EmptyList is empty.
func (e EmptyList) setFirst(a interface{}) {
}

// setRest does nothing on an empty list. EmptyList is empty.
func (e EmptyList) setRest(a interface{}) {
}

// theEmptyList represents an empty list and may be used as a place holder
// in expressions that require a certain number of values.
var theEmptyList EmptyList = EmptyList(0)

// PairIterator iterates over a chained Pair, whether proper or not.
type PairIterator struct {
	curr   Pair // curr is the Pair currently under consideration
	proper bool // if true, list was proper (e.g. (a b c))
}

// NewPairIterator constructs an iterator for the given Pair.
func NewPairIterator(pair Pair) *PairIterator {
	// assume the list is proper
	if pair == theEmptyList {
		return &PairIterator{nil, true}
	}
	return &PairIterator{pair, true}
}

// HasNext indicates if there is another value in the Pair chain.
func (i *PairIterator) HasNext() bool {
	return i.curr != nil
}

// IsProper indicates that the list was a proper list (e.g. (a b c)) versus an
// improper list (e.g. (a b . c). This function will always return true until
// the end of an improper list has been reached.
func (i *PairIterator) IsProper() bool {
	return i.curr != nil || i.proper
}

// Next returns the next value in the Pair chain, returning nil if the end of
// the list has been reached.
func (i *PairIterator) Next() interface{} {
	var result interface{} = nil
	if i.curr != nil {
		if i.proper {
			result = i.curr.First()
			rest := i.curr.Rest()
			if rest == theEmptyList {
				i.curr = nil
			} else if rp, ok := rest.(Pair); ok {
				i.curr = rp
			} else {
				i.proper = false
			}
		} else {
			result = i.curr.Rest()
			i.curr = nil
		}
	}
	return result
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

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

// Init resets all the things
func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	}
	fmt.Println("invoke did not find func: " + function)

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

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "getUsername" {
		return fns.GetUsername()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	} else if function == "echo" {
		address := args[0]
		f := "echo"
		arg := args[1]
		return fns.Echo(address, f, arg)
	} else if function == "getDealStatus" {
		return fns.GetDealStatus()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

// Public Functions

func (c ChaincodeFunctions) GetUsername() ([]byte, error) {
    username, _ := c.stub.ReadCertAttribute("username");
	return username, nil
}

func (c ChaincodeFunctions) GetDealStatus() ([]byte, error)  {
	dealStatus, _ := c.stub.GetState("dealStatus")
	return dealStatus, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	_ = c.stub.PutState("dealStatus", []byte(dealStatus))
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealStatus, _ := c.GetDealStatus()
	if(string(dealStatus) != "open") {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	order := Order{Investor: investor, Ioi: ioi, Alloc: 0.0}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) Echo(address string, f string, arg string) ([]byte, error) {
	invokeArgs := util.ToChaincodeArgs(f, arg)
	return c.stub.QueryChaincode(address, invokeArgs)
}

// Private Functions

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}<commit_msg>batch check-in<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

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

// Init resets all the things
func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	}
	fmt.Println("invoke did not find func: " + function)

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

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "getUsername" {
		return fns.GetUsername()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	} else if function == "echo" {
		address := args[0]
		f := "echo"
		arg := args[1]
		return fns.Echo(address, f, arg)
	} else if function == "getDealStatus" {
		return fns.GetDealStatus()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

// Public Functions

func (c ChaincodeFunctions) GetUsername() ([]byte, error) {
    username, err := c.stub.ReadCertAttribute("username");
    if err != nil { return nil, errors.New("Couldn't get attribute 'username'. Error: " + err.Error()) }
	return username, nil
}

func (c ChaincodeFunctions) GetDealStatus() ([]byte, error)  {
	dealStatus, _ := c.stub.GetState("dealStatus")
	return dealStatus, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	_ = c.stub.PutState("dealStatus", []byte(dealStatus))
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealStatus, _ := c.GetDealStatus()
	if(string(dealStatus) != "open") {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	order := Order{Investor: investor, Ioi: ioi, Alloc: 0.0}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) Echo(address string, f string, arg string) ([]byte, error) {
	invokeArgs := util.ToChaincodeArgs(f, arg)
	return c.stub.QueryChaincode(address, invokeArgs)
}

// Private Functions

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}<|endoftext|>


<commit_before>package datastore

import (
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/docker/libkv"
	"github.com/docker/libkv/store"
	"github.com/docker/libkv/store/boltdb"
	"github.com/docker/libkv/store/consul"
	"github.com/docker/libkv/store/etcd"
	"github.com/docker/libkv/store/zookeeper"
	"github.com/docker/libnetwork/types"
)

//DataStore exported
type DataStore interface {
	// GetObject gets data from datastore and unmarshals to the specified object
	GetObject(key string, o KVObject) error
	// PutObject adds a new Record based on an object into the datastore
	PutObject(kvObject KVObject) error
	// PutObjectAtomic provides an atomic add and update operation for a Record
	PutObjectAtomic(kvObject KVObject) error
	// DeleteObject deletes a record
	DeleteObject(kvObject KVObject) error
	// DeleteObjectAtomic performs an atomic delete operation
	DeleteObjectAtomic(kvObject KVObject) error
	// DeleteTree deletes a record
	DeleteTree(kvObject KVObject) error
	// Watchable returns whether the store is watchable are not
	Watchable() bool
	// Watch for changes on a KVObject
	Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)
	// List returns of a list of KVObjects belonging to the parent
	// key. The caller must pass a KVObject of the same type as
	// the objects that need to be listed
	List(string, KVObject) ([]KVObject, error)
	// Scope returns the scope of the store
	Scope() string
	// KVStore returns access to the KV Store
	KVStore() store.Store
	// Close closes the data store
	Close()
}

// ErrKeyModified is raised for an atomic update when the update is working on a stale state
var (
	ErrKeyModified = store.ErrKeyModified
	ErrKeyNotFound = store.ErrKeyNotFound
)

type datastore struct {
	scope string
	store store.Store
	cache *cache
	sync.Mutex
}

// KVObject is  Key/Value interface used by objects to be part of the DataStore
type KVObject interface {
	// Key method lets an object to provide the Key to be used in KV Store
	Key() []string
	// KeyPrefix method lets an object to return immediate parent key that can be used for tree walk
	KeyPrefix() []string
	// Value method lets an object to marshal its content to be stored in the KV store
	Value() []byte
	// SetValue is used by the datastore to set the object's value when loaded from the data store.
	SetValue([]byte) error
	// Index method returns the latest DB Index as seen by the object
	Index() uint64
	// SetIndex method allows the datastore to store the latest DB Index into the object
	SetIndex(uint64)
	// True if the object exists in the datastore, false if it hasn't been stored yet.
	// When SetIndex() is called, the object has been stored.
	Exists() bool
	// DataScope indicates the storage scope of the KV object
	DataScope() string
	// Skip provides a way for a KV Object to avoid persisting it in the KV Store
	Skip() bool
}

// KVConstructor interface defines methods which can construct a KVObject from another.
type KVConstructor interface {
	// New returns a new object which is created based on the
	// source object
	New() KVObject
	// CopyTo deep copies the contents of the implementing object
	// to the passed destination object
	CopyTo(KVObject) error
}

// ScopeCfg represents Datastore configuration.
type ScopeCfg struct {
	Client ScopeClientCfg
}

// ScopeClientCfg represents Datastore Client-only mode configuration
type ScopeClientCfg struct {
	Provider string
	Address  string
	Config   *store.Config
}

const (
	// LocalScope indicates to store the KV object in local datastore such as boltdb
	LocalScope = "local"
	// GlobalScope indicates to store the KV object in global datastore such as consul/etcd/zookeeper
	GlobalScope   = "global"
	defaultPrefix = "/var/lib/docker/network/files"
)

const (
	// NetworkKeyPrefix is the prefix for network key in the kv store
	NetworkKeyPrefix = "network"
	// EndpointKeyPrefix is the prefix for endpoint key in the kv store
	EndpointKeyPrefix = "endpoint"
)

var (
	defaultScopes = makeDefaultScopes()
)

func makeDefaultScopes() map[string]*ScopeCfg {
	def := make(map[string]*ScopeCfg)
	def[LocalScope] = &ScopeCfg{
		Client: ScopeClientCfg{
			Provider: "boltdb",
			Address:  defaultPrefix + "/local-kv.db",
			Config: &store.Config{
				Bucket: "libnetwork",
			},
		},
	}

	return def
}

var rootChain = []string{"docker", "network", "v1.0"}

func init() {
	consul.Register()
	zookeeper.Register()
	etcd.Register()
	boltdb.Register()
}

// DefaultScopes returns a map of default scopes and it's config for clients to use.
func DefaultScopes(dataDir string) map[string]*ScopeCfg {
	if dataDir != "" {
		defaultScopes[LocalScope].Client.Address = dataDir + "/network/files/local-kv.db"
		return defaultScopes
	}

	defaultScopes[LocalScope].Client.Address = defaultPrefix + "/local-kv.db"
	return defaultScopes
}

// IsValid checks if the scope config has valid configuration.
func (cfg *ScopeCfg) IsValid() bool {
	if cfg == nil ||
		strings.TrimSpace(cfg.Client.Provider) == "" ||
		strings.TrimSpace(cfg.Client.Address) == "" {
		return false
	}

	return true
}

//Key provides convenient method to create a Key
func Key(key ...string) string {
	keychain := append(rootChain, key...)
	str := strings.Join(keychain, "/")
	return str + "/"
}

//ParseKey provides convenient method to unpack the key to complement the Key function
func ParseKey(key string) ([]string, error) {
	chain := strings.Split(strings.Trim(key, "/"), "/")

	// The key must atleast be equal to the rootChain in order to be considered as valid
	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
		return nil, types.BadRequestErrorf("invalid Key : %s", key)
	}
	return chain[len(rootChain):], nil
}

// newClient used to connect to KV Store
func newClient(scope string, kv string, addr string, config *store.Config, cached bool) (DataStore, error) {
	if cached && scope != LocalScope {
		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
	}

	if config == nil {
		config = &store.Config{}
	}

	addrs := strings.Split(addr, ",")

	store, err := libkv.NewStore(store.Backend(kv), addrs, config)
	if err != nil {
		return nil, err
	}

	ds := &datastore{scope: scope, store: store}
	if cached {
		ds.cache = newCache(ds)
	}

	return ds, nil
}

// NewDataStore creates a new instance of LibKV data store
func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
	if cfg == nil || cfg.Client.Provider == "" || cfg.Client.Address == "" {
		c, ok := defaultScopes[scope]
		if !ok || c.Client.Provider == "" || c.Client.Address == "" {
			return nil, fmt.Errorf("unexpected scope %s without configuration passed", scope)
		}

		cfg = c
	}

	var cached bool
	if scope == LocalScope {
		cached = true
	}

	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
}

func (ds *datastore) Close() {
	ds.store.Close()
}

func (ds *datastore) Scope() string {
	return ds.scope
}

func (ds *datastore) Watchable() bool {
	return ds.scope != LocalScope
}

func (ds *datastore) Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error) {
	sCh := make(chan struct{})

	ctor, ok := kvObject.(KVConstructor)
	if !ok {
		return nil, fmt.Errorf("error watching object type %T, object does not implement KVConstructor interface", kvObject)
	}

	kvpCh, err := ds.store.Watch(Key(kvObject.Key()...), sCh)
	if err != nil {
		return nil, err
	}

	kvoCh := make(chan KVObject)

	go func() {
		for {
			select {
			case <-stopCh:
				close(sCh)
				return
			case kvPair := <-kvpCh:
				dstO := ctor.New()

				if err := dstO.SetValue(kvPair.Value); err != nil {
					log.Printf("Could not unmarshal kvpair value = %s", string(kvPair.Value))
					break
				}

				dstO.SetIndex(kvPair.LastIndex)
				kvoCh <- dstO
			}
		}
	}()

	return kvoCh, nil
}

func (ds *datastore) KVStore() store.Store {
	return ds.store
}

// PutObjectAtomic adds a new Record based on an object into the datastore
func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
	var (
		previous *store.KVPair
		pair     *store.KVPair
		err      error
	)
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	kvObjValue := kvObject.Value()

	if kvObjValue == nil {
		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
	}

	if kvObject.Skip() {
		goto add_cache
	}

	if kvObject.Exists() {
		previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
	} else {
		previous = nil
	}

	_, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
	if err != nil {
		return err
	}

	kvObject.SetIndex(pair.LastIndex)

add_cache:
	if ds.cache != nil {
		return ds.cache.add(kvObject)
	}

	return nil
}

// PutObject adds a new Record based on an object into the datastore
func (ds *datastore) PutObject(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	if kvObject.Skip() {
		goto add_cache
	}

	if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil {
		return err
	}

add_cache:
	if ds.cache != nil {
		return ds.cache.add(kvObject)
	}

	return nil
}

func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
	kvObjValue := kvObject.Value()

	if kvObjValue == nil {
		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
	}
	return ds.store.Put(Key(key...), kvObjValue, nil)
}

// GetObject returns a record matching the key
func (ds *datastore) GetObject(key string, o KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if ds.cache != nil {
		return ds.cache.get(key, o)
	}

	kvPair, err := ds.store.Get(key)
	if err != nil {
		return err
	}

	if err := o.SetValue(kvPair.Value); err != nil {
		return err
	}

	// Make sure the object has a correct view of the DB index in
	// case we need to modify it and update the DB.
	o.SetIndex(kvPair.LastIndex)
	return nil
}

func (ds *datastore) ensureParent(parent string) error {
	exists, err := ds.store.Exists(parent)
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	return ds.store.Put(parent, []byte{}, &store.WriteOptions{IsDir: true})
}

func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
	ds.Lock()
	defer ds.Unlock()

	if ds.cache != nil {
		return ds.cache.list(kvObject)
	}

	// Bail out right away if the kvObject does not implement KVConstructor
	ctor, ok := kvObject.(KVConstructor)
	if !ok {
		return nil, fmt.Errorf("error listing objects, object does not implement KVConstructor interface")
	}

	// Make sure the parent key exists
	if err := ds.ensureParent(key); err != nil {
		return nil, err
	}

	kvList, err := ds.store.List(key)
	if err != nil {
		return nil, err
	}

	var kvol []KVObject
	for _, kvPair := range kvList {
		if len(kvPair.Value) == 0 {
			continue
		}

		dstO := ctor.New()
		if err := dstO.SetValue(kvPair.Value); err != nil {
			return nil, err
		}

		// Make sure the object has a correct view of the DB index in
		// case we need to modify it and update the DB.
		dstO.SetIndex(kvPair.LastIndex)

		kvol = append(kvol, dstO)
	}

	return kvol, nil
}

// DeleteObject unconditionally deletes a record from the store
func (ds *datastore) DeleteObject(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	// cleaup the cache first
	if ds.cache != nil {
		ds.cache.del(kvObject)
	}

	if kvObject.Skip() {
		return nil
	}

	return ds.store.Delete(Key(kvObject.Key()...))
}

// DeleteObjectAtomic performs atomic delete on a record
func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}

	if kvObject.Skip() {
		goto del_cache
	}

	if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil {
		return err
	}

del_cache:
	// cleanup the cache only if AtomicDelete went through successfully
	if ds.cache != nil {
		return ds.cache.del(kvObject)
	}

	return nil
}

// DeleteTree unconditionally deletes a record from the store
func (ds *datastore) DeleteTree(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	// cleaup the cache first
	if ds.cache != nil {
		ds.cache.del(kvObject)
	}

	if kvObject.Skip() {
		return nil
	}

	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
}
<commit_msg>Fix the daemon panic on consul server restart<commit_after>package datastore

import (
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/docker/libkv"
	"github.com/docker/libkv/store"
	"github.com/docker/libkv/store/boltdb"
	"github.com/docker/libkv/store/consul"
	"github.com/docker/libkv/store/etcd"
	"github.com/docker/libkv/store/zookeeper"
	"github.com/docker/libnetwork/types"
)

//DataStore exported
type DataStore interface {
	// GetObject gets data from datastore and unmarshals to the specified object
	GetObject(key string, o KVObject) error
	// PutObject adds a new Record based on an object into the datastore
	PutObject(kvObject KVObject) error
	// PutObjectAtomic provides an atomic add and update operation for a Record
	PutObjectAtomic(kvObject KVObject) error
	// DeleteObject deletes a record
	DeleteObject(kvObject KVObject) error
	// DeleteObjectAtomic performs an atomic delete operation
	DeleteObjectAtomic(kvObject KVObject) error
	// DeleteTree deletes a record
	DeleteTree(kvObject KVObject) error
	// Watchable returns whether the store is watchable are not
	Watchable() bool
	// Watch for changes on a KVObject
	Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)
	// List returns of a list of KVObjects belonging to the parent
	// key. The caller must pass a KVObject of the same type as
	// the objects that need to be listed
	List(string, KVObject) ([]KVObject, error)
	// Scope returns the scope of the store
	Scope() string
	// KVStore returns access to the KV Store
	KVStore() store.Store
	// Close closes the data store
	Close()
}

// ErrKeyModified is raised for an atomic update when the update is working on a stale state
var (
	ErrKeyModified = store.ErrKeyModified
	ErrKeyNotFound = store.ErrKeyNotFound
)

type datastore struct {
	scope string
	store store.Store
	cache *cache
	sync.Mutex
}

// KVObject is  Key/Value interface used by objects to be part of the DataStore
type KVObject interface {
	// Key method lets an object to provide the Key to be used in KV Store
	Key() []string
	// KeyPrefix method lets an object to return immediate parent key that can be used for tree walk
	KeyPrefix() []string
	// Value method lets an object to marshal its content to be stored in the KV store
	Value() []byte
	// SetValue is used by the datastore to set the object's value when loaded from the data store.
	SetValue([]byte) error
	// Index method returns the latest DB Index as seen by the object
	Index() uint64
	// SetIndex method allows the datastore to store the latest DB Index into the object
	SetIndex(uint64)
	// True if the object exists in the datastore, false if it hasn't been stored yet.
	// When SetIndex() is called, the object has been stored.
	Exists() bool
	// DataScope indicates the storage scope of the KV object
	DataScope() string
	// Skip provides a way for a KV Object to avoid persisting it in the KV Store
	Skip() bool
}

// KVConstructor interface defines methods which can construct a KVObject from another.
type KVConstructor interface {
	// New returns a new object which is created based on the
	// source object
	New() KVObject
	// CopyTo deep copies the contents of the implementing object
	// to the passed destination object
	CopyTo(KVObject) error
}

// ScopeCfg represents Datastore configuration.
type ScopeCfg struct {
	Client ScopeClientCfg
}

// ScopeClientCfg represents Datastore Client-only mode configuration
type ScopeClientCfg struct {
	Provider string
	Address  string
	Config   *store.Config
}

const (
	// LocalScope indicates to store the KV object in local datastore such as boltdb
	LocalScope = "local"
	// GlobalScope indicates to store the KV object in global datastore such as consul/etcd/zookeeper
	GlobalScope   = "global"
	defaultPrefix = "/var/lib/docker/network/files"
)

const (
	// NetworkKeyPrefix is the prefix for network key in the kv store
	NetworkKeyPrefix = "network"
	// EndpointKeyPrefix is the prefix for endpoint key in the kv store
	EndpointKeyPrefix = "endpoint"
)

var (
	defaultScopes = makeDefaultScopes()
)

func makeDefaultScopes() map[string]*ScopeCfg {
	def := make(map[string]*ScopeCfg)
	def[LocalScope] = &ScopeCfg{
		Client: ScopeClientCfg{
			Provider: "boltdb",
			Address:  defaultPrefix + "/local-kv.db",
			Config: &store.Config{
				Bucket: "libnetwork",
			},
		},
	}

	return def
}

var rootChain = []string{"docker", "network", "v1.0"}

func init() {
	consul.Register()
	zookeeper.Register()
	etcd.Register()
	boltdb.Register()
}

// DefaultScopes returns a map of default scopes and it's config for clients to use.
func DefaultScopes(dataDir string) map[string]*ScopeCfg {
	if dataDir != "" {
		defaultScopes[LocalScope].Client.Address = dataDir + "/network/files/local-kv.db"
		return defaultScopes
	}

	defaultScopes[LocalScope].Client.Address = defaultPrefix + "/local-kv.db"
	return defaultScopes
}

// IsValid checks if the scope config has valid configuration.
func (cfg *ScopeCfg) IsValid() bool {
	if cfg == nil ||
		strings.TrimSpace(cfg.Client.Provider) == "" ||
		strings.TrimSpace(cfg.Client.Address) == "" {
		return false
	}

	return true
}

//Key provides convenient method to create a Key
func Key(key ...string) string {
	keychain := append(rootChain, key...)
	str := strings.Join(keychain, "/")
	return str + "/"
}

//ParseKey provides convenient method to unpack the key to complement the Key function
func ParseKey(key string) ([]string, error) {
	chain := strings.Split(strings.Trim(key, "/"), "/")

	// The key must atleast be equal to the rootChain in order to be considered as valid
	if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
		return nil, types.BadRequestErrorf("invalid Key : %s", key)
	}
	return chain[len(rootChain):], nil
}

// newClient used to connect to KV Store
func newClient(scope string, kv string, addr string, config *store.Config, cached bool) (DataStore, error) {
	if cached && scope != LocalScope {
		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
	}

	if config == nil {
		config = &store.Config{}
	}

	addrs := strings.Split(addr, ",")

	store, err := libkv.NewStore(store.Backend(kv), addrs, config)
	if err != nil {
		return nil, err
	}

	ds := &datastore{scope: scope, store: store}
	if cached {
		ds.cache = newCache(ds)
	}

	return ds, nil
}

// NewDataStore creates a new instance of LibKV data store
func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
	if cfg == nil || cfg.Client.Provider == "" || cfg.Client.Address == "" {
		c, ok := defaultScopes[scope]
		if !ok || c.Client.Provider == "" || c.Client.Address == "" {
			return nil, fmt.Errorf("unexpected scope %s without configuration passed", scope)
		}

		cfg = c
	}

	var cached bool
	if scope == LocalScope {
		cached = true
	}

	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
}

func (ds *datastore) Close() {
	ds.store.Close()
}

func (ds *datastore) Scope() string {
	return ds.scope
}

func (ds *datastore) Watchable() bool {
	return ds.scope != LocalScope
}

func (ds *datastore) Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error) {
	sCh := make(chan struct{})

	ctor, ok := kvObject.(KVConstructor)
	if !ok {
		return nil, fmt.Errorf("error watching object type %T, object does not implement KVConstructor interface", kvObject)
	}

	kvpCh, err := ds.store.Watch(Key(kvObject.Key()...), sCh)
	if err != nil {
		return nil, err
	}

	kvoCh := make(chan KVObject)

	go func() {
		for {
			select {
			case <-stopCh:
				close(sCh)
				return
			case kvPair := <-kvpCh:
				// If the backend KV store gets reset libkv's go routine
				// for the watch can exit resulting in a nil value in
				// channel.
				if kvPair == nil {
					close(sCh)
					return
				}
				dstO := ctor.New()

				if err := dstO.SetValue(kvPair.Value); err != nil {
					log.Printf("Could not unmarshal kvpair value = %s", string(kvPair.Value))
					break
				}

				dstO.SetIndex(kvPair.LastIndex)
				kvoCh <- dstO
			}
		}
	}()

	return kvoCh, nil
}

func (ds *datastore) KVStore() store.Store {
	return ds.store
}

// PutObjectAtomic adds a new Record based on an object into the datastore
func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
	var (
		previous *store.KVPair
		pair     *store.KVPair
		err      error
	)
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	kvObjValue := kvObject.Value()

	if kvObjValue == nil {
		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
	}

	if kvObject.Skip() {
		goto add_cache
	}

	if kvObject.Exists() {
		previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
	} else {
		previous = nil
	}

	_, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
	if err != nil {
		return err
	}

	kvObject.SetIndex(pair.LastIndex)

add_cache:
	if ds.cache != nil {
		return ds.cache.add(kvObject)
	}

	return nil
}

// PutObject adds a new Record based on an object into the datastore
func (ds *datastore) PutObject(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	if kvObject.Skip() {
		goto add_cache
	}

	if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil {
		return err
	}

add_cache:
	if ds.cache != nil {
		return ds.cache.add(kvObject)
	}

	return nil
}

func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
	kvObjValue := kvObject.Value()

	if kvObjValue == nil {
		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
	}
	return ds.store.Put(Key(key...), kvObjValue, nil)
}

// GetObject returns a record matching the key
func (ds *datastore) GetObject(key string, o KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if ds.cache != nil {
		return ds.cache.get(key, o)
	}

	kvPair, err := ds.store.Get(key)
	if err != nil {
		return err
	}

	if err := o.SetValue(kvPair.Value); err != nil {
		return err
	}

	// Make sure the object has a correct view of the DB index in
	// case we need to modify it and update the DB.
	o.SetIndex(kvPair.LastIndex)
	return nil
}

func (ds *datastore) ensureParent(parent string) error {
	exists, err := ds.store.Exists(parent)
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	return ds.store.Put(parent, []byte{}, &store.WriteOptions{IsDir: true})
}

func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
	ds.Lock()
	defer ds.Unlock()

	if ds.cache != nil {
		return ds.cache.list(kvObject)
	}

	// Bail out right away if the kvObject does not implement KVConstructor
	ctor, ok := kvObject.(KVConstructor)
	if !ok {
		return nil, fmt.Errorf("error listing objects, object does not implement KVConstructor interface")
	}

	// Make sure the parent key exists
	if err := ds.ensureParent(key); err != nil {
		return nil, err
	}

	kvList, err := ds.store.List(key)
	if err != nil {
		return nil, err
	}

	var kvol []KVObject
	for _, kvPair := range kvList {
		if len(kvPair.Value) == 0 {
			continue
		}

		dstO := ctor.New()
		if err := dstO.SetValue(kvPair.Value); err != nil {
			return nil, err
		}

		// Make sure the object has a correct view of the DB index in
		// case we need to modify it and update the DB.
		dstO.SetIndex(kvPair.LastIndex)

		kvol = append(kvol, dstO)
	}

	return kvol, nil
}

// DeleteObject unconditionally deletes a record from the store
func (ds *datastore) DeleteObject(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	// cleaup the cache first
	if ds.cache != nil {
		ds.cache.del(kvObject)
	}

	if kvObject.Skip() {
		return nil
	}

	return ds.store.Delete(Key(kvObject.Key()...))
}

// DeleteObjectAtomic performs atomic delete on a record
func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	if kvObject == nil {
		return types.BadRequestErrorf("invalid KV Object : nil")
	}

	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}

	if kvObject.Skip() {
		goto del_cache
	}

	if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil {
		return err
	}

del_cache:
	// cleanup the cache only if AtomicDelete went through successfully
	if ds.cache != nil {
		return ds.cache.del(kvObject)
	}

	return nil
}

// DeleteTree unconditionally deletes a record from the store
func (ds *datastore) DeleteTree(kvObject KVObject) error {
	ds.Lock()
	defer ds.Unlock()

	// cleaup the cache first
	if ds.cache != nil {
		ds.cache.del(kvObject)
	}

	if kvObject.Skip() {
		return nil
	}

	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
}
<|endoftext|>


<commit_before>package box

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
)

// TODO(ttacon): reconcile this with Folder for one common struct?
type File struct {
	ID                string          `json:"id,omitempty"`
	FolderUploadEmail *AccessEmail    `json:"folder_upload_email,omitempty"`
	Parent            *Item           `json:"parent,omitempty"`
	ItemStatus        string          `json:"item_status"`
	ItemCollection    *ItemCollection `json:"item_collection"`
	Type              string          `json:"type"` // TODO(ttacon): enum
	Description       string          `json:"description"`
	Size              int             `json:"size"`
	CreateBy          *Item           `json:"created_by"`
	ModifiedBy        *Item           `json:"modified_by"`
	TrashedAt         *string         `json:"trashed_at"`          // TODO(ttacon): change to time.Time
	ContentModifiedAt *string         `json:"content_modified_at"` // TODO(ttacon): change to time.Time
	PurgedAt          *string         `json:"purged_at"`           // TODO(ttacon): change to time.Time, this field isn't documented but I keep getting it back...
	SharedLinkg       *string         `json:"shared_link"`
	SequenceId        string          `json:"sequence_id"`
	ETag              *string         `json:"etag"`
	Name              string          `json:"name"`
	CreatedAt         *string         `json:"created_at"` // TODO(ttacon): change to time.Time
	OwnedBy           *Item           `json:"owned_by"`
	ModifiedAt        *string         `json:"modified_at"`        // TODO(ttacon): change to time.Time
	ContentCreatedAt  *string         `json:"content_created_at"` // TODO(ttacon): change to time.Time
	PathCollection    *PathCollection `json:"path_collection"`    // TODO(ttacon): make sure this is the correct kind of struct(ure)
	SharedLink        *Link           `json:"shared_link"`

	SHA1 string `json:"sha1"`
}

type FileCollection struct {
	TotalCount int     `json:"total_count"`
	Entries    []*File `json:"entries"`
}

// Documentation: https://developer.box.com/docs/#files-get
func (c *Client) GetFile(fileId string) (*http.Response, *File, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s", fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// Documentation https://developer.box.com/docs/#files-upload-a-file
// TODO(ttacon): deal with handling SHA1 headers
func (c *Client) UploadFile(filePath, parentId string) (*http.Response, *FileCollection, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	fileContents, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, nil, err
	}

	fi, err := file.Stat()
	if err != nil {
		return nil, nil, err
	}

	var (
		body   = &bytes.Buffer{}
		writer = multipart.NewWriter(body)
	)

	// write the file
	part, err := writer.CreateFormFile("file", fi.Name())
	if err != nil {
		return nil, nil, err
	}
	part.Write(fileContents)

	// write the other form fields we need
	err = writer.WriteField("filename", fi.Name())
	if err != nil {
		return nil, nil, err
	}

	err = writer.WriteField("parent_id", parentId)
	if err != nil {
		return nil, nil, err
	}

	// TODO(ttacon): add in content_created_at, content_modified_at

	err = writer.Close()
	if err != nil {
		return nil, nil, err
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf("https://upload.box.com/api/2.0/files/content"),
		body,
	)
	req.Header.Add("Content-Type", writer.FormDataContentType())
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data FileCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-delete-a-file
func (c *Client) DeleteFile(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"DELETE",
		fmt.Sprintf("/files/%s", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// Documentation: https://developers.box.com/docs/#files-copy-a-file
func (c *Client) CopyFile(fileId, parent, name string) (*http.Response, *File, error) {
	var bodyData = map[string]interface{}{
		"parent": map[string]string{
			"id": parent,
		},
		"name": name,
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf("/files/%s/copy", fileId),
		dataMap,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// NOTE: we return the http.Response as Box may return a 202 if there is not
// yet a download link, or a 302 with the link - this allows the user to
// decide what to do.
// Documentation: https://developers.box.com/docs/#files-download-a-file
func (c *Client) DownloadFile(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/content", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// Documentation: https://developers.box.com/docs/#files-view-versions-of-a-file
// TODO(ttacon): don't use file collection, make actual structs specific to file versions
func (c *Client) ViewVersionsOfFile(fileId string) (*http.Response, *FileCollection, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/versions", fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *FileCollection
	resp, err := c.Do(req, data)
	return resp, data, err
}

// NOTE: we only return the response as there are many possible responses that we
// feel the user should have control over
// Documentation: https://developers.box.com/docs/#files-get-a-thumbnail-for-a-file
func (c *Client) GetThumbnail(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/thumbnail.extension", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req)
}

// Documentation: https://developers.box.com/docs/#files-create-a-shared-link-for-a-file
func (c *Client) CreateSharedLinkForFile(fileId, access, unsharedAt string, canDownload, canPreview bool) (*http.Response, *File, error) {
	var dataMap = make(map[string]interface{})
	if len(access) > 0 {
		dataMap["access"] = access
	}
	// TODO(ttacon): support unshared_at as time.Time
	// TODO(ttacon): validate access is open or company before add permissions
	if canDownload {
		dataMap["permissions"] = map[string]bool{
			"can_download": canDownload,
		}
	}
	if canPreview {
		if m, ok := dataMap["permissions"]; ok {
			mVal, _ := m.(map[string]bool)
			mVal["can_preview"] = canPreview
		} else {
			dataMap["permissions"] = map[string]bool{
				"can_preview": canPreview,
			}
		}
	}

	req, err := c.NewRequest(
		"PUT",
		fmt.Sprintf("/files/%s", fileId),
		dataMap,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// Documentation: https://developers.box.com/docs/#files-get-a-trashed-file
func (c *Client) GetTrashedFile(fileId string) (*http.Response, *File, error) {
	req, err := http.NewRequest(
		"GET",
		fmt.Sprintf("%s/files/%s/trash", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data File
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-restore-a-trashed-item
func (c *Client) RestoreTrashedItem(name, parentId string) (*http.Response, *File, error) {
	var dataMap = make(map[string]interface{})
	if len(name) > 0 {
		dataMap["name"] = name
	}
	if len(parentId) > 0 {
		dataMap["parent"] = map[string]string{
			"id": parentId,
		}
	}
	dataBytes, err := json.Marshal(&dataMap)
	if err != nil {
		return nil, nil, err
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf(),
		bytes.NewReader(dataBytes),
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data File
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-permanently-delete-a-trashed-file
func (c *Client) PermanentlyDeleteTrashedFile(fileId string) (*http.Response, error) {
	req, err := http.NewRequest(
		"DELETE",
		fmt.Sprintf("%s/files/%s/trash", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Trans.Client().Do(req)
}

// Documentation: https://developers.box.com/docs/#files-view-the-comments-on-a-file
func (c *Client) ViewCommentsOnFile(fileId string) (*http.Response, *CommentCollection, error) {
	req, err := http.NewRequest(
		"GET",
		fmt.Sprintf("%s/files/%s/comments", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data CommentCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-get-the-tasks-for-a-file
func (c *Client) GetTasksForFile(fileId string) (*http.Response, *TaskCollection, error) {
	req, err := http.NewRequest(
		"GET",
		fmt.Sprintf("%s/files/%s/tasks", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data TaskCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}
<commit_msg>refactor get trashed file<commit_after>package box

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
)

// TODO(ttacon): reconcile this with Folder for one common struct?
type File struct {
	ID                string          `json:"id,omitempty"`
	FolderUploadEmail *AccessEmail    `json:"folder_upload_email,omitempty"`
	Parent            *Item           `json:"parent,omitempty"`
	ItemStatus        string          `json:"item_status"`
	ItemCollection    *ItemCollection `json:"item_collection"`
	Type              string          `json:"type"` // TODO(ttacon): enum
	Description       string          `json:"description"`
	Size              int             `json:"size"`
	CreateBy          *Item           `json:"created_by"`
	ModifiedBy        *Item           `json:"modified_by"`
	TrashedAt         *string         `json:"trashed_at"`          // TODO(ttacon): change to time.Time
	ContentModifiedAt *string         `json:"content_modified_at"` // TODO(ttacon): change to time.Time
	PurgedAt          *string         `json:"purged_at"`           // TODO(ttacon): change to time.Time, this field isn't documented but I keep getting it back...
	SharedLinkg       *string         `json:"shared_link"`
	SequenceId        string          `json:"sequence_id"`
	ETag              *string         `json:"etag"`
	Name              string          `json:"name"`
	CreatedAt         *string         `json:"created_at"` // TODO(ttacon): change to time.Time
	OwnedBy           *Item           `json:"owned_by"`
	ModifiedAt        *string         `json:"modified_at"`        // TODO(ttacon): change to time.Time
	ContentCreatedAt  *string         `json:"content_created_at"` // TODO(ttacon): change to time.Time
	PathCollection    *PathCollection `json:"path_collection"`    // TODO(ttacon): make sure this is the correct kind of struct(ure)
	SharedLink        *Link           `json:"shared_link"`

	SHA1 string `json:"sha1"`
}

type FileCollection struct {
	TotalCount int     `json:"total_count"`
	Entries    []*File `json:"entries"`
}

// Documentation: https://developer.box.com/docs/#files-get
func (c *Client) GetFile(fileId string) (*http.Response, *File, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s", fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// Documentation https://developer.box.com/docs/#files-upload-a-file
// TODO(ttacon): deal with handling SHA1 headers
func (c *Client) UploadFile(filePath, parentId string) (*http.Response, *FileCollection, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	fileContents, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, nil, err
	}

	fi, err := file.Stat()
	if err != nil {
		return nil, nil, err
	}

	var (
		body   = &bytes.Buffer{}
		writer = multipart.NewWriter(body)
	)

	// write the file
	part, err := writer.CreateFormFile("file", fi.Name())
	if err != nil {
		return nil, nil, err
	}
	part.Write(fileContents)

	// write the other form fields we need
	err = writer.WriteField("filename", fi.Name())
	if err != nil {
		return nil, nil, err
	}

	err = writer.WriteField("parent_id", parentId)
	if err != nil {
		return nil, nil, err
	}

	// TODO(ttacon): add in content_created_at, content_modified_at

	err = writer.Close()
	if err != nil {
		return nil, nil, err
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf("https://upload.box.com/api/2.0/files/content"),
		body,
	)
	req.Header.Add("Content-Type", writer.FormDataContentType())
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data FileCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-delete-a-file
func (c *Client) DeleteFile(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"DELETE",
		fmt.Sprintf("/files/%s", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// Documentation: https://developers.box.com/docs/#files-copy-a-file
func (c *Client) CopyFile(fileId, parent, name string) (*http.Response, *File, error) {
	var bodyData = map[string]interface{}{
		"parent": map[string]string{
			"id": parent,
		},
		"name": name,
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf("/files/%s/copy", fileId),
		dataMap,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// NOTE: we return the http.Response as Box may return a 202 if there is not
// yet a download link, or a 302 with the link - this allows the user to
// decide what to do.
// Documentation: https://developers.box.com/docs/#files-download-a-file
func (c *Client) DownloadFile(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/content", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// Documentation: https://developers.box.com/docs/#files-view-versions-of-a-file
// TODO(ttacon): don't use file collection, make actual structs specific to file versions
func (c *Client) ViewVersionsOfFile(fileId string) (*http.Response, *FileCollection, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/versions", fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *FileCollection
	resp, err := c.Do(req, data)
	return resp, data, err
}

// NOTE: we only return the response as there are many possible responses that we
// feel the user should have control over
// Documentation: https://developers.box.com/docs/#files-get-a-thumbnail-for-a-file
func (c *Client) GetThumbnail(fileId string) (*http.Response, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/thumbnail.extension", fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Do(req)
}

// Documentation: https://developers.box.com/docs/#files-create-a-shared-link-for-a-file
func (c *Client) CreateSharedLinkForFile(fileId, access, unsharedAt string, canDownload, canPreview bool) (*http.Response, *File, error) {
	var dataMap = make(map[string]interface{})
	if len(access) > 0 {
		dataMap["access"] = access
	}
	// TODO(ttacon): support unshared_at as time.Time
	// TODO(ttacon): validate access is open or company before add permissions
	if canDownload {
		dataMap["permissions"] = map[string]bool{
			"can_download": canDownload,
		}
	}
	if canPreview {
		if m, ok := dataMap["permissions"]; ok {
			mVal, _ := m.(map[string]bool)
			mVal["can_preview"] = canPreview
		} else {
			dataMap["permissions"] = map[string]bool{
				"can_preview": canPreview,
			}
		}
	}

	req, err := c.NewRequest(
		"PUT",
		fmt.Sprintf("/files/%s", fileId),
		dataMap,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// Documentation: https://developers.box.com/docs/#files-get-a-trashed-file
func (c *Client) GetTrashedFile(fileId string) (*http.Response, *File, error) {
	req, err := c.NewRequest(
		"GET",
		fmt.Sprintf("/files/%s/trash", fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	var data *File
	resp, err := c.Do(req, data)
	return resp, data, err
}

// Documentation: https://developers.box.com/docs/#files-restore-a-trashed-item
func (c *Client) RestoreTrashedItem(name, parentId string) (*http.Response, *File, error) {
	var dataMap = make(map[string]interface{})
	if len(name) > 0 {
		dataMap["name"] = name
	}
	if len(parentId) > 0 {
		dataMap["parent"] = map[string]string{
			"id": parentId,
		}
	}
	dataBytes, err := json.Marshal(&dataMap)
	if err != nil {
		return nil, nil, err
	}

	req, err := http.NewRequest(
		"POST",
		fmt.Sprintf(),
		bytes.NewReader(dataBytes),
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data File
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-permanently-delete-a-trashed-file
func (c *Client) PermanentlyDeleteTrashedFile(fileId string) (*http.Response, error) {
	req, err := http.NewRequest(
		"DELETE",
		fmt.Sprintf("%s/files/%s/trash", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, err
	}

	return c.Trans.Client().Do(req)
}

// Documentation: https://developers.box.com/docs/#files-view-the-comments-on-a-file
func (c *Client) ViewCommentsOnFile(fileId string) (*http.Response, *CommentCollection, error) {
	req, err := http.NewRequest(
		"GET",
		fmt.Sprintf("%s/files/%s/comments", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data CommentCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}

// Documentation: https://developers.box.com/docs/#files-get-the-tasks-for-a-file
func (c *Client) GetTasksForFile(fileId string) (*http.Response, *TaskCollection, error) {
	req, err := http.NewRequest(
		"GET",
		fmt.Sprintf("%s/files/%s/tasks", BASE_URL, fileId),
		nil,
	)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.Trans.Client().Do(req)
	if err != nil {
		return resp, nil, err
	}

	var data TaskCollection
	err = json.NewDecoder(resp.Body).Decode(&data)
	return resp, &data, err
}
<|endoftext|>


<commit_before>package atm

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/labstack/echo"
)

const AUTH_SEP = ":"
const XTIME = "X-Timestamp"
const CONTENT_TYPE = "Content-Type"
const CONTENT_MD5 = "Content-MD5"
const XNONCE = "X-Nonce"
const API_KEY = "api-key"

type KeyFinder func(string) (string, error)

type HmacOpts struct {
	AuthPrefix   string
	Expiration   time.Duration
	SecretKeyFor KeyFinder
}

func NewHmacOpts(f KeyFinder) *HmacOpts {
	o := &HmacOpts{
		AuthPrefix:   "ATM_Auth",
		Expiration:   5 * time.Minute,
		SecretKeyFor: f,
	}
	return o
}

func HMACAuth(o *HmacOpts) echo.HandlerFunc {
	return func(c *echo.Context) error {
		auth, err := newAuth(c.Request(), o)
		if nil != err {
			return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
		}
		if err := auth.Authentic(c.Request()); nil != err {
			return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
		}
		c.Set(API_KEY, auth.ApiKey)
		return nil
	}
}

type Authorizor struct {
	ApiKey    string
	Signature string
	Md5       string
	Type      string
	Nonce     string
	Xtime     string
	Method    string
	Uri       string
	Timestamp time.Time
	Opts      *HmacOpts
}

type hmacError struct {
	msg string
}

func (e hmacError) Error() string {
	return e.msg
}

func AuthorizorForRequest(o *HmacOpts, method string, uri string) *Authorizor {
	return &Authorizor{
		Opts:   o,
		Method: strings.ToUpper(method),
		Uri:    uri,
	}
}

func newAuth(r *http.Request, o *HmacOpts) (*Authorizor, error) {
	h := r.Header
	if len(h.Get(echo.Authorization)) <= 0 {
		return nil, hmacError{"Missing required Authorization header"}
	}
	a := &Authorizor{
		Opts:   o,
		Method: strings.ToUpper(r.Method),
		Uri:    r.URL.RequestURI(),
	}
	err := a.authorizorFromAuthHeader(h.Get(echo.Authorization))
	if nil != err {
		return nil, err
	}
	err = a.extractRequiredHeaders(&h)
	if nil != err {
		return nil, err
	}
	return a, nil
}

func (a *Authorizor) Authentic(r *http.Request) error {
	if err := a.invalidTime(); nil != err {
		return err
	}
	//TODO Actually check the nonce
	body := readerToByte(r.Body)
	r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	contentHash := md5Of(body)
	if strings.ToLower(a.Md5) != strings.ToLower(contentHash) {
		return hmacError{fmt.Sprintf("Content MD5s do not match:%s", contentHash)}
	}
	secret, err := a.Opts.SecretKeyFor(a.ApiKey)
	if nil != err {
		return err
	}
	if "" == secret {
		return hmacError{fmt.Sprintf("No secret key for %s", a.ApiKey)}
	}
	generatedSig := a.signatureWith(secret)
	if "" == generatedSig {
		return hmacError{"Unable to generate hmac signature"}
	}
	if hmac.Equal([]byte(generatedSig), []byte(a.Signature)) {
		return nil
	}
	return hmacError{"HMAC Signature mismatch"}
}

func md5Of(b []byte) string {
	h := md5.New()
	h.Write(b)
	return hex.EncodeToString(h.Sum(nil))
}

func readerToByte(s io.Reader) []byte {
	b, _ := ioutil.ReadAll(s)
	return b
}

func (a *Authorizor) invalidTime() error {
	age := time.Since(a.Timestamp)
	if age < 0 {
		age *= -1
	}
	if age > a.Opts.Expiration {
		return hmacError{"Timestamp out of range"}
	}
	return nil
}

func (a *Authorizor) signatureWith(key string) string {
	c := a.SigningString()
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(c))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

//Build the content for signging & sign it with the key
//method\nURI\nMD5\ntype\ntimestamp\nnonce
func (a *Authorizor) SigningString() string {
	var b bytes.Buffer
	b.WriteString(a.Method)
	b.WriteString("\n")
	b.WriteString(a.Uri)
	b.WriteString("\n")
	b.WriteString(a.Md5)
	b.WriteString("\n")
	b.WriteString(a.Type)
	b.WriteString("\n")
	b.WriteString(a.Xtime)
	b.WriteString("\n")
	b.WriteString(a.Nonce)
	b.WriteString("\n")
	b.WriteString(a.ApiKey)

	return b.String()
}

// We need x-timestamp, content-md5, content-type, x-nonce
func (a *Authorizor) extractRequiredHeaders(h *http.Header) error {
	a.Md5 = h.Get(CONTENT_MD5)
	if "" == a.Md5 {
		return hmacError{fmt.Sprintf("Missing required %s header", CONTENT_MD5)}
	}
	a.Type = h.Get(CONTENT_TYPE)
	if "" == a.Type {
		return hmacError{fmt.Sprintf("Missing required %s header", CONTENT_TYPE)}
	}
	a.Nonce = h.Get(XNONCE)
	if "" == a.Nonce {
		return hmacError{fmt.Sprintf("Missing required %s header", XNONCE)}
	}
	return a.parseTimestamp(h.Get(XTIME))
}

func (a *Authorizor) parseTimestamp(t string) error {
	if "" == t {
		return hmacError{fmt.Sprintf("Missing required %s header", XTIME)}
	}
	a.Xtime = t
	ts, err := time.Parse(time.RFC3339, t)
	if nil != err {
		return hmacError{fmt.Sprintf("Invalid timestamp: %s", err.Error())}
	}
	a.Timestamp = ts
	return nil
}

func (a *Authorizor) authorizorFromAuthHeader(h string) error {
	l := len(a.Opts.AuthPrefix)
	if len(h)-l-1 <= 0 || h[:l] != a.Opts.AuthPrefix {
		return hmacError{fmt.Sprintf("Authorization header invalid format: Missing %s prefix", a.Opts.AuthPrefix)}
	}
	parts := strings.SplitN(strings.Trim(h[l+1:], " "), AUTH_SEP, 2)
	if len(parts) != 2 {
		return hmacError{"Authorization header invalid format: Missing ApiKey:Signature"}
	}
	a.ApiKey = parts[0]
	if "" == a.ApiKey {
		return hmacError{"Authorization header invalid format: Missing ApiKey"}
	}
	a.Signature = parts[1]
	if "" == a.Signature {
		return hmacError{"Authorization header invalid format: Missing Signature"}
	}
	return nil
}
<commit_msg>Expose the signing method for clients<commit_after>package atm

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/labstack/echo"
)

const AUTH_SEP = ":"
const XTIME = "X-Timestamp"
const CONTENT_TYPE = "Content-Type"
const CONTENT_MD5 = "Content-MD5"
const XNONCE = "X-Nonce"
const API_KEY = "api-key"

type KeyFinder func(string) (string, error)

type HmacOpts struct {
	AuthPrefix   string
	Expiration   time.Duration
	SecretKeyFor KeyFinder
}

func NewHmacOpts(f KeyFinder) *HmacOpts {
	o := &HmacOpts{
		AuthPrefix:   "ATM_Auth",
		Expiration:   5 * time.Minute,
		SecretKeyFor: f,
	}
	return o
}

func HMACAuth(o *HmacOpts) echo.HandlerFunc {
	return func(c *echo.Context) error {
		auth, err := newAuth(c.Request(), o)
		if nil != err {
			return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
		}
		if err := auth.Authentic(c.Request()); nil != err {
			return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
		}
		c.Set(API_KEY, auth.ApiKey)
		return nil
	}
}

type Authorizor struct {
	ApiKey    string
	Signature string
	Md5       string
	Type      string
	Nonce     string
	Xtime     string
	Method    string
	Uri       string
	Timestamp time.Time
	Opts      *HmacOpts
}

type hmacError struct {
	msg string
}

func (e hmacError) Error() string {
	return e.msg
}

func AuthorizorForRequest(o *HmacOpts, method string, uri string) *Authorizor {
	return &Authorizor{
		Opts:   o,
		Method: strings.ToUpper(method),
		Uri:    uri,
	}
}

func newAuth(r *http.Request, o *HmacOpts) (*Authorizor, error) {
	h := r.Header
	if len(h.Get(echo.Authorization)) <= 0 {
		return nil, hmacError{"Missing required Authorization header"}
	}
	a := &Authorizor{
		Opts:   o,
		Method: strings.ToUpper(r.Method),
		Uri:    r.URL.RequestURI(),
	}
	err := a.authorizorFromAuthHeader(h.Get(echo.Authorization))
	if nil != err {
		return nil, err
	}
	err = a.extractRequiredHeaders(&h)
	if nil != err {
		return nil, err
	}
	return a, nil
}

func (a *Authorizor) Authentic(r *http.Request) error {
	if err := a.invalidTime(); nil != err {
		return err
	}
	//TODO Actually check the nonce
	body := readerToByte(r.Body)
	r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	contentHash := md5Of(body)
	if strings.ToLower(a.Md5) != strings.ToLower(contentHash) {
		return hmacError{fmt.Sprintf("Content MD5s do not match:%s", contentHash)}
	}
	secret, err := a.Opts.SecretKeyFor(a.ApiKey)
	if nil != err {
		return err
	}
	if "" == secret {
		return hmacError{fmt.Sprintf("No secret key for %s", a.ApiKey)}
	}
	generatedSig := a.SignatureWith(secret)
	if "" == generatedSig {
		return hmacError{"Unable to generate hmac signature"}
	}
	if hmac.Equal([]byte(generatedSig), []byte(a.Signature)) {
		return nil
	}
	return hmacError{"HMAC Signature mismatch"}
}

func md5Of(b []byte) string {
	h := md5.New()
	h.Write(b)
	return hex.EncodeToString(h.Sum(nil))
}

func readerToByte(s io.Reader) []byte {
	b, _ := ioutil.ReadAll(s)
	return b
}

func (a *Authorizor) invalidTime() error {
	age := time.Since(a.Timestamp)
	if age < 0 {
		age *= -1
	}
	if age > a.Opts.Expiration {
		return hmacError{"Timestamp out of range"}
	}
	return nil
}

func (a *Authorizor) SignatureWith(key string) string {
	c := a.SigningString()
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(c))
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

//Build the content for signging & sign it with the key
//method\nURI\nMD5\ntype\ntimestamp\nnonce
func (a *Authorizor) SigningString() string {
	var b bytes.Buffer
	b.WriteString(a.Method)
	b.WriteString("\n")
	b.WriteString(a.Uri)
	b.WriteString("\n")
	b.WriteString(a.Md5)
	b.WriteString("\n")
	b.WriteString(a.Type)
	b.WriteString("\n")
	b.WriteString(a.Xtime)
	b.WriteString("\n")
	b.WriteString(a.Nonce)
	b.WriteString("\n")
	b.WriteString(a.ApiKey)

	return b.String()
}

// We need x-timestamp, content-md5, content-type, x-nonce
func (a *Authorizor) extractRequiredHeaders(h *http.Header) error {
	a.Md5 = h.Get(CONTENT_MD5)
	if "" == a.Md5 {
		return hmacError{fmt.Sprintf("Missing required %s header", CONTENT_MD5)}
	}
	a.Type = h.Get(CONTENT_TYPE)
	if "" == a.Type {
		return hmacError{fmt.Sprintf("Missing required %s header", CONTENT_TYPE)}
	}
	a.Nonce = h.Get(XNONCE)
	if "" == a.Nonce {
		return hmacError{fmt.Sprintf("Missing required %s header", XNONCE)}
	}
	return a.parseTimestamp(h.Get(XTIME))
}

func (a *Authorizor) parseTimestamp(t string) error {
	if "" == t {
		return hmacError{fmt.Sprintf("Missing required %s header", XTIME)}
	}
	a.Xtime = t
	ts, err := time.Parse(time.RFC3339, t)
	if nil != err {
		return hmacError{fmt.Sprintf("Invalid timestamp: %s", err.Error())}
	}
	a.Timestamp = ts
	return nil
}

func (a *Authorizor) authorizorFromAuthHeader(h string) error {
	l := len(a.Opts.AuthPrefix)
	if len(h)-l-1 <= 0 || h[:l] != a.Opts.AuthPrefix {
		return hmacError{fmt.Sprintf("Authorization header invalid format: Missing %s prefix", a.Opts.AuthPrefix)}
	}
	parts := strings.SplitN(strings.Trim(h[l+1:], " "), AUTH_SEP, 2)
	if len(parts) != 2 {
		return hmacError{"Authorization header invalid format: Missing ApiKey:Signature"}
	}
	a.ApiKey = parts[0]
	if "" == a.ApiKey {
		return hmacError{"Authorization header invalid format: Missing ApiKey"}
	}
	a.Signature = parts[1]
	if "" == a.Signature {
		return hmacError{"Authorization header invalid format: Missing Signature"}
	}
	return nil
}
<|endoftext|>