<commit_before>package database

import (
	"encoding/json"
	"reflect"

	"github.com/go-steem/rpc/apis/types"

	"github.com/pkg/errors"
)

const (
	OpTypeConvert             = "convert"
	OpTypeFeedPublish         = "feed_publish"
	OpTypePow                 = "pow"
	OpTypeAccountCreate       = "account_create"
	OpTypeAccountUpdate       = "account_update"
	OpTypeTransfer            = "transfer"
	OpTypeTransferToVesting   = "transfer_to_vesting"
	OpTypeWithdrawVesting     = "withdraw_vesting"
	OpTypeAccountWitnessVote  = "account_witness_vote"
	OpTypeAccountWitnessProxy = "account_witness_proxy"
	OpTypeComment             = "comment"
	OpTypeVote                = "vote"
	OpTypeLimitOrderCreate    = "limit_order_create"
	OpTypeFillOrder           = "fill_order"
	OpTypeLimitOrderCancel    = "limit_order_cancel"
	OpTypeDeleteComment       = "delete_comment"
	OpTypeCommentOptions      = "comment_options"
)

var opBodyObjects = map[string]interface{}{
	OpTypeConvert:             &ConvertOperation{},
	OpTypeFeedPublish:         &FeedPublishOperation{},
	OpTypePow:                 &PowOperation{},
	OpTypeAccountCreate:       &AccountCreateOperation{},
	OpTypeAccountUpdate:       &AccountUpdateOperation{},
	OpTypeTransfer:            &TransferOperation{},
	OpTypeTransferToVesting:   &TransferToVestingOperation{},
	OpTypeWithdrawVesting:     &WithdrawVestingOperation{},
	OpTypeAccountWitnessVote:  &AccountWitnessVoteOperation{},
	OpTypeAccountWitnessProxy: &AccountWitnessProxyOperation{},
	OpTypeComment:             &CommentOperation{},
	OpTypeVote:                &VoteOperation{},
	OpTypeLimitOrderCreate:    &LimitOrderCreateOperation{},
	OpTypeFillOrder:           &FillOrderOperation{},
	OpTypeLimitOrderCancel:    &LimitOrderCancelOperation{},
	OpTypeDeleteComment:       &DeleteCommentOperation{},
	OpTypeCommentOptions:      &CommentOptionsOperation{},
}

// FC_REFLECT( steemit::chain::report_over_production_operation,
//             (reporter)
//             (first_block)
//             (second_block) )

type ReportOverProductionOperation struct {
	Reporter string `json:"reporter"`
}

// FC_REFLECT( steemit::chain::convert_operation,
//             (owner)
//             (requestid)
//             (amount) )

type ConvertOperation struct {
	Owner     string `json:"owner"`
	RequestID uint32 `json:"requestid"`
	Amount    string `json:"amount"`
}

// FC_REFLECT( steemit::chain::feed_publish_operation,
//             (publisher)
//             (exchange_rate) )

type FeedPublishOperation struct {
	Publisher    string `json:"publisher"`
	ExchangeRate struct {
		Base  string `json:"base"`
		Quote string `json:"quote"`
	} `json:"exchange_rate"`
}

// FC_REFLECT( steemit::chain::pow,
//             (worker)
//             (input)
//             (signature)
//             (work) )

type Pow struct {
	Worker    string `json:"worker"`
	Input     string `json:"input"`
	Signature string `json:"signature"`
	Work      string `json:"work"`
}

// FC_REFLECT( steemit::chain::chain_properties,
//             (account_creation_fee)
//             (maximum_block_size)
//             (sbd_interest_rate) );

type ChainProperties struct {
	AccountCreationFee string `json:"account_creation_fee"`
	MaximumBlockSize   uint32 `json:"maximum_block_size"`
	SBDInterestRate    uint16 `json:"sbd_interest_rate"`
}

// FC_REFLECT( steemit::chain::pow_operation,
//             (worker_account)
//             (block_id)
//             (nonce)
//             (work)
//             (props) )

type PowOperation struct {
	WorkerAccount string           `json:"worker_account"`
	BlockID       string           `json:"block_id"`
	Nonce         string           `json:"nonce"`
	Work          *Pow             `json:"work"`
	Props         *ChainProperties `json:"props"`
}

// FC_REFLECT( steemit::chain::account_create_operation,
//             (fee)
//             (creator)
//             (new_account_name)
//             (owner)
//             (active)
//             (posting)
//             (memo_key)
//             (json_metadata) )

type AccountCreateOperation struct {
	Fee            string     `json:"fee"`
	Creator        string     `json:"creator"`
	NewAccountName string     `json:"new_account_name"`
	Owner          *Authority `json:"owner"`
	Active         *Authority `json:"active"`
	Posting        *Authority `json:"posting"`
	MemoKey        string     `json:"memo_key"`
	JsonMetadata   string     `json:"json_metadata"`
}

// FC_REFLECT( steemit::chain::account_update_operation,
//             (account)
//             (owner)
//             (active)
//             (posting)
//             (memo_key)
//             (json_metadata) )

type AccountUpdateOperation struct {
	Account      string     `json:"account"`
	Owner        *Authority `json:"owner"`
	Active       *Authority `json:"active"`
	Posting      *Authority `json:"posting"`
	MemoKey      string     `json:"memo_key"`
	JsonMetadata string     `json:"json_metadata"`
}

// FC_REFLECT( steemit::chain::transfer_operation,
//             (from)
//             (to)
//             (amount)
//             (memo) )

type TransferOperation struct {
	From   string `json:"from"`
	To     string `json:"to"`
	Amount string `json:"amount"`
	Memo   string `json:"memo"`
}

// FC_REFLECT( steemit::chain::transfer_to_vesting_operation,
//             (from)
//             (to)
//             (amount) )

type TransferToVestingOperation struct {
	From   string `json:"from"`
	To     string `json:"to"`
	Amount string `json:"amount"`
}

// FC_REFLECT( steemit::chain::withdraw_vesting_operation,
//             (account)
//             (vesting_shares) )

type WithdrawVestingOperation struct {
	Account       string `json:"account"`
	VestingShares string `json:"vesting_shares"`
}

// FC_REFLECT( steemit::chain::set_withdraw_vesting_route_operation,
//             (from_account)
//             (to_account)
//             (percent)
//             (auto_vest) )

// FC_REFLECT( steemit::chain::witness_update_operation,
//             (owner)
//             (url)
//             (block_signing_key)
//             (props)
//             (fee) )

// FC_REFLECT( steemit::chain::account_witness_vote_operation,
//             (account)
//             (witness)(approve) )

type AccountWitnessVoteOperation struct {
	Account string `json:"account"`
	Witness string `json:"witness"`
	Approve bool   `json:"approve"`
}

// FC_REFLECT( steemit::chain::account_witness_proxy_operation,
//             (account)
//             (proxy) )

type AccountWitnessProxyOperation struct {
	Account string `json:"account"`
	Proxy   string `json:"proxy"`
}

// FC_REFLECT( steemit::chain::comment_operation,
//             (parent_author)
//             (parent_permlink)
//             (author)
//             (permlink)
//             (title)
//             (body)
//             (json_metadata) )

// CommentOperation represents either a new post or a comment.
//
// In case Title is filled in and ParentAuthor is empty, it is a new post.
// The post category can be read from ParentPermlink.
type CommentOperation struct {
	Author         string `json:"author"`
	Title          string `json:"title"`
	Permlink       string `json:"permlink"`
	ParentAuthor   string `json:"parent_author"`
	ParentPermlink string `json:"parent_permlink"`
	Body           string `json:"body"`
}

func (op *CommentOperation) IsStoryOperation() bool {
	return op.ParentAuthor == ""
}

// FC_REFLECT( steemit::chain::vote_operation,
//             (voter)
//             (author)
//             (permlink)
//             (weight) )

type VoteOperation struct {
	Voter    string     `json:"voter"`
	Author   string     `json:"author"`
	Permlink string     `json:"permlink"`
	Weight   *types.Int `json:"weight"`
}

// FC_REFLECT( steemit::chain::custom_operation,
//             (required_auths)
//             (id)
//             (data) )

// FC_REFLECT( steemit::chain::custom_json_operation,
//             (required_auths)
//             (required_posting_auths)
//             (id)
//             (json) )

// FC_REFLECT( steemit::chain::limit_order_create_operation,
//             (owner)
//             (orderid)
//             (amount_to_sell)
//             (min_to_receive)
//             (fill_or_kill)
//             (expiration) )

type LimitOrderCreateOperation struct {
	Owner        string      `json:"owner"`
	OrderID      uint32      `json:"orderid"`
	AmountToSell string      `json:"amount_to_sell"`
	MinToReceive string      `json:"min_to_receive"`
	FillOrKill   bool        `json:"fill_or_kill"`
	Expiration   *types.Time `json:"expiration"`
}

// FC_REFLECT( steemit::chain::fill_order_operation,
//             (owner)
//             (orderid)
//             (pays)
//             (receives) );

type FillOrderOperation struct {
	Owner    string `json:"owner"`
	OrderID  string `json:"orderid"`
	Pays     string `json:"pays"`
	Receives string `json:"receives"`
}

// FC_REFLECT( steemit::chain::limit_order_cancel_operation,
//             (owner)
//             (orderid) )

type LimitOrderCancelOperation struct {
	Owner   string `json:"owner"`
	OrderID uint32 `json:"orderid"`
}

// FC_REFLECT( steemit::chain::delete_comment_operation,
//             (author)
//             (permlink) )

type DeleteCommentOperation struct {
	Author   string `json:"author"`
	Permlink string `json:"permlink"`
}

// FC_REFLECT( steemit::chain::comment_options_operation,
//             (author)
//             (permlink)
//             (max_accepted_payout)
//             (percent_steem_dollars)
//             (allow_votes)
//             (allow_curation_rewards)
//             (extensions) )

type CommentOptionsOperation struct {
	Author               string        `json:"author"`
	Permlink             string        `json:"permlink"`
	MaxAcceptedPayout    string        `json:"max_accepted_payout"`
	PercentSteemDollars  uint16        `json:"percent_steem_dollars"`
	AllowVotes           bool          `json:"allow_votes"`
	AllowCurationRewards bool          `json:"allow_curation_rewards"`
	Extensions           []interface{} `json:"extensions"`
}

// Operation represents an operation stored in a transaction.
type Operation struct {
	// Type contains the string representation of the operation.
	Type string
	// Body contains one of the operation objects depending on the type.
	Body interface{}
}

func (op *Operation) UnmarshalJSON(data []byte) error {
	// The operation object is [opType, opBody].
	raw := make([]json.RawMessage, 2)
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	if len(raw) != 2 {
		return errors.Errorf("invalid operation object: %v\n", string(data))
	}

	// Unmarshal opType.
	var opType string
	if err := json.Unmarshal(raw[0], &opType); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Operation.Type: %v", string(raw[0]))
	}

	// Unmarshal opBody.
	bodyTemplate, ok := opBodyObjects[opType]
	if !ok {
		bodyTemplate = map[string]interface{}{}
	}
	opBody := reflect.New(reflect.Indirect(reflect.ValueOf(bodyTemplate)).Type()).Interface()
	if err := json.Unmarshal(raw[1], opBody); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Operation.Body: %v", string(raw[1]))
	}

	// Update fields.
	op.Type = opType
	op.Body = opBody
	return nil
}

type Authority struct {
	AccountAuths    []*Auth `json:"account_auths"`
	KeyAuths        []*Auth `json:"key_auths"`
	WeightThreshold uint32  `json:"weight_threshold"`
}

// XXX: Not sure about the struct field names.
type Auth struct {
	Key   string
	Check uint32
}

func (auth *Auth) UnmarshalJSON(data []byte) error {
	// The auth object is [key, check].
	raw := make([]json.RawMessage, 2)
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	if len(raw) != 2 {
		return errors.Errorf("invalid auth object: %v", string(data))
	}

	// Unmarshal Key.
	var key string
	if err := json.Unmarshal(raw[0], &key); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Auth.Key: %v", string(raw[0]))
	}

	// Unmarshal Check.
	var check uint32
	if err := json.Unmarshal(raw[1], &check); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Auth.Check: %v", string(raw[1]))
	}

	// Update fields.
	auth.Key = key
	auth.Check = check
	return nil

}
<commit_msg>apis/database: Fix PowOperation unmarshalling<commit_after>package database

import (
	"encoding/json"
	"reflect"

	"github.com/go-steem/rpc/apis/types"

	"github.com/pkg/errors"
)

const (
	OpTypeConvert             = "convert"
	OpTypeFeedPublish         = "feed_publish"
	OpTypePow                 = "pow"
	OpTypeAccountCreate       = "account_create"
	OpTypeAccountUpdate       = "account_update"
	OpTypeTransfer            = "transfer"
	OpTypeTransferToVesting   = "transfer_to_vesting"
	OpTypeWithdrawVesting     = "withdraw_vesting"
	OpTypeAccountWitnessVote  = "account_witness_vote"
	OpTypeAccountWitnessProxy = "account_witness_proxy"
	OpTypeComment             = "comment"
	OpTypeVote                = "vote"
	OpTypeLimitOrderCreate    = "limit_order_create"
	OpTypeFillOrder           = "fill_order"
	OpTypeLimitOrderCancel    = "limit_order_cancel"
	OpTypeDeleteComment       = "delete_comment"
	OpTypeCommentOptions      = "comment_options"
)

var opBodyObjects = map[string]interface{}{
	OpTypeConvert:             &ConvertOperation{},
	OpTypeFeedPublish:         &FeedPublishOperation{},
	OpTypePow:                 &PowOperation{},
	OpTypeAccountCreate:       &AccountCreateOperation{},
	OpTypeAccountUpdate:       &AccountUpdateOperation{},
	OpTypeTransfer:            &TransferOperation{},
	OpTypeTransferToVesting:   &TransferToVestingOperation{},
	OpTypeWithdrawVesting:     &WithdrawVestingOperation{},
	OpTypeAccountWitnessVote:  &AccountWitnessVoteOperation{},
	OpTypeAccountWitnessProxy: &AccountWitnessProxyOperation{},
	OpTypeComment:             &CommentOperation{},
	OpTypeVote:                &VoteOperation{},
	OpTypeLimitOrderCreate:    &LimitOrderCreateOperation{},
	OpTypeFillOrder:           &FillOrderOperation{},
	OpTypeLimitOrderCancel:    &LimitOrderCancelOperation{},
	OpTypeDeleteComment:       &DeleteCommentOperation{},
	OpTypeCommentOptions:      &CommentOptionsOperation{},
}

// FC_REFLECT( steemit::chain::report_over_production_operation,
//             (reporter)
//             (first_block)
//             (second_block) )

type ReportOverProductionOperation struct {
	Reporter string `json:"reporter"`
}

// FC_REFLECT( steemit::chain::convert_operation,
//             (owner)
//             (requestid)
//             (amount) )

type ConvertOperation struct {
	Owner     string `json:"owner"`
	RequestID uint32 `json:"requestid"`
	Amount    string `json:"amount"`
}

// FC_REFLECT( steemit::chain::feed_publish_operation,
//             (publisher)
//             (exchange_rate) )

type FeedPublishOperation struct {
	Publisher    string `json:"publisher"`
	ExchangeRate struct {
		Base  string `json:"base"`
		Quote string `json:"quote"`
	} `json:"exchange_rate"`
}

// FC_REFLECT( steemit::chain::pow,
//             (worker)
//             (input)
//             (signature)
//             (work) )

type Pow struct {
	Worker    string `json:"worker"`
	Input     string `json:"input"`
	Signature string `json:"signature"`
	Work      string `json:"work"`
}

// FC_REFLECT( steemit::chain::chain_properties,
//             (account_creation_fee)
//             (maximum_block_size)
//             (sbd_interest_rate) );

type ChainProperties struct {
	AccountCreationFee string `json:"account_creation_fee"`
	MaximumBlockSize   uint32 `json:"maximum_block_size"`
	SBDInterestRate    uint16 `json:"sbd_interest_rate"`
}

// FC_REFLECT( steemit::chain::pow_operation,
//             (worker_account)
//             (block_id)
//             (nonce)
//             (work)
//             (props) )

type PowOperation struct {
	WorkerAccount string           `json:"worker_account"`
	BlockID       string           `json:"block_id"`
	Nonce         uint64           `json:"nonce"`
	Work          *Pow             `json:"work"`
	Props         *ChainProperties `json:"props"`
}

// FC_REFLECT( steemit::chain::account_create_operation,
//             (fee)
//             (creator)
//             (new_account_name)
//             (owner)
//             (active)
//             (posting)
//             (memo_key)
//             (json_metadata) )

type AccountCreateOperation struct {
	Fee            string     `json:"fee"`
	Creator        string     `json:"creator"`
	NewAccountName string     `json:"new_account_name"`
	Owner          *Authority `json:"owner"`
	Active         *Authority `json:"active"`
	Posting        *Authority `json:"posting"`
	MemoKey        string     `json:"memo_key"`
	JsonMetadata   string     `json:"json_metadata"`
}

// FC_REFLECT( steemit::chain::account_update_operation,
//             (account)
//             (owner)
//             (active)
//             (posting)
//             (memo_key)
//             (json_metadata) )

type AccountUpdateOperation struct {
	Account      string     `json:"account"`
	Owner        *Authority `json:"owner"`
	Active       *Authority `json:"active"`
	Posting      *Authority `json:"posting"`
	MemoKey      string     `json:"memo_key"`
	JsonMetadata string     `json:"json_metadata"`
}

// FC_REFLECT( steemit::chain::transfer_operation,
//             (from)
//             (to)
//             (amount)
//             (memo) )

type TransferOperation struct {
	From   string `json:"from"`
	To     string `json:"to"`
	Amount string `json:"amount"`
	Memo   string `json:"memo"`
}

// FC_REFLECT( steemit::chain::transfer_to_vesting_operation,
//             (from)
//             (to)
//             (amount) )

type TransferToVestingOperation struct {
	From   string `json:"from"`
	To     string `json:"to"`
	Amount string `json:"amount"`
}

// FC_REFLECT( steemit::chain::withdraw_vesting_operation,
//             (account)
//             (vesting_shares) )

type WithdrawVestingOperation struct {
	Account       string `json:"account"`
	VestingShares string `json:"vesting_shares"`
}

// FC_REFLECT( steemit::chain::set_withdraw_vesting_route_operation,
//             (from_account)
//             (to_account)
//             (percent)
//             (auto_vest) )

// FC_REFLECT( steemit::chain::witness_update_operation,
//             (owner)
//             (url)
//             (block_signing_key)
//             (props)
//             (fee) )

// FC_REFLECT( steemit::chain::account_witness_vote_operation,
//             (account)
//             (witness)(approve) )

type AccountWitnessVoteOperation struct {
	Account string `json:"account"`
	Witness string `json:"witness"`
	Approve bool   `json:"approve"`
}

// FC_REFLECT( steemit::chain::account_witness_proxy_operation,
//             (account)
//             (proxy) )

type AccountWitnessProxyOperation struct {
	Account string `json:"account"`
	Proxy   string `json:"proxy"`
}

// FC_REFLECT( steemit::chain::comment_operation,
//             (parent_author)
//             (parent_permlink)
//             (author)
//             (permlink)
//             (title)
//             (body)
//             (json_metadata) )

// CommentOperation represents either a new post or a comment.
//
// In case Title is filled in and ParentAuthor is empty, it is a new post.
// The post category can be read from ParentPermlink.
type CommentOperation struct {
	Author         string `json:"author"`
	Title          string `json:"title"`
	Permlink       string `json:"permlink"`
	ParentAuthor   string `json:"parent_author"`
	ParentPermlink string `json:"parent_permlink"`
	Body           string `json:"body"`
}

func (op *CommentOperation) IsStoryOperation() bool {
	return op.ParentAuthor == ""
}

// FC_REFLECT( steemit::chain::vote_operation,
//             (voter)
//             (author)
//             (permlink)
//             (weight) )

type VoteOperation struct {
	Voter    string     `json:"voter"`
	Author   string     `json:"author"`
	Permlink string     `json:"permlink"`
	Weight   *types.Int `json:"weight"`
}

// FC_REFLECT( steemit::chain::custom_operation,
//             (required_auths)
//             (id)
//             (data) )

// FC_REFLECT( steemit::chain::custom_json_operation,
//             (required_auths)
//             (required_posting_auths)
//             (id)
//             (json) )

// FC_REFLECT( steemit::chain::limit_order_create_operation,
//             (owner)
//             (orderid)
//             (amount_to_sell)
//             (min_to_receive)
//             (fill_or_kill)
//             (expiration) )

type LimitOrderCreateOperation struct {
	Owner        string      `json:"owner"`
	OrderID      uint32      `json:"orderid"`
	AmountToSell string      `json:"amount_to_sell"`
	MinToReceive string      `json:"min_to_receive"`
	FillOrKill   bool        `json:"fill_or_kill"`
	Expiration   *types.Time `json:"expiration"`
}

// FC_REFLECT( steemit::chain::fill_order_operation,
//             (owner)
//             (orderid)
//             (pays)
//             (receives) );

type FillOrderOperation struct {
	Owner    string `json:"owner"`
	OrderID  string `json:"orderid"`
	Pays     string `json:"pays"`
	Receives string `json:"receives"`
}

// FC_REFLECT( steemit::chain::limit_order_cancel_operation,
//             (owner)
//             (orderid) )

type LimitOrderCancelOperation struct {
	Owner   string `json:"owner"`
	OrderID uint32 `json:"orderid"`
}

// FC_REFLECT( steemit::chain::delete_comment_operation,
//             (author)
//             (permlink) )

type DeleteCommentOperation struct {
	Author   string `json:"author"`
	Permlink string `json:"permlink"`
}

// FC_REFLECT( steemit::chain::comment_options_operation,
//             (author)
//             (permlink)
//             (max_accepted_payout)
//             (percent_steem_dollars)
//             (allow_votes)
//             (allow_curation_rewards)
//             (extensions) )

type CommentOptionsOperation struct {
	Author               string        `json:"author"`
	Permlink             string        `json:"permlink"`
	MaxAcceptedPayout    string        `json:"max_accepted_payout"`
	PercentSteemDollars  uint16        `json:"percent_steem_dollars"`
	AllowVotes           bool          `json:"allow_votes"`
	AllowCurationRewards bool          `json:"allow_curation_rewards"`
	Extensions           []interface{} `json:"extensions"`
}

// Operation represents an operation stored in a transaction.
type Operation struct {
	// Type contains the string representation of the operation.
	Type string
	// Body contains one of the operation objects depending on the type.
	Body interface{}
}

func (op *Operation) UnmarshalJSON(data []byte) error {
	// The operation object is [opType, opBody].
	raw := make([]json.RawMessage, 2)
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	if len(raw) != 2 {
		return errors.Errorf("invalid operation object: %v\n", string(data))
	}

	// Unmarshal opType.
	var opType string
	if err := json.Unmarshal(raw[0], &opType); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Operation.Type: %v", string(raw[0]))
	}

	// Unmarshal opBody.
	bodyTemplate, ok := opBodyObjects[opType]
	if !ok {
		bodyTemplate = map[string]interface{}{}
	}
	opBody := reflect.New(reflect.Indirect(reflect.ValueOf(bodyTemplate)).Type()).Interface()
	if err := json.Unmarshal(raw[1], opBody); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Operation.Body: %v", string(raw[1]))
	}

	// Update fields.
	op.Type = opType
	op.Body = opBody
	return nil
}

type Authority struct {
	AccountAuths    []*Auth `json:"account_auths"`
	KeyAuths        []*Auth `json:"key_auths"`
	WeightThreshold uint32  `json:"weight_threshold"`
}

// XXX: Not sure about the struct field names.
type Auth struct {
	Key   string
	Check uint32
}

func (auth *Auth) UnmarshalJSON(data []byte) error {
	// The auth object is [key, check].
	raw := make([]json.RawMessage, 2)
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	if len(raw) != 2 {
		return errors.Errorf("invalid auth object: %v", string(data))
	}

	// Unmarshal Key.
	var key string
	if err := json.Unmarshal(raw[0], &key); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Auth.Key: %v", string(raw[0]))
	}

	// Unmarshal Check.
	var check uint32
	if err := json.Unmarshal(raw[1], &check); err != nil {
		return errors.Wrapf(err, "failed to unmarshal Auth.Check: %v", string(raw[1]))
	}

	// Update fields.
	auth.Key = key
	auth.Check = check
	return nil

}
<|endoftext|>


<commit_before><commit_msg>chore: get rid of spurious debug print<commit_after><|endoftext|>


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

package pals

import (
	"fmt"
	"github.com/kortschak/biogo/feat"
	"github.com/kortschak/biogo/interval"
)

var duplicatePair = fmt.Errorf("pals: attempt to add duplicate feature pair to pile")

type Piler struct {
	intervals interval.Tree
	seen      map[string]struct{}
	overlap   int
}

func NewPiler(overlap int) *Piler {
	return &Piler{
		intervals: interval.NewTree(),
		seen:      make(map[string]struct{}),
		overlap:   overlap,
	}
}

func (self *Piler) Add(p *FeaturePair) (err error) {
	a := fmt.Sprintf("%q:[%d,%d)", p.A.Location, p.A.Start, p.A.End)
	b := fmt.Sprintf("%q:[%d,%d)", p.B.Location, p.B.Start, p.B.End)

	if _, ok := self.seen[a+b]; ok {
		return duplicatePair
	}
	if _, ok := self.seen[b+a]; ok {
		return duplicatePair
	}

	ai, err := interval.New(string(p.A.Location), p.A.Start, p.A.End, 0, []*FeaturePair{p})
	if err != nil {
		return
	}
	bi, err := interval.New(string(p.B.Location), p.B.Start, p.B.End, 0, []*FeaturePair(nil))
	if err != nil {
		return
	}

	self.merge(ai)
	self.merge(bi)
	self.seen[a+b] = struct{}{}
	self.seen[b+a] = struct{}{}

	return
}

// merge an interval into the tree adding meta data from the replaced intervals into the new interval
func (self *Piler) merge(i *interval.Interval) {
	rc := self.intervals.Merge(i, self.overlap)
	m := i.Meta.([]*FeaturePair)
	for _, ri := range rc {
		m = append(m, ri.Meta.([]*FeaturePair)...)
	}
	i.Meta = m
}

type Pile struct {
	Pile   *feat.Feature
	Images []*FeaturePair
}

// A PileFilter is used to determine whether a FeaturePair is included in a Pile
type PileFilter func(a, b *feat.Feature, pa, pb *interval.Interval) bool

// We use the Features' Meta field to point back to the containing Pile, so Meta cannot be used for other things here.
func (self *Piler) Piles(f PileFilter) (piles []*Pile, err error) {
	pm := make(map[*interval.Interval]*Pile)

	for pa := range self.intervals.TraverseAll() {
		var bi, pb *interval.Interval
		for _, p := range pa.Meta.([]*FeaturePair) {
			bi, err = interval.New(p.B.Location, p.B.Start, p.B.End, 0, nil)
			if err != nil {
				return
			}
			pb, err = self.Pile(bi)
			if err != nil {
				return
			}

			if f != nil && !f(p.A, p.B, pa, pb) {
				continue
			}
			if wp, ok := pm[pa]; !ok {
				tp := &Pile{
					Pile:   &feat.Feature{Location: pa.Segment(), Start: pa.Start(), End: pa.End()},
					Images: []*FeaturePair{p},
				}
				p.A.Meta = tp
				pm[pa] = tp
			} else {
				p.A.Meta = wp
				wp.Images = append(wp.Images, p)
			}
			if wp, ok := pm[pb]; !ok {
				tp := &Pile{
					Pile:   &feat.Feature{Location: pb.Segment(), Start: pb.Start(), End: pb.End()},
					Images: []*FeaturePair{p.Invert()},
				}
				p.B.Meta = tp
				pm[pb] = tp
			} else {
				p.B.Meta = wp
				wp.Images = append(wp.Images, p.Invert())
			}
		}
	}

	piles = make([]*Pile, 0, len(pm))
	for _, p := range pm {
		piles = append(piles, p)
	}

	return
}

func (self *Piler) Pile(i *interval.Interval) (p *interval.Interval, err error) {
	c := 0
	for p = range self.intervals.Intersect(i, 0) {
		// first sanity check: no interval described in the features should extend beyond the interval
		if i.Start() < p.Start() || i.End() > p.End() {
			return nil, fmt.Errorf("pals: internal inconsistency - escaped bounds: %s is outside %s", i, p)
		}
		c++
	}
	// second sanity check: no interval should overlap any other interval
	if c > 1 {
		return nil, fmt.Errorf("pals: internal inconsistency - too many results:", c)
	}

	return
}
<commit_msg>Documentation<commit_after>// Copyright ©2012 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package pals

import (
	"fmt"
	"github.com/kortschak/biogo/feat"
	"github.com/kortschak/biogo/interval"
)

var duplicatePair = fmt.Errorf("pals: attempt to add duplicate feature pair to pile")

// A Piler performs the aggregation of feature pairs according to the description in section 2.3
// of Edgar and Myers (2005) using an interval tree, giving O(nlogn) time but better space complexity
// and flexibility with feature overlap.
type Piler struct {
	intervals interval.Tree
	seen      map[string]struct{}
	overlap   int
}

// NewPiler creates a Piler object ready for piling feature pairs.
func NewPiler(overlap int) *Piler {
	return &Piler{
		intervals: interval.NewTree(),
		seen:      make(map[string]struct{}),
		overlap:   overlap,
	}
}

// Add adds a feature pair to the piler incorporating the features into piles where appropriate.
func (self *Piler) Add(p *FeaturePair) (err error) {
	a := fmt.Sprintf("%q:[%d,%d)", p.A.Location, p.A.Start, p.A.End)
	b := fmt.Sprintf("%q:[%d,%d)", p.B.Location, p.B.Start, p.B.End)

	if _, ok := self.seen[a+b]; ok {
		return duplicatePair
	}
	if _, ok := self.seen[b+a]; ok {
		return duplicatePair
	}

	ai, err := interval.New(string(p.A.Location), p.A.Start, p.A.End, 0, []*FeaturePair{p})
	if err != nil {
		return
	}
	bi, err := interval.New(string(p.B.Location), p.B.Start, p.B.End, 0, []*FeaturePair(nil))
	if err != nil {
		return
	}

	self.merge(ai)
	self.merge(bi)
	self.seen[a+b] = struct{}{}
	self.seen[b+a] = struct{}{}

	return
}

// merge an interval into the tree adding meta data from the replaced intervals into the new interval
func (self *Piler) merge(i *interval.Interval) {
	rc := self.intervals.Merge(i, self.overlap)
	m := i.Meta.([]*FeaturePair)
	for _, ri := range rc {
		m = append(m, ri.Meta.([]*FeaturePair)...)
	}
	i.Meta = m
}

// A Pile is a collection of features covering a maximal (potentially contiguous, depending on
// the value of overlap used for creation of the Piler) region of copy count > 0.
type Pile struct {
	Pile   *feat.Feature
	Images []*FeaturePair
}

// A PileFilter is used to determine whether a FeaturePair is included in a Pile
type PileFilter func(a, b *feat.Feature, pa, pb *interval.Interval) bool

// We use the Features' Meta field to point back to the containing Pile, so Meta cannot be used for other things here.
func (self *Piler) Piles(f PileFilter) (piles []*Pile, err error) {
	pm := make(map[*interval.Interval]*Pile)

	for pa := range self.intervals.TraverseAll() {
		var bi, pb *interval.Interval
		for _, p := range pa.Meta.([]*FeaturePair) {
			bi, err = interval.New(p.B.Location, p.B.Start, p.B.End, 0, nil)
			if err != nil {
				return
			}
			pb, err = self.Pile(bi)
			if err != nil {
				return
			}

			if f != nil && !f(p.A, p.B, pa, pb) {
				continue
			}
			if wp, ok := pm[pa]; !ok {
				tp := &Pile{
					Pile:   &feat.Feature{Location: pa.Segment(), Start: pa.Start(), End: pa.End()},
					Images: []*FeaturePair{p},
				}
				p.A.Meta = tp
				pm[pa] = tp
			} else {
				p.A.Meta = wp
				wp.Images = append(wp.Images, p)
			}
			if wp, ok := pm[pb]; !ok {
				tp := &Pile{
					Pile:   &feat.Feature{Location: pb.Segment(), Start: pb.Start(), End: pb.End()},
					Images: []*FeaturePair{p.Invert()},
				}
				p.B.Meta = tp
				pm[pb] = tp
			} else {
				p.B.Meta = wp
				wp.Images = append(wp.Images, p.Invert())
			}
		}
	}

	piles = make([]*Pile, 0, len(pm))
	for _, p := range pm {
		piles = append(piles, p)
	}

	return
}

// Pile returns the interval representation of the pile containing i.
// An error is returned if more than one pile would be returned.
func (self *Piler) Pile(i *interval.Interval) (p *interval.Interval, err error) {
	c := 0
	for p = range self.intervals.Contain(i, self.overlap) {
		c++
	}
	// Sanity check: no pile should overlap any other pile within overlap constraints
	if c > 1 {
		return nil, fmt.Errorf("pals: internal inconsistency - too many results:", c)
	}

	return
}
<|endoftext|>


<commit_before>package storage

import (
	"gopkg.in/mgo.v2"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db/storage"
)

const (
	DefaultDatabaseHost = "127.0.0.1:27017"
	DefaultDatabaseName = "backstage"
)

type Storage struct {
	*storage.Storage
}

func conn() (*storage.Storage, error) {
	databaseHost, err := config.GetString("database:host")
	if err != nil {
		databaseHost = DefaultDatabaseHost
	}

	databaseName, err := config.GetString("database:name")
	if err != nil {
		databaseName = DefaultDatabaseName
	}

	return storage.Open(databaseHost, databaseName)
}

func Conn() (*Storage, error) {
	var (
		strg Storage
		err  error
	)

	strg.Storage, err = conn()
	return &strg, err
}

func (storage *Storage) Services() *storage.Collection {
	subdomainIndex := mgo.Index{Key: []string{"subdomain"}, Unique: true}
	collection := storage.Collection("services")
	collection.EnsureIndex(subdomainIndex)
	return collection
}
<commit_msg>Change the way we use default values to connect to MongoDB.<commit_after>package storage

import (
	"gopkg.in/mgo.v2"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db/storage"
)

const (
	DefaultDatabaseHost = "127.0.0.1:27017"
	DefaultDatabaseName = "backstage"
)

type Storage struct {
	*storage.Storage
}

func conn() (*storage.Storage, error) {
	databaseHost, _ := config.GetString("database:host")
	if databaseHost == "" {
		databaseHost = DefaultDatabaseHost
	}

	databaseName, _ := config.GetString("database:name")
	if databaseName == "" {
		databaseName = DefaultDatabaseName
	}

	return storage.Open(databaseHost, databaseName)
}

func Conn() (*Storage, error) {
	var (
		strg Storage
		err  error
	)

	strg.Storage, err = conn()
	return &strg, err
}

func (storage *Storage) Services() *storage.Collection {
	subdomainIndex := mgo.Index{Key: []string{"subdomain"}, Unique: true}
	collection := storage.Collection("services")
	collection.EnsureIndex(subdomainIndex)
	return collection
}
<|endoftext|>


<commit_before>package aphgrpc

import (
	"fmt"
	"math"
	"strings"
)

const (
	DefaultPagenum  = 1
	DefaultPagesize = 10
)

// JSONAPIParamsInfo interface should be implement by all grpc-gateway services
// that supports JSON API specifications.
type JSONAPIParamsInfo interface {
	// Relationships that could be included
	AllowedInclude() []string
	// Attribute fields that are allowed
	AllowedFields() []string
	// Filter fields that are allowed
	AllowedFilter() []string
	// FilterToColumns provides mapping between filter and storage columns
	FilterToColumns() map[string]string
	// RequiredAttrs are the mandatory attributes for creating a new resource
	RequiredAttrs() []string
}

// JSONAPIResource interface provides information about HTTP resource. All
// grpc-gateway services that supports JSONAPI should implement this interface.
type JSONAPIResource interface {
	//GetResourceName returns canonical resource name
	GetResourceName() string
	// GetBaseURL returns the base url with the scheme
	GetBaseURL() string
	// GetPrefix returns the path that could be appended to base url
	GetPathPrefix() string
}

// GetTotalPageNum calculate total no of pages from total no. records and page size
func GetTotalPageNum(record, pagesize int64) int64 {
	total := int64(math.Floor(float64(record) / float64(pagesize)))
	if math.Mod(float64(record), float64(pagesize)) > 0 {
		total += 1
	}
	return total
}

// GetPaginatedLinks gets paginated links and total page number for collection resources
func GetPaginatedLinks(rs JSONAPIResource, lastpage, pagenum, pagesize int64) map[string]string {
	var links map[string]string
	links["self"] = GenPaginatedResourceLink(rs, pagenum, pagesize)
	links["first"] = GenPaginatedResourceLink(rs, 1, pagesize)
	if pagenum != 1 {
		links["previous"] = GenPaginatedResourceLink(rs, pagenum-1, pagesize)
	}
	links["last"] = GenPaginatedResourceLink(rs, lastpage, pagesize)
	if pagenum != lastpage {
		links["next"] = GenPaginatedResourceLink(rs, pagenum+1, pagesize)
	}
	return links
}

func GenBaseLink(rs JSONAPIResource) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(sinfo.GetBaseURL(), "/"),
		strings.Trim(sinfo.GetPrefix(), "/"),
	)
}

func GenSingleResourceLink(rs JSONAPIResource, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
	)
}

func GenMultiResourceLink(rs JSONAPIResource) string {
	return fmt.Sprintf(
		"%s/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
	)
}

func GenPaginatedResourceLink(rs JSONAPIResource, pagenum, pagesize int64) string {
	return fmt.Sprintf(
		"%s/%s?pagenum=%d&pagesize=%d",
		GenBaseLink(rs),
		rs.GetResourceName(),
		pagenum,
		pagesize,
	)
}

func GenSelfRelationshipLink(rs JSONAPIResource, rel string, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d/relationships/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
		rel,
	)
}

func GenRelatedRelationshipLink(rs JSONAPIResource, rel string, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
		rel,
	)
}
<commit_msg>Added method to check for initialized fields and return their specified tag values<commit_after>package aphgrpc

import (
	"fmt"
	"math"
	"strings"

	"github.com/fatih/structs"
)

const (
	DefaultPagenum  = 1
	DefaultPagesize = 10
)

// JSONAPIParamsInfo interface should be implement by all grpc-gateway services
// that supports JSON API specifications.
type JSONAPIParamsInfo interface {
	// Relationships that could be included
	AllowedInclude() []string
	// Attribute fields that are allowed
	AllowedFields() []string
	// Filter fields that are allowed
	AllowedFilter() []string
	// FilterToColumns provides mapping between filter and storage columns
	FilterToColumns() map[string]string
	// RequiredAttrs are the mandatory attributes for creating a new resource
	RequiredAttrs() []string
}

// JSONAPIResource interface provides information about HTTP resource. All
// grpc-gateway services that supports JSONAPI should implement this interface.
type JSONAPIResource interface {
	//GetResourceName returns canonical resource name
	GetResourceName() string
	// GetBaseURL returns the base url with the scheme
	GetBaseURL() string
	// GetPrefix returns the path that could be appended to base url
	GetPathPrefix() string
}

// GetTotalPageNum calculate total no of pages from total no. records and page size
func GetTotalPageNum(record, pagesize int64) int64 {
	total := int64(math.Floor(float64(record) / float64(pagesize)))
	if math.Mod(float64(record), float64(pagesize)) > 0 {
		total += 1
	}
	return total
}

// GetPaginatedLinks gets paginated links and total page number for collection resources
func GetPaginatedLinks(rs JSONAPIResource, lastpage, pagenum, pagesize int64) map[string]string {
	var links map[string]string
	links["self"] = GenPaginatedResourceLink(rs, pagenum, pagesize)
	links["first"] = GenPaginatedResourceLink(rs, 1, pagesize)
	if pagenum != 1 {
		links["previous"] = GenPaginatedResourceLink(rs, pagenum-1, pagesize)
	}
	links["last"] = GenPaginatedResourceLink(rs, lastpage, pagesize)
	if pagenum != lastpage {
		links["next"] = GenPaginatedResourceLink(rs, pagenum+1, pagesize)
	}
	return links
}

func GenBaseLink(rs JSONAPIResource) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(sinfo.GetBaseURL(), "/"),
		strings.Trim(sinfo.GetPrefix(), "/"),
	)
}

func GenSingleResourceLink(rs JSONAPIResource, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
	)
}

func GenMultiResourceLink(rs JSONAPIResource) string {
	return fmt.Sprintf(
		"%s/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
	)
}

func GenPaginatedResourceLink(rs JSONAPIResource, pagenum, pagesize int64) string {
	return fmt.Sprintf(
		"%s/%s?pagenum=%d&pagesize=%d",
		GenBaseLink(rs),
		rs.GetResourceName(),
		pagenum,
		pagesize,
	)
}

func GenSelfRelationshipLink(rs JSONAPIResource, rel string, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d/relationships/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
		rel,
	)
}

func GenRelatedRelationshipLink(rs JSONAPIResource, rel string, id int64) string {
	return fmt.Sprintf(
		"%s/%s/%d/%s",
		GenBaseLink(rs),
		rs.GetResourceName(),
		id,
		rel,
	)
}

//GetDefinedTags check for fields that are initialized and returns a slice of
//their matching tag values
func GetDefinedTags(i interface{}, tag string) []string {
	var v []string
	s := structs.New(i)
	for _, f := range s.Fields() {
		if !f.IsZero() {
			v = append(v, f.Tag(tag))
		}
	}
	return v
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"

	"github.com/apex/log"
	"github.com/juju/errors"
)

var (
	// APIUrl represents Online's endpoint
	APIUrl = "https://api.online.net/api/v1"
)

// OnlineAPI is used to communicate with Online API
type OnlineAPI struct {
	client    *http.Client
	userAgent string
	verbose   bool
}

// NewC14API returns a new API
func NewC14API(client *http.Client, userAgent string, verbose bool) (api *OnlineAPI) {
	api = &OnlineAPI{
		client:    client,
		userAgent: userAgent,
		verbose:   verbose,
	}
	return
}

func (o *OnlineAPI) response(method, uri string, content io.Reader) (resp *http.Response, err error) {
	var (
		req *http.Request
	)

	req, err = http.NewRequest(method, uri, content)
	if err != nil {
		err = errors.Annotatef(err, "response %s %s", method, uri)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", o.userAgent)

	// curl, err := http2curl.GetCurlCommand(req)
	// if err != nil {
	// 	return nil, err
	// }
	if o.verbose {
		dump, _ := httputil.DumpRequest(req, false)
		log.Debugf("%v", string(dump))
	} else {
		log.Debugf("[%s]: %v", method, uri)
	}
	resp, err = o.client.Do(req)
	return
}

func (o *OnlineAPI) getWrapper(uri string, export interface{}) (err error) {
	var (
		resp *http.Response
		body []byte
	)

	resp, err = o.response("GET", uri, nil)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		err = errors.Annotatef(err, "Unable to get %s", uri)
		return
	}

	if body, err = o.handleHTTPError([]int{200}, resp); err != nil {
		return
	}
	err = json.Unmarshal(body, export)
	return
}

func (o *OnlineAPI) postWrapper(uri string, content interface{}) (body []byte, err error) {
	var (
		resp    *http.Response
		payload = new(bytes.Buffer)
	)

	encoder := json.NewEncoder(payload)
	if err = encoder.Encode(content); err != nil {
		return
	}
	resp, err = o.response("POST", uri, payload)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		err = errors.Annotatef(err, "Unable to post %s", uri)
		return
	}
	body, err = o.handleHTTPError([]int{201}, resp)
	return
}

func (o *OnlineAPI) handleHTTPError(goodStatusCode []int, resp *http.Response) (content []byte, err error) {
	content, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	if o.verbose {
		dump, _ := httputil.DumpResponse(resp, false)
		log.Debugf("%v", string(dump))
	} else {
		log.Debugf("[Response]: [%v] %v", resp.StatusCode, string(content))
	}

	if resp.StatusCode >= 500 {
		err = errors.Errorf("[%v] %v", resp.StatusCode, string(content))
		return
	}
	good := false
	for _, code := range goodStatusCode {
		if code == resp.StatusCode {
			good = true
		}
	}
	if !good {
		var why OnlineError

		if err = json.Unmarshal(content, &why); err != nil {
			return
		}
		why.StatusCode = resp.StatusCode
		err = why
	}
	return
}
<commit_msg>verbose ... more verbose<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"

	"github.com/apex/log"
	"github.com/juju/errors"
)

var (
	// APIUrl represents Online's endpoint
	APIUrl = "https://api.online.net/api/v1"
)

// OnlineAPI is used to communicate with Online API
type OnlineAPI struct {
	client    *http.Client
	userAgent string
	verbose   bool
}

// NewC14API returns a new API
func NewC14API(client *http.Client, userAgent string, verbose bool) (api *OnlineAPI) {
	api = &OnlineAPI{
		client:    client,
		userAgent: userAgent,
		verbose:   verbose,
	}
	return
}

func (o *OnlineAPI) response(method, uri string, content io.Reader) (resp *http.Response, err error) {
	var (
		req *http.Request
	)

	req, err = http.NewRequest(method, uri, content)
	if err != nil {
		err = errors.Annotatef(err, "response %s %s", method, uri)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", o.userAgent)

	// curl, err := http2curl.GetCurlCommand(req)
	// if err != nil {
	// 	return nil, err
	// }
	if o.verbose {
		dump, _ := httputil.DumpRequest(req, true)
		log.Debugf("%v", string(dump))
	} else {
		log.Debugf("[%s]: %v", method, uri)
	}
	resp, err = o.client.Do(req)
	return
}

func (o *OnlineAPI) getWrapper(uri string, export interface{}) (err error) {
	var (
		resp *http.Response
		body []byte
	)

	resp, err = o.response("GET", uri, nil)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		err = errors.Annotatef(err, "Unable to get %s", uri)
		return
	}

	if body, err = o.handleHTTPError([]int{200}, resp); err != nil {
		return
	}
	err = json.Unmarshal(body, export)
	return
}

func (o *OnlineAPI) postWrapper(uri string, content interface{}) (body []byte, err error) {
	var (
		resp    *http.Response
		payload = new(bytes.Buffer)
	)

	encoder := json.NewEncoder(payload)
	if err = encoder.Encode(content); err != nil {
		return
	}
	resp, err = o.response("POST", uri, payload)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		err = errors.Annotatef(err, "Unable to post %s", uri)
		return
	}
	body, err = o.handleHTTPError([]int{201}, resp)
	return
}

func (o *OnlineAPI) handleHTTPError(goodStatusCode []int, resp *http.Response) (content []byte, err error) {
	content, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	if o.verbose {
		dump, _ := httputil.DumpResponse(resp, true)
		log.Debugf("%v", string(dump))
	} else {
		log.Debugf("[Response]: [%v] %v", resp.StatusCode, string(content))
	}

	if resp.StatusCode >= 500 {
		err = errors.Errorf("[%v] %v", resp.StatusCode, string(content))
		return
	}
	good := false
	for _, code := range goodStatusCode {
		if code == resp.StatusCode {
			good = true
		}
	}
	if !good {
		var why OnlineError

		if err = json.Unmarshal(content, &why); err != nil {
			return
		}
		why.StatusCode = resp.StatusCode
		err = why
	}
	return
}
<|endoftext|>


<commit_before>package cli

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"

	"github.com/mitchellh/go-homedir"
	"github.com/supergiant/supergiant/pkg/client"
	"github.com/supergiant/supergiant/pkg/model"
	"github.com/urfave/cli"
)

var globalConfFile string

func init() {
	home, err := homedir.Dir()
	if err != nil {
		panic(err)
	}
	globalConfFile = home + "/.supergiant"
}

var baseFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "server, s",
		Usage: "Host and port of the Supergiant server",
	},
	cli.StringFlag{
		Name:  "api-token, t",
		Usage: "API token of the operating Supergiant User",
	},
	cli.StringFlag{
		Name:  "cert-file, c",
		Usage: "Filepath of the SSL certificate used by the server. If not provided, the cert must be manually trusted through OS.",
	},
}

type CLI struct {
	*cli.App
	Client  func(*cli.Context) *client.Client
	Stdin   *os.File
	Version string
}

func New(clientFn func(*cli.Context) *client.Client, stdin *os.File, version string) *CLI {
	sgcli := &CLI{cli.NewApp(), clientFn, stdin, version}

	sgcli.Name = "supergiant"
	sgcli.Usage = "Supergiant CLI " + version
	// TODO for whatever reason the version always reports 0.0.0
	sgcli.Version = version

	sgcli.Commands = []cli.Command{
		{
			Name:   "configure",
			Usage:  "globally configure server settings (helpful to prevent repeating flags)",
			Flags:  baseFlags,
			Action: sgcli.commandConfigure,
		},
		{
			Name:  "kubectl",
			Usage: "wrapper for Kubectl that auto-populates connection-related tags",
			Flags: append(baseFlags, []cli.Flag{
				cli.Int64Flag{
					Name:  "kube-id, k",
					Usage: "ID of the Supergiant Kube",
				},
			}...),
			Action: sgcli.commandKubectl,
		},
		{
			Name:  "cloud_accounts",
			Usage: "actions for CloudAccounts",
			Subcommands: []cli.Command{
				sgcli.commandList("CloudAccounts", new(model.CloudAccountList)),
				sgcli.commandCreate("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandGet("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandUpdate("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandAction("delete", "Delete", "CloudAccounts", new(model.CloudAccount)),
			},
		},
		{
			Name:  "entrypoints",
			Usage: "actions for Entrypoints",
			Subcommands: []cli.Command{
				sgcli.commandList("Entrypoints", new(model.EntrypointList)),
				sgcli.commandCreate("Entrypoints", new(model.Entrypoint)),
				sgcli.commandGet("Entrypoints", new(model.Entrypoint)),
				sgcli.commandUpdate("Entrypoints", new(model.Entrypoint)),
				sgcli.commandAction("delete", "Delete", "Entrypoints", new(model.Entrypoint)),
			},
		},
		{
			Name:  "entrypoint_listeners",
			Usage: "actions for EntrypointListeners",
			Subcommands: []cli.Command{
				sgcli.commandList("EntrypointListeners", new(model.EntrypointListenerList)),
				sgcli.commandCreate("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandGet("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandUpdate("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandAction("delete", "Delete", "EntrypointListeners", new(model.EntrypointListener)),
			},
		},
		{
			Name:  "kubes",
			Usage: "actions for Kubes",
			Subcommands: []cli.Command{
				sgcli.commandList("Kubes", new(model.KubeList)),
				sgcli.commandCreate("Kubes", new(model.Kube)),
				sgcli.commandGet("Kubes", new(model.Kube)),
				sgcli.commandUpdate("Kubes", new(model.Kube)),
				sgcli.commandAction("delete", "Delete", "Kubes", new(model.Kube)),
			},
		},
		{
			Name:  "nodes",
			Usage: "actions for Nodes",
			Subcommands: []cli.Command{
				sgcli.commandList("Nodes", new(model.NodeList)),
				sgcli.commandCreate("Nodes", new(model.Node)),
				sgcli.commandGet("Nodes", new(model.Node)),
				sgcli.commandUpdate("Nodes", new(model.Node)),
				sgcli.commandAction("delete", "Delete", "Nodes", new(model.Node)),
			},
		},
		{
			Name:  "sessions",
			Usage: "actions for Sessions",
			Subcommands: []cli.Command{
				sgcli.commandList("Sessions", new(model.SessionList)),
				sgcli.commandCreate("Sessions", new(model.Session)),
				sgcli.commandGet("Sessions", new(model.Session)),
				sgcli.commandAction("delete", "Delete", "Sessions", new(model.Session)),
			},
		},
		{
			Name:  "users",
			Usage: "actions for Users",
			Subcommands: []cli.Command{
				sgcli.commandList("Users", new(model.UserList)),
				sgcli.commandCreate("Users", new(model.User)),
				sgcli.commandGet("Users", new(model.User)),
				sgcli.commandUpdate("Users", new(model.User)),
				sgcli.commandAction("delete", "Delete", "Users", new(model.User)),
			},
		},
		{
			Name:  "volumes",
			Usage: "actions for Volumes",
			Subcommands: []cli.Command{
				sgcli.commandList("Volumes", new(model.VolumeList)),
				sgcli.commandCreate("Volumes", new(model.Volume)),
				sgcli.commandGet("Volumes", new(model.Volume)),
				sgcli.commandUpdate("Volumes", new(model.Volume)),
				sgcli.commandAction("delete", "Delete", "Volumes", new(model.Volume)),
				sgcli.commandAction("resize", "Resize", "Volumes", new(model.Volume)),
			},
		},
		{
			Name:  "kube_resources",
			Usage: "actions for Kube Resources",
			Subcommands: []cli.Command{
				sgcli.commandList("KubeResources", new(model.KubeResourceList)),
				sgcli.commandCreate("KubeResources", new(model.KubeResource)),
				sgcli.commandGet("KubeResources", new(model.KubeResource)),
				sgcli.commandUpdate("KubeResources", new(model.KubeResource)),
				sgcli.commandAction("delete", "Delete", "KubeResources", new(model.KubeResource)),
				sgcli.commandAction("start", "Start", "KubeResources", new(model.KubeResource)),
				sgcli.commandAction("stop", "Stop", "KubeResources", new(model.KubeResource)),
			},
		},
	}

	return sgcli
}

// Private

func (sgcli *CLI) commandList(collectionName string, list model.List) cli.Command {
	return cli.Command{
		Name:  "list",
		Usage: "list " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringSliceFlag{
				Name:  "filter",
				Usage: "--filter=name:this,or,that --filter=other_field:value",
			},
			cli.StringFlag{
				Name:  "format",
				Usage: "--format=\"{{ .ThisField }}\"",
			},
		}...),
		Action: func(c *cli.Context) error {
			filters, err := listFilters(c)
			if err != nil {
				return err
			}

			reflectList := reflect.ValueOf(list)

			// Set filters
			reflectList.Elem().FieldByName("Filters").Set(reflect.ValueOf(filters))

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("List")
			ret := fn.Call([]reflect.Value{reflectList})

			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}
			return printList(c, list)
		},
	}
}

func (sgcli *CLI) commandCreate(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "create",
		Usage: "create new " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "file, f",
				Usage: "JSON input file",
			},
		}...),
		Action: func(c *cli.Context) error {
			if err := sgcli.decodeInputFileInto(c, item); err != nil {
				return err
			}

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Create")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandGet(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "get",
		Usage: "get " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Get")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandUpdate(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "update",
		Usage: "update " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
			cli.StringFlag{
				Name:  "file, f",
				Usage: "JSON input file",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")
			if err := sgcli.decodeInputFileInto(c, item); err != nil {
				return err
			}

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Update")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandAction(action string, methodName string, collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  action,
		Usage: action + " " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName(methodName)
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

// Root commands

func (sgcli *CLI) commandConfigure(c *cli.Context) error {
	conf := newGlobalConf(c)
	b, err := json.Marshal(conf)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(globalConfFile, b, 0600); err != nil {
		return err
	}
	fmt.Println("Written to " + globalConfFile)
	return nil
}

func (sgcli *CLI) commandKubectl(c *cli.Context) error {
	id := c.Int64("kube-id")
	kube := new(model.Kube)
	if err := sgcli.Client(c).Kubes.Get(&id, kube); err != nil {
		return err
	}

	args := []string{
		"--api-version=v1",
		"--insecure-skip-tls-verify=true",
		"--server=https://" + kube.MasterPublicIP,
		"--cluster=" + kube.Name,
		"--username=" + kube.Username,
		"--password=" + kube.Password,
	}
	// Prepend the user's kubectl args, which will look like `get pods --namespace=kube-system`
	args = append([]string(c.Args()), args...)

	cmd := exec.Command("kubectl", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

// Helpers

func (sgcli *CLI) decodeInputFileInto(c *cli.Context, item model.Model) (err error) {
	var file *os.File

	switch filepath := c.String("f"); filepath {
	case "":
		return errors.New("-f required")
	case "-":
		file = sgcli.Stdin
	default:
		file, err = os.Open(filepath)
		if err != nil {
			return err
		}
		defer file.Close()
	}

	err = json.NewDecoder(file).Decode(item)
	return err
}
<commit_msg>Remove deprecated api-version flag. Fixes #181. (#182)<commit_after>package cli

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"

	"github.com/mitchellh/go-homedir"
	"github.com/supergiant/supergiant/pkg/client"
	"github.com/supergiant/supergiant/pkg/model"
	"github.com/urfave/cli"
)

var globalConfFile string

func init() {
	home, err := homedir.Dir()
	if err != nil {
		panic(err)
	}
	globalConfFile = home + "/.supergiant"
}

var baseFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "server, s",
		Usage: "Host and port of the Supergiant server",
	},
	cli.StringFlag{
		Name:  "api-token, t",
		Usage: "API token of the operating Supergiant User",
	},
	cli.StringFlag{
		Name:  "cert-file, c",
		Usage: "Filepath of the SSL certificate used by the server. If not provided, the cert must be manually trusted through OS.",
	},
}

type CLI struct {
	*cli.App
	Client  func(*cli.Context) *client.Client
	Stdin   *os.File
	Version string
}

func New(clientFn func(*cli.Context) *client.Client, stdin *os.File, version string) *CLI {
	sgcli := &CLI{cli.NewApp(), clientFn, stdin, version}

	sgcli.Name = "supergiant"
	sgcli.Usage = "Supergiant CLI " + version
	// TODO for whatever reason the version always reports 0.0.0
	sgcli.Version = version

	sgcli.Commands = []cli.Command{
		{
			Name:   "configure",
			Usage:  "globally configure server settings (helpful to prevent repeating flags)",
			Flags:  baseFlags,
			Action: sgcli.commandConfigure,
		},
		{
			Name:  "kubectl",
			Usage: "wrapper for Kubectl that auto-populates connection-related tags",
			Flags: append(baseFlags, []cli.Flag{
				cli.Int64Flag{
					Name:  "kube-id, k",
					Usage: "ID of the Supergiant Kube",
				},
			}...),
			Action: sgcli.commandKubectl,
		},
		{
			Name:  "cloud_accounts",
			Usage: "actions for CloudAccounts",
			Subcommands: []cli.Command{
				sgcli.commandList("CloudAccounts", new(model.CloudAccountList)),
				sgcli.commandCreate("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandGet("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandUpdate("CloudAccounts", new(model.CloudAccount)),
				sgcli.commandAction("delete", "Delete", "CloudAccounts", new(model.CloudAccount)),
			},
		},
		{
			Name:  "entrypoints",
			Usage: "actions for Entrypoints",
			Subcommands: []cli.Command{
				sgcli.commandList("Entrypoints", new(model.EntrypointList)),
				sgcli.commandCreate("Entrypoints", new(model.Entrypoint)),
				sgcli.commandGet("Entrypoints", new(model.Entrypoint)),
				sgcli.commandUpdate("Entrypoints", new(model.Entrypoint)),
				sgcli.commandAction("delete", "Delete", "Entrypoints", new(model.Entrypoint)),
			},
		},
		{
			Name:  "entrypoint_listeners",
			Usage: "actions for EntrypointListeners",
			Subcommands: []cli.Command{
				sgcli.commandList("EntrypointListeners", new(model.EntrypointListenerList)),
				sgcli.commandCreate("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandGet("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandUpdate("EntrypointListeners", new(model.EntrypointListener)),
				sgcli.commandAction("delete", "Delete", "EntrypointListeners", new(model.EntrypointListener)),
			},
		},
		{
			Name:  "kubes",
			Usage: "actions for Kubes",
			Subcommands: []cli.Command{
				sgcli.commandList("Kubes", new(model.KubeList)),
				sgcli.commandCreate("Kubes", new(model.Kube)),
				sgcli.commandGet("Kubes", new(model.Kube)),
				sgcli.commandUpdate("Kubes", new(model.Kube)),
				sgcli.commandAction("delete", "Delete", "Kubes", new(model.Kube)),
			},
		},
		{
			Name:  "nodes",
			Usage: "actions for Nodes",
			Subcommands: []cli.Command{
				sgcli.commandList("Nodes", new(model.NodeList)),
				sgcli.commandCreate("Nodes", new(model.Node)),
				sgcli.commandGet("Nodes", new(model.Node)),
				sgcli.commandUpdate("Nodes", new(model.Node)),
				sgcli.commandAction("delete", "Delete", "Nodes", new(model.Node)),
			},
		},
		{
			Name:  "sessions",
			Usage: "actions for Sessions",
			Subcommands: []cli.Command{
				sgcli.commandList("Sessions", new(model.SessionList)),
				sgcli.commandCreate("Sessions", new(model.Session)),
				sgcli.commandGet("Sessions", new(model.Session)),
				sgcli.commandAction("delete", "Delete", "Sessions", new(model.Session)),
			},
		},
		{
			Name:  "users",
			Usage: "actions for Users",
			Subcommands: []cli.Command{
				sgcli.commandList("Users", new(model.UserList)),
				sgcli.commandCreate("Users", new(model.User)),
				sgcli.commandGet("Users", new(model.User)),
				sgcli.commandUpdate("Users", new(model.User)),
				sgcli.commandAction("delete", "Delete", "Users", new(model.User)),
			},
		},
		{
			Name:  "volumes",
			Usage: "actions for Volumes",
			Subcommands: []cli.Command{
				sgcli.commandList("Volumes", new(model.VolumeList)),
				sgcli.commandCreate("Volumes", new(model.Volume)),
				sgcli.commandGet("Volumes", new(model.Volume)),
				sgcli.commandUpdate("Volumes", new(model.Volume)),
				sgcli.commandAction("delete", "Delete", "Volumes", new(model.Volume)),
				sgcli.commandAction("resize", "Resize", "Volumes", new(model.Volume)),
			},
		},
		{
			Name:  "kube_resources",
			Usage: "actions for Kube Resources",
			Subcommands: []cli.Command{
				sgcli.commandList("KubeResources", new(model.KubeResourceList)),
				sgcli.commandCreate("KubeResources", new(model.KubeResource)),
				sgcli.commandGet("KubeResources", new(model.KubeResource)),
				sgcli.commandUpdate("KubeResources", new(model.KubeResource)),
				sgcli.commandAction("delete", "Delete", "KubeResources", new(model.KubeResource)),
				sgcli.commandAction("start", "Start", "KubeResources", new(model.KubeResource)),
				sgcli.commandAction("stop", "Stop", "KubeResources", new(model.KubeResource)),
			},
		},
	}

	return sgcli
}

// Private

func (sgcli *CLI) commandList(collectionName string, list model.List) cli.Command {
	return cli.Command{
		Name:  "list",
		Usage: "list " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringSliceFlag{
				Name:  "filter",
				Usage: "--filter=name:this,or,that --filter=other_field:value",
			},
			cli.StringFlag{
				Name:  "format",
				Usage: "--format=\"{{ .ThisField }}\"",
			},
		}...),
		Action: func(c *cli.Context) error {
			filters, err := listFilters(c)
			if err != nil {
				return err
			}

			reflectList := reflect.ValueOf(list)

			// Set filters
			reflectList.Elem().FieldByName("Filters").Set(reflect.ValueOf(filters))

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("List")
			ret := fn.Call([]reflect.Value{reflectList})

			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}
			return printList(c, list)
		},
	}
}

func (sgcli *CLI) commandCreate(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "create",
		Usage: "create new " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "file, f",
				Usage: "JSON input file",
			},
		}...),
		Action: func(c *cli.Context) error {
			if err := sgcli.decodeInputFileInto(c, item); err != nil {
				return err
			}

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Create")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandGet(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "get",
		Usage: "get " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Get")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandUpdate(collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  "update",
		Usage: "update " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
			cli.StringFlag{
				Name:  "file, f",
				Usage: "JSON input file",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")
			if err := sgcli.decodeInputFileInto(c, item); err != nil {
				return err
			}

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName("Update")
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

func (sgcli *CLI) commandAction(action string, methodName string, collectionName string, item model.Model) cli.Command {
	return cli.Command{
		Name:  action,
		Usage: action + " " + collectionName,
		Flags: append(baseFlags, []cli.Flag{
			cli.StringFlag{
				Name:  "id",
				Usage: "the resource ID",
			},
		}...),
		Action: func(c *cli.Context) error {
			id := c.Int64("id")

			fn := reflect.ValueOf(sgcli.Client(c)).Elem().FieldByName(collectionName).MethodByName(methodName)
			ret := fn.Call([]reflect.Value{reflect.ValueOf(&id), reflect.ValueOf(item)})
			if err := ret[0].Interface(); err != nil {
				return err.(error)
			}

			return printObj(item)
		},
	}
}

// Root commands

func (sgcli *CLI) commandConfigure(c *cli.Context) error {
	conf := newGlobalConf(c)
	b, err := json.Marshal(conf)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(globalConfFile, b, 0600); err != nil {
		return err
	}
	fmt.Println("Written to " + globalConfFile)
	return nil
}

func (sgcli *CLI) commandKubectl(c *cli.Context) error {
	id := c.Int64("kube-id")
	kube := new(model.Kube)
	if err := sgcli.Client(c).Kubes.Get(&id, kube); err != nil {
		return err
	}

	args := []string{
		"--insecure-skip-tls-verify=true",
		"--server=https://" + kube.MasterPublicIP,
		"--cluster=" + kube.Name,
		"--username=" + kube.Username,
		"--password=" + kube.Password,
	}
	// Prepend the user's kubectl args, which will look like `get pods --namespace=kube-system`
	args = append([]string(c.Args()), args...)

	cmd := exec.Command("kubectl", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

// Helpers

func (sgcli *CLI) decodeInputFileInto(c *cli.Context, item model.Model) (err error) {
	var file *os.File

	switch filepath := c.String("f"); filepath {
	case "":
		return errors.New("-f required")
	case "-":
		file = sgcli.Stdin
	default:
		file, err = os.Open(filepath)
		if err != nil {
			return err
		}
		defer file.Close()
	}

	err = json.NewDecoder(file).Decode(item)
	return err
}
<|endoftext|>


<commit_before>package hub // import "a4.io/blobstash/pkg/hub"

import (
	"context"

	log "github.com/inconshreveable/log15"

	"a4.io/blobstash/pkg/blob"
	_ "a4.io/blobstash/pkg/ctxutil"
)

type EventType int

const (
	NewBlob EventType = iota
	ScanBlob
	GarbageCollection
	AppUpdate
)

type AppUpdateData struct {
	Ref          string
	Name         string
	RawAppConfig []byte
}

type Hub struct {
	log         log.Logger
	subscribers map[EventType]map[string]func(context.Context, *blob.Blob, interface{}) error
}

func (h *Hub) Subscribe(etype EventType, name string, callback func(context.Context, *blob.Blob, interface{}) error) {
	h.log.Info("new subscription", "type", etype, "name", name)
	h.subscribers[etype][name] = callback
}

func (h *Hub) newEvent(ctx context.Context, etype EventType, blob *blob.Blob, data interface{}) error {
	l := h.log.New("type", etype, "blob", blob, "data", data)
	l.Debug("new event")
	for name, callback := range h.subscribers[etype] {
		h.log.Debug("triggering callback", "name", name)
		if err := callback(ctx, blob, data); err != nil {
			return err
		}
	}
	return nil
}

func (h *Hub) NewAppUpdateEvent(ctx context.Context, blob *blob.Blob, data interface{}) error {
	return h.newEvent(ctx, AppUpdate, blob, data)
}

func (h *Hub) NewBlobEvent(ctx context.Context, blob *blob.Blob, data interface{}) error {
	return h.newEvent(ctx, NewBlob, blob, data)
}

func (h *Hub) ScanBlobEvent(ctx context.Context, blob *blob.Blob, data interface{}) error {
	return h.newEvent(ctx, ScanBlob, blob, data)
}

func New(logger log.Logger) *Hub {
	logger.Debug("init")
	return &Hub{
		log: logger,
		subscribers: map[EventType]map[string]func(context.Context, *blob.Blob, interface{}) error{
			NewBlob:   map[string]func(context.Context, *blob.Blob, interface{}) error{},
			ScanBlob:  map[string]func(context.Context, *blob.Blob, interface{}) error{},
			AppUpdate: map[string]func(context.Context, *blob.Blob, interface{}) error{},
		},
	}
}
<commit_msg>hub: removed old app update event<commit_after>package hub // import "a4.io/blobstash/pkg/hub"

import (
	"context"

	log "github.com/inconshreveable/log15"

	"a4.io/blobstash/pkg/blob"
	_ "a4.io/blobstash/pkg/ctxutil"
)

type EventType int

const (
	NewBlob EventType = iota
	ScanBlob
	GarbageCollection
)

type Hub struct {
	log         log.Logger
	subscribers map[EventType]map[string]func(context.Context, *blob.Blob, interface{}) error
}

func (h *Hub) Subscribe(etype EventType, name string, callback func(context.Context, *blob.Blob, interface{}) error) {
	h.log.Info("new subscription", "type", etype, "name", name)
	h.subscribers[etype][name] = callback
}

func (h *Hub) newEvent(ctx context.Context, etype EventType, blob *blob.Blob, data interface{}) error {
	l := h.log.New("type", etype, "blob", blob, "data", data)
	l.Debug("new event")
	for name, callback := range h.subscribers[etype] {
		h.log.Debug("triggering callback", "name", name)
		if err := callback(ctx, blob, data); err != nil {
			return err
		}
	}
	return nil
}

func (h *Hub) NewBlobEvent(ctx context.Context, blob *blob.Blob, data interface{}) error {
	return h.newEvent(ctx, NewBlob, blob, data)
}

func (h *Hub) ScanBlobEvent(ctx context.Context, blob *blob.Blob, data interface{}) error {
	return h.newEvent(ctx, ScanBlob, blob, data)
}

func New(logger log.Logger) *Hub {
	logger.Debug("init")
	return &Hub{
		log: logger,
		subscribers: map[EventType]map[string]func(context.Context, *blob.Blob, interface{}) error{
			NewBlob:  map[string]func(context.Context, *blob.Blob, interface{}) error{},
			ScanBlob: map[string]func(context.Context, *blob.Blob, interface{}) error{},
		},
	}
}
<|endoftext|>


<commit_before>package zk

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"bazil.org/fuse/fuseutil"
	"github.com/golang/glog"
	"github.com/qorio/maestro/pkg/registry"
	"golang.org/x/net/context"
	"os"
	"sync"
	"syscall"
)

type fsNode struct {
	Path registry.Path
	conn ZK
	node *Node
	Dir  *Dir
}

type FS struct {
	*fsNode
}

type Dir struct {
	*fsNode
}

type File struct {
	*fsNode

	// lock
	mu sync.Mutex
	// number of write-capable handles currently open
	writers uint
}

var _ = fs.FS(&FS{})

func fs_node(zc ZK, n *Node, p registry.Path, d *Dir) *fsNode {
	return &fsNode{
		Dir:  d,
		Path: p,
		conn: zc,
		node: n,
	}
}

func (this *FS) Root() (fs.Node, error) {
	glog.Infoln("Root")
	if this.node == nil {
		if n, err := Follow(this.conn, this.Path); err != nil {
			glog.Infoln(">>>>>>", this.Path, err)
			return nil, err
		} else {
			this.node = n
		}
	}
	n := &Dir{
		fsNode: fs_node(this.conn, this.node, this.Path, nil),
	}
	return n, nil
}

var _ = fs.Node(&Dir{})

func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Mode = os.ModeDir | 0755
	return nil
}

var _ = fs.HandleReadDirAller(&Dir{})

func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	var result []fuse.Dirent

	if children, err := d.node.Children(); err != nil {
		return nil, err
	} else {
		for _, c := range children {
			de := fuse.Dirent{
				Name: c.GetBasename(),
			}
			if c.CountChildren() == 0 {
				de.Type = fuse.DT_File
			} else {
				de.Type = fuse.DT_Dir
			}
			result = append(result, de)
		}
		return result, nil
	}
}

var _ = fs.NodeStringLookuper(&Dir{})

func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	child := d.Path.Sub(name)
	n, err := Follow(d.conn, child)
	switch err {
	case ErrNotExist:
		return nil, fuse.ENOENT
	case nil:
		if n.CountChildren() == 0 {
			return &File{
				fsNode: fs_node(d.conn, n, child, d),
			}, nil
		} else {
			return &Dir{
				fsNode: fs_node(d.conn, n, child, d),
			}, nil
		}
	default:
		return nil, err
	}
}

var _ = fs.NodeMkdirer(&Dir{})

func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	path := d.Path.Sub(req.Name)
	if PathExists(d.conn, path) {
		return nil, fuse.EEXIST
	}
	// TODO - check permissions and return fuse.EPERM if not writable
	err := CreateOrSetBytes(d.conn, path, []byte{})
	if err != nil {
		return nil, err
	}
	n, err := Follow(d.conn, path)
	if err != nil {
		return nil, err
	}
	return &Dir{
		fsNode: fs_node(d.conn, n, path, d),
	}, nil
}

var _ = fs.NodeCreater(&Dir{})

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	path := d.Path.Sub(req.Name)
	if PathExists(d.conn, path) {
		return nil, nil, fuse.EEXIST
	}

	err := CreateOrSetBytes(d.conn, path, []byte(""))
	if err != nil {
		return nil, nil, err
	}
	n, err := d.conn.Get(path.Path())
	if err != nil {
		return nil, nil, err
	}
	f := &File{
		fsNode: fs_node(d.conn, n, path, d),
	}
	glog.Infoln(">>>> create", path, f, n)
	return f, f, nil
}

var _ = fs.NodeRemover(&Dir{})

func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	path := d.Path.Sub(req.Name)
	if !PathExists(d.conn, path) {
		return fuse.ENOENT
	}
	return DeleteObject(d.conn, path)
}

var _ = fs.Node(&File{})
var _ = fs.Handle(&File{})

func (f *File) Attr(ctx context.Context, a *fuse.Attr) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	n, err := Follow(f.conn, f.Path)
	if err != nil {
		return err
	}
	a.Mode = 0644
	a.Size = uint64(len(n.Value))
	return nil
}

var _ = fs.NodeOpener(&File{})

func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	glog.Infoln("Open", ctx, req, resp)

	if req.Flags.IsReadOnly() {
		// we don't need to track read-only handles
		return f, nil
	}
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.writers == 0 || f.node == nil {
		if n, err := Follow(f.conn, f.Path); err != nil {
			return nil, err
		} else {
			f.node = n
		}
	}

	f.writers++
	return f, nil
}

var _ = fs.HandleReleaser(&File{})

func (f *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	f.writers--
	return nil
}

var _ = fs.HandleReader(&File{})

func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.node == nil {
		if n, err := Follow(f.conn, f.Path); err != nil {
			return nil
		} else {
			f.node = n
		}
	}
	fuseutil.HandleRead(req, resp, f.node.Value)
	return nil
}

var _ = fs.HandleWriter(&File{})

const maxInt = int(^uint(0) >> 1)

func (f *File) write_data(input []byte, offset int64) (int, error) {
	glog.Infoln("write_data", string(input), offset)

	// expand the buffer if necessary
	newLen := offset + int64(len(input))
	if newLen > int64(maxInt) {
		return 0, fuse.Errno(syscall.EFBIG)
	}
	if newLen := int(newLen); newLen > len(f.node.Value) {
		f.node.Value = append(f.node.Value, make([]byte, newLen-len(f.node.Value))...)
	}
	n := copy(f.node.Value[offset:], input)
	err := f.node.Set(f.node.Value)
	glog.Infoln("write_data", string(f.node.Value), err)

	return n, err
}

func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	glog.Infoln("Write", ctx, req, resp)
	_, err := f.write_data(req.Data, req.Offset)
	return err
}

var _ = fs.HandleFlusher(&File{})

func (f *File) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	glog.Infoln("Flush", ctx, req)
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.writers == 0 {
		// Read-only handles also get flushes. Make sure we don't
		// overwrite valid file contents with a nil buffer.
		return nil
	}
	_, err := f.write_data(f.node.Value, 0)
	glog.Infoln("flush:", string(f.node.Value), err)
	return err
}

var _ = fs.NodeSetattrer(&File{})

func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	glog.Infoln("Setattr", ctx, req, resp)
	f.mu.Lock()
	defer f.mu.Unlock()

	if req.Valid.Size() {
		if req.Size > uint64(maxInt) {
			return fuse.Errno(syscall.EFBIG)
		}
		newLen := int(req.Size)
		switch {
		case newLen > len(f.node.Value):
			f.node.Value = append(f.node.Value, make([]byte, newLen-len(f.node.Value))...)
		case newLen < len(f.node.Value):
			f.node.Value = f.node.Value[:newLen]
		}
	}
	return nil
}
<commit_msg>Added unmount and mount<commit_after>package zk

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"bazil.org/fuse/fuseutil"
	"github.com/golang/glog"
	"github.com/qorio/maestro/pkg/registry"
	"golang.org/x/net/context"
	"os"
	"sync"
	"syscall"
)

type fsNode struct {
	Path registry.Path
	conn ZK
	node *Node
	Dir  *Dir
}

type FS struct {
	*fsNode
	fuse_conn  *fuse.Conn
	mountpoint *string
}

func NewFS(zc ZK, path registry.Path) *FS {
	return &FS{
		fsNode: fs_node(zc, nil, path, nil),
	}
}

func (this *FS) Conn() *fuse.Conn {
	return this.fuse_conn
}

func (this *FS) Unmount() error {
	if this.mountpoint != nil {
		return fuse.Unmount(*this.mountpoint)
	}
	return nil
}

func (this *FS) Mount(dir string, perm os.FileMode) error {
	if err := os.MkdirAll(dir, perm); err != nil {
		return err
	}
	fc, err := fuse.Mount(dir)
	if err != nil {
		return err
	}
	this.fuse_conn = fc
	this.mountpoint = &dir
	return fs.Serve(this.fuse_conn, this)
}

func (this *FS) Wait() error {
	if this.fuse_conn != nil {
		<-this.fuse_conn.Ready
	}
	return this.fuse_conn.MountError
}

type Dir struct {
	*fsNode
}

type File struct {
	*fsNode

	// lock
	mu sync.Mutex
	// number of write-capable handles currently open
	writers uint
}

var _ = fs.FS(&FS{})

func fs_node(zc ZK, n *Node, p registry.Path, d *Dir) *fsNode {
	return &fsNode{
		Dir:  d,
		Path: p,
		conn: zc,
		node: n,
	}
}

func (this *FS) Root() (fs.Node, error) {
	glog.Infoln("Root")
	if this.node == nil {
		if n, err := Follow(this.conn, this.Path); err != nil {
			glog.Infoln(">>>>>>", this.Path, err)
			return nil, err
		} else {
			this.node = n
		}
	}
	n := &Dir{
		fsNode: fs_node(this.conn, this.node, this.Path, nil),
	}
	return n, nil
}

var _ = fs.Node(&Dir{})

func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Mode = os.ModeDir | 0755
	return nil
}

var _ = fs.HandleReadDirAller(&Dir{})

func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	var result []fuse.Dirent

	if children, err := d.node.Children(); err != nil {
		return nil, err
	} else {
		for _, c := range children {
			de := fuse.Dirent{
				Name: c.GetBasename(),
			}
			if c.CountChildren() == 0 {
				de.Type = fuse.DT_File
			} else {
				de.Type = fuse.DT_Dir
			}
			result = append(result, de)
		}
		return result, nil
	}
}

var _ = fs.NodeStringLookuper(&Dir{})

func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	child := d.Path.Sub(name)
	n, err := Follow(d.conn, child)
	switch err {
	case ErrNotExist:
		return nil, fuse.ENOENT
	case nil:
		if n.CountChildren() == 0 {
			return &File{
				fsNode: fs_node(d.conn, n, child, d),
			}, nil
		} else {
			return &Dir{
				fsNode: fs_node(d.conn, n, child, d),
			}, nil
		}
	default:
		return nil, err
	}
}

var _ = fs.NodeMkdirer(&Dir{})

func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	path := d.Path.Sub(req.Name)
	if PathExists(d.conn, path) {
		return nil, fuse.EEXIST
	}
	// TODO - check permissions and return fuse.EPERM if not writable
	err := CreateOrSetBytes(d.conn, path, []byte{})
	if err != nil {
		return nil, err
	}
	n, err := Follow(d.conn, path)
	if err != nil {
		return nil, err
	}
	return &Dir{
		fsNode: fs_node(d.conn, n, path, d),
	}, nil
}

var _ = fs.NodeCreater(&Dir{})

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	path := d.Path.Sub(req.Name)
	if PathExists(d.conn, path) {
		return nil, nil, fuse.EEXIST
	}

	err := CreateOrSetBytes(d.conn, path, []byte(""))
	if err != nil {
		return nil, nil, err
	}
	n, err := d.conn.Get(path.Path())
	if err != nil {
		return nil, nil, err
	}
	f := &File{
		fsNode: fs_node(d.conn, n, path, d),
	}
	glog.Infoln(">>>> create", path, f, n)
	return f, f, nil
}

var _ = fs.NodeRemover(&Dir{})

func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	path := d.Path.Sub(req.Name)
	if !PathExists(d.conn, path) {
		return fuse.ENOENT
	}
	return DeleteObject(d.conn, path)
}

var _ = fs.Node(&File{})
var _ = fs.Handle(&File{})

func (f *File) Attr(ctx context.Context, a *fuse.Attr) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	n, err := Follow(f.conn, f.Path)
	if err != nil {
		return err
	}
	a.Mode = 0644
	a.Size = uint64(len(n.Value))
	return nil
}

var _ = fs.NodeOpener(&File{})

func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	glog.Infoln("Open", ctx, req, resp)

	if req.Flags.IsReadOnly() {
		// we don't need to track read-only handles
		return f, nil
	}
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.writers == 0 || f.node == nil {
		if n, err := Follow(f.conn, f.Path); err != nil {
			return nil, err
		} else {
			f.node = n
		}
	}

	f.writers++
	return f, nil
}

var _ = fs.HandleReleaser(&File{})

func (f *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	f.writers--
	return nil
}

var _ = fs.HandleReader(&File{})

func (f *File) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.node == nil {
		if n, err := Follow(f.conn, f.Path); err != nil {
			return nil
		} else {
			f.node = n
		}
	}
	fuseutil.HandleRead(req, resp, f.node.Value)
	return nil
}

var _ = fs.HandleWriter(&File{})

const maxInt = int(^uint(0) >> 1)

func (f *File) write_data(input []byte, offset int64) (int, error) {
	glog.Infoln("write_data", string(input), offset)

	// expand the buffer if necessary
	newLen := offset + int64(len(input))
	if newLen > int64(maxInt) {
		return 0, fuse.Errno(syscall.EFBIG)
	}
	if newLen := int(newLen); newLen > len(f.node.Value) {
		f.node.Value = append(f.node.Value, make([]byte, newLen-len(f.node.Value))...)
	}
	n := copy(f.node.Value[offset:], input)
	err := f.node.Set(f.node.Value)
	glog.Infoln("write_data", string(f.node.Value), err)

	return n, err
}

func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	glog.Infoln("Write", ctx, req, resp)
	_, err := f.write_data(req.Data, req.Offset)
	return err
}

var _ = fs.HandleFlusher(&File{})

func (f *File) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	glog.Infoln("Flush", ctx, req)
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.writers == 0 {
		// Read-only handles also get flushes. Make sure we don't
		// overwrite valid file contents with a nil buffer.
		return nil
	}
	_, err := f.write_data(f.node.Value, 0)
	glog.Infoln("flush:", string(f.node.Value), err)
	return err
}

var _ = fs.NodeSetattrer(&File{})

func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	glog.Infoln("Setattr", ctx, req, resp)
	f.mu.Lock()
	defer f.mu.Unlock()

	if req.Valid.Size() {
		if req.Size > uint64(maxInt) {
			return fuse.Errno(syscall.EFBIG)
		}
		newLen := int(req.Size)
		switch {
		case newLen > len(f.node.Value):
			f.node.Value = append(f.node.Value, make([]byte, newLen-len(f.node.Value))...)
		case newLen < len(f.node.Value):
			f.node.Value = f.node.Value[:newLen]
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/ant0ine/go-json-rest/rest"
	"realbase/core"
	"gopkg.in/mgo.v2/bson"
	"realbase/utils"
	"errors"
	"time"
)

type ApplicationModel struct {
	Id string `json: _id`
	Name string `json: "name"`
}

func GetAppFromRequest(r *rest.Request) (map[string]interface{}, error) {
	appId := r.PathParam("appId")

	if appId != "" {
		//TODO: cache this
		appDb := realbase.NewApplicationsDbService()
		return appDb.FindId(appId, nil)
	} else {
		return nil, errors.New("Invalid app id.")
	}
}

func CreateApplicationHandler(w rest.ResponseWriter, r *rest.Request) {
	body := &ApplicationModel{}

	if err := r.DecodeJsonPayload(body); err != nil {
		RestGeneralError(w, err)
		return
	}

	if body.Name == "" {
		RestErrorInvalidBody(w)
		return
	}

	db := realbase.NewApplicationsDbService()

	username := r.Env["user"].(string)
	doc := bson.M{
		"name": body.Name,
		"owner": username,
		"types": []string{"users"},
		"createdAt": time.Now(),
		"keys": bson.M{ //TODO:
			"Master Key": bson.M{
				"key": utils.GetCleanUUID(),
				"name": "Master Key",
				"permissions": bson.M{
					"types": bson.M{
						"read": true,
						"write": true,
					},
				},
			},
		},
	}

	if err := db.Insert(doc); err != nil {
		RestGeneralError(w, err)
		return
	}

	RespondId(doc["_id"], w)
}

func GetApplicationsHandler(w rest.ResponseWriter, r *rest.Request) {
	db := realbase.NewApplicationsDbService()

	res, err := db.Find(
		bson.M{
			"owner": r.Env["user"],
		},
		bson.M{
			"name": 1,
		},
	)

	if err != nil {
		RestGeneralError(w, err)
		return
	}

	w.WriteJson(res)
}

func GetApplicationHandler(w rest.ResponseWriter, r *rest.Request) {
	app, err := GetAppFromRequest(r)

	if err != nil {
		RestGeneralError(w, err)
		return
	}

	w.WriteJson(app)
}<commit_msg>Updated mport path in application.go<commit_after>package api

import (
	"github.com/ant0ine/go-json-rest/rest"
	"gopkg.in/mgo.v2/bson"
	"errors"
	"time"
	"github.com/realbas3/realbas3/core"
	"github.com/realbas3/realbas3/utils"
)

type ApplicationModel struct {
	Id string `json: _id`
	Name string `json: "name"`
}

func GetAppFromRequest(r *rest.Request) (map[string]interface{}, error) {
	appId := r.PathParam("appId")

	if appId != "" {
		//TODO: cache this
		appDb := realbase.NewApplicationsDbService()
		return appDb.FindId(appId, nil)
	} else {
		return nil, errors.New("Invalid app id.")
	}
}

func CreateApplicationHandler(w rest.ResponseWriter, r *rest.Request) {
	body := &ApplicationModel{}

	if err := r.DecodeJsonPayload(body); err != nil {
		RestGeneralError(w, err)
		return
	}

	if body.Name == "" {
		RestErrorInvalidBody(w)
		return
	}

	db := realbase.NewApplicationsDbService()

	username := r.Env["user"].(string)
	doc := bson.M{
		"name": body.Name,
		"owner": username,
		"types": []string{"users"},
		"createdAt": time.Now(),
		"keys": bson.M{ //TODO:
			"Master Key": bson.M{
				"key": utils.GetCleanUUID(),
				"name": "Master Key",
				"permissions": bson.M{
					"types": bson.M{
						"read": true,
						"write": true,
					},
				},
			},
		},
	}

	if err := db.Insert(doc); err != nil {
		RestGeneralError(w, err)
		return
	}

	RespondId(doc["_id"], w)
}

func GetApplicationsHandler(w rest.ResponseWriter, r *rest.Request) {
	db := realbase.NewApplicationsDbService()

	res, err := db.Find(
		bson.M{
			"owner": r.Env["user"],
		},
		bson.M{
			"name": 1,
		},
	)

	if err != nil {
		RestGeneralError(w, err)
		return
	}

	w.WriteJson(res)
}

func GetApplicationHandler(w rest.ResponseWriter, r *rest.Request) {
	app, err := GetAppFromRequest(r)

	if err != nil {
		RestGeneralError(w, err)
		return
	}

	w.WriteJson(app)
}<|endoftext|>


<commit_before>// Package asset provides business logic for manipulating assets.
package asset

import (
	"bytes"

	"golang.org/x/net/context"

	"chain/api/appdb"
	"chain/errors"
	"chain/fedchain-sandbox/txscript"
	"chain/fedchain-sandbox/wire"
)

// ErrBadAddr is returned by Issue.
var ErrBadAddr = errors.New("bad address")

// Issue creates a transaction that
// issues new units of an asset
// distributed to the outputs provided.
func Issue(ctx context.Context, assetID string, outs []Output) (*Tx, error) {
	tx := wire.NewMsgTx()
	tx.AddTxIn(wire.NewTxIn(wire.NewOutPoint(new(wire.Hash32), 0), []byte{}))

	asset, err := appdb.AssetByID(ctx, assetID)
	if err != nil {
		return nil, errors.WithDetailf(err, "get asset with ID %q", assetID)
	}

	for i, out := range outs {
		if (out.BucketID == "") == (out.Address == "") {
			return nil, errors.WithDetailf(ErrBadOutDest, "output index=%d", i)
		}
	}

	err = addAssetIssuanceOutputs(ctx, tx, asset, outs)
	if err != nil {
		return nil, errors.Wrap(err, "add issuance outputs")
	}

	var buf bytes.Buffer
	tx.Serialize(&buf)
	appTx := &Tx{
		Unsigned:   buf.Bytes(),
		BlockChain: "sandbox", // TODO(tess): make this BlockChain: blockchain.FromContext(ctx)
		Inputs:     []*Input{issuanceInput(asset, tx)},
	}
	return appTx, nil
}

// Output is a user input struct that describes
// the destination of a transaction's inputs.
type Output struct {
	AssetID  string
	Address  string
	BucketID string `json:"bucket_id"`
	Amount   int64
	isChange bool
}

// PkScript returns the script for sending to
// the destination address or bucket id provided.
func (o *Output) PkScript(ctx context.Context) ([]byte, error) {
	if o.BucketID != "" {
		addr := &appdb.Address{
			BucketID: o.BucketID,
		}
		err := CreateAddress(ctx, addr)
		if err != nil {
			return nil, errors.Wrapf(err, "output create address error bucket=%v", o.BucketID)
		}
		return addr.PKScript, nil
	}
	script, err := txscript.AddrPkScript(o.Address)
	if err != nil {
		return nil, errors.Wrapf(ErrBadAddr, "output pkscript error addr=%v", o.Address)
	}
	return script, nil
}

func addAssetIssuanceOutputs(ctx context.Context, tx *wire.MsgTx, asset *appdb.Asset, outs []Output) error {
	for i, out := range outs {
		pkScript, err := out.PkScript(ctx)
		if err != nil {
			return errors.WithDetailf(err, "output %d: %v", i, err.Error())
		}

		tx.AddTxOut(wire.NewTxOut(asset.Hash, out.Amount, pkScript))
	}
	return nil
}

// issuanceInput returns an Input that can be used
// to issue units of asset 'a'.
func issuanceInput(a *appdb.Asset, tx *wire.MsgTx) *Input {
	var buf bytes.Buffer
	tx.Serialize(&buf)

	return &Input{
		AssetGroupID:  a.GroupID,
		RedeemScript:  a.RedeemScript,
		SignatureData: wire.DoubleSha256(buf.Bytes()),
		Sigs:          inputSigs(Signers(a.Keys, IssuancePath(a))),
	}
}

func inputSigs(keys []*DerivedKey) (sigs []*Signature) {
	for _, k := range keys {
		sigs = append(sigs, &Signature{
			XPubHash:       k.Root.ID,
			DerivationPath: k.Path,
		})
	}
	return sigs
}
<commit_msg>api/asset: fix Output struct to have json tags<commit_after>// Package asset provides business logic for manipulating assets.
package asset

import (
	"bytes"

	"golang.org/x/net/context"

	"chain/api/appdb"
	"chain/errors"
	"chain/fedchain-sandbox/txscript"
	"chain/fedchain-sandbox/wire"
)

// ErrBadAddr is returned by Issue.
var ErrBadAddr = errors.New("bad address")

// Issue creates a transaction that
// issues new units of an asset
// distributed to the outputs provided.
func Issue(ctx context.Context, assetID string, outs []Output) (*Tx, error) {
	tx := wire.NewMsgTx()
	tx.AddTxIn(wire.NewTxIn(wire.NewOutPoint(new(wire.Hash32), 0), []byte{}))

	asset, err := appdb.AssetByID(ctx, assetID)
	if err != nil {
		return nil, errors.WithDetailf(err, "get asset with ID %q", assetID)
	}

	for i, out := range outs {
		if (out.BucketID == "") == (out.Address == "") {
			return nil, errors.WithDetailf(ErrBadOutDest, "output index=%d", i)
		}
	}

	err = addAssetIssuanceOutputs(ctx, tx, asset, outs)
	if err != nil {
		return nil, errors.Wrap(err, "add issuance outputs")
	}

	var buf bytes.Buffer
	tx.Serialize(&buf)
	appTx := &Tx{
		Unsigned:   buf.Bytes(),
		BlockChain: "sandbox", // TODO(tess): make this BlockChain: blockchain.FromContext(ctx)
		Inputs:     []*Input{issuanceInput(asset, tx)},
	}
	return appTx, nil
}

// Output is a user input struct that describes
// the destination of a transaction's inputs.
type Output struct {
	AssetID  string `json:"asset_id"`
	Address  string `json:"address"`
	BucketID string `json:"bucket_id"`
	Amount   int64  `json:"amount"`
	isChange bool
}

// PkScript returns the script for sending to
// the destination address or bucket id provided.
func (o *Output) PkScript(ctx context.Context) ([]byte, error) {
	if o.BucketID != "" {
		addr := &appdb.Address{
			BucketID: o.BucketID,
		}
		err := CreateAddress(ctx, addr)
		if err != nil {
			return nil, errors.Wrapf(err, "output create address error bucket=%v", o.BucketID)
		}
		return addr.PKScript, nil
	}
	script, err := txscript.AddrPkScript(o.Address)
	if err != nil {
		return nil, errors.Wrapf(ErrBadAddr, "output pkscript error addr=%v", o.Address)
	}
	return script, nil
}

func addAssetIssuanceOutputs(ctx context.Context, tx *wire.MsgTx, asset *appdb.Asset, outs []Output) error {
	for i, out := range outs {
		pkScript, err := out.PkScript(ctx)
		if err != nil {
			return errors.WithDetailf(err, "output %d: %v", i, err.Error())
		}

		tx.AddTxOut(wire.NewTxOut(asset.Hash, out.Amount, pkScript))
	}
	return nil
}

// issuanceInput returns an Input that can be used
// to issue units of asset 'a'.
func issuanceInput(a *appdb.Asset, tx *wire.MsgTx) *Input {
	var buf bytes.Buffer
	tx.Serialize(&buf)

	return &Input{
		AssetGroupID:  a.GroupID,
		RedeemScript:  a.RedeemScript,
		SignatureData: wire.DoubleSha256(buf.Bytes()),
		Sigs:          inputSigs(Signers(a.Keys, IssuancePath(a))),
	}
}

func inputSigs(keys []*DerivedKey) (sigs []*Signature) {
	for _, k := range keys {
		sigs = append(sigs, &Signature{
			XPubHash:       k.Root.ID,
			DerivationPath: k.Path,
		})
	}
	return sigs
}
<|endoftext|>