<commit_before>// Copyright 2015-2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package undertaker

import (
	"fmt"

	"github.com/juju/errors"

	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/status"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker/catacomb"
)

// Facade covers the parts of the api/undertaker.UndertakerClient that we
// need for the worker. It's more than a little raw, but we'll survive.
type Facade interface {
	ModelInfo() (params.UndertakerModelInfoResult, error)
	WatchModelResources() (watcher.NotifyWatcher, error)
	ProcessDyingModel() error
	RemoveModel() error
	SetStatus(status status.Status, message string, data map[string]interface{}) error
}

// Config holds the resources and configuration necessary to run an
// undertaker worker.
type Config struct {
	Facade  Facade
	Environ environs.Environ
}

// Validate returns an error if the config cannot be expected to drive
// a functional undertaker worker.
func (config Config) Validate() error {
	if config.Facade == nil {
		return errors.NotValidf("nil Facade")
	}
	if config.Environ == nil {
		return errors.NotValidf("nil Environ")
	}
	return nil
}

// NewUndertaker returns a worker which processes a dying model.
func NewUndertaker(config Config) (*Undertaker, error) {
	if err := config.Validate(); err != nil {
		return nil, errors.Trace(err)
	}
	u := &Undertaker{
		config: config,
	}
	err := catacomb.Invoke(catacomb.Plan{
		Site: &u.catacomb,
		Work: u.run,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return u, nil
}

type Undertaker struct {
	catacomb catacomb.Catacomb
	config   Config
}

// Kill is part of the worker.Worker interface.
func (u *Undertaker) Kill() {
	u.catacomb.Kill(nil)
}

// Wait is part of the worker.Worker interface.
func (u *Undertaker) Wait() error {
	return u.catacomb.Wait()
}

func (u *Undertaker) run() error {
	result, err := u.config.Facade.ModelInfo()
	if err != nil {
		return errors.Trace(err)
	}
	if result.Error != nil {
		return errors.Trace(result.Error)
	}
	modelInfo := result.Result

	if modelInfo.Life == params.Alive {
		return errors.Errorf("model still alive")
	}

	if modelInfo.Life == params.Dying {
		// TODO(axw) 2016-04-14 #1570285
		// We should update status with information
		// about the remaining resources here, and
		// also make the worker responsible for
		// checking the emptiness criteria before
		// attempting to remove the model.
		if err := u.setStatus(
			status.Destroying,
			"cleaning up cloud resources",
		); err != nil {
			return errors.Trace(err)
		}
		// Process the dying model. This blocks until the model
		// is dead or the worker is stopped.
		if err := u.processDyingModel(); err != nil {
			return errors.Trace(err)
		}
	}

	// If we get this far, the model must be dead (or *have been*
	// dead, but actually removed by something else since the call).
	if modelInfo.IsSystem {
		// Nothing to do. We don't destroy environ resources or
		// delete model docs for a controller model, because we're
		// running inside that controller and can't safely clean up
		// our own infrastructure. (That'll be the client's job in
		// the end, once we've reported that we've tidied up what we
		// can, by returning nil here, indicating that we've set it
		// to Dead -- implied by processDyingModel succeeding.)
		return nil
	}

	// Now the model is known to be hosted and dead, we can tidy up any
	// provider resources it might have used.
	if err := u.setStatus(
		status.Destroying, "tearing down cloud environment",
	); err != nil {
		return errors.Trace(err)
	}
	if err := u.config.Environ.Destroy(); err != nil {
		return errors.Trace(err)
	}

	// Finally, remove the model.
	if err := u.config.Facade.RemoveModel(); err != nil {
		return errors.Annotate(err, "cannot remove model")
	}
	return nil
}

func (u *Undertaker) setStatus(modelStatus status.Status, message string) error {
	return u.config.Facade.SetStatus(modelStatus, message, nil)
}

func (u *Undertaker) processDyingModel() error {
	watcher, err := u.config.Facade.WatchModelResources()
	if err != nil {
		return errors.Trace(err)
	}
	if err := u.catacomb.Add(watcher); err != nil {
		return errors.Trace(err)
	}
	defer watcher.Kill() // The watcher is not needed once this func returns.

	attempt := 1
	for {
		select {
		case <-u.catacomb.Dying():
			return u.catacomb.ErrDying()
		case <-watcher.Changes():
			// TODO(fwereade): this is wrong. If there's a time
			// it's ok to ignore an error, it's when we know
			// exactly what an error is/means. If there's a
			// specific code for "not done yet", *that* is what
			// we should be ignoring. But unknown errors are
			// *unknown*, and we can't just assume that it's
			// safe to continue.
			err := u.config.Facade.ProcessDyingModel()
			if err == nil {
				// ProcessDyingModel succeeded. We're free to
				// destroy any remaining environ resources.
				return nil
			}
			// Yes, we ignore the error. See comment above. But let's at least
			// surface it in status.
			u.setStatus(status.Destroying, fmt.Sprintf("%d attempt to destroy model:  %v", attempt, err))
		}
		attempt++
	}
}
<commit_msg>Change status message to be clearer.<commit_after>// Copyright 2015-2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package undertaker

import (
	"fmt"

	"github.com/juju/errors"

	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/status"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker/catacomb"
)

// Facade covers the parts of the api/undertaker.UndertakerClient that we
// need for the worker. It's more than a little raw, but we'll survive.
type Facade interface {
	ModelInfo() (params.UndertakerModelInfoResult, error)
	WatchModelResources() (watcher.NotifyWatcher, error)
	ProcessDyingModel() error
	RemoveModel() error
	SetStatus(status status.Status, message string, data map[string]interface{}) error
}

// Config holds the resources and configuration necessary to run an
// undertaker worker.
type Config struct {
	Facade  Facade
	Environ environs.Environ
}

// Validate returns an error if the config cannot be expected to drive
// a functional undertaker worker.
func (config Config) Validate() error {
	if config.Facade == nil {
		return errors.NotValidf("nil Facade")
	}
	if config.Environ == nil {
		return errors.NotValidf("nil Environ")
	}
	return nil
}

// NewUndertaker returns a worker which processes a dying model.
func NewUndertaker(config Config) (*Undertaker, error) {
	if err := config.Validate(); err != nil {
		return nil, errors.Trace(err)
	}
	u := &Undertaker{
		config: config,
	}
	err := catacomb.Invoke(catacomb.Plan{
		Site: &u.catacomb,
		Work: u.run,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return u, nil
}

type Undertaker struct {
	catacomb catacomb.Catacomb
	config   Config
}

// Kill is part of the worker.Worker interface.
func (u *Undertaker) Kill() {
	u.catacomb.Kill(nil)
}

// Wait is part of the worker.Worker interface.
func (u *Undertaker) Wait() error {
	return u.catacomb.Wait()
}

func (u *Undertaker) run() error {
	result, err := u.config.Facade.ModelInfo()
	if err != nil {
		return errors.Trace(err)
	}
	if result.Error != nil {
		return errors.Trace(result.Error)
	}
	modelInfo := result.Result

	if modelInfo.Life == params.Alive {
		return errors.Errorf("model still alive")
	}

	if modelInfo.Life == params.Dying {
		// TODO(axw) 2016-04-14 #1570285
		// We should update status with information
		// about the remaining resources here, and
		// also make the worker responsible for
		// checking the emptiness criteria before
		// attempting to remove the model.
		if err := u.setStatus(
			status.Destroying,
			"cleaning up cloud resources",
		); err != nil {
			return errors.Trace(err)
		}
		// Process the dying model. This blocks until the model
		// is dead or the worker is stopped.
		if err := u.processDyingModel(); err != nil {
			return errors.Trace(err)
		}
	}

	// If we get this far, the model must be dead (or *have been*
	// dead, but actually removed by something else since the call).
	if modelInfo.IsSystem {
		// Nothing to do. We don't destroy environ resources or
		// delete model docs for a controller model, because we're
		// running inside that controller and can't safely clean up
		// our own infrastructure. (That'll be the client's job in
		// the end, once we've reported that we've tidied up what we
		// can, by returning nil here, indicating that we've set it
		// to Dead -- implied by processDyingModel succeeding.)
		return nil
	}

	// Now the model is known to be hosted and dead, we can tidy up any
	// provider resources it might have used.
	if err := u.setStatus(
		status.Destroying, "tearing down cloud environment",
	); err != nil {
		return errors.Trace(err)
	}
	if err := u.config.Environ.Destroy(); err != nil {
		return errors.Trace(err)
	}

	// Finally, remove the model.
	if err := u.config.Facade.RemoveModel(); err != nil {
		return errors.Annotate(err, "cannot remove model")
	}
	return nil
}

func (u *Undertaker) setStatus(modelStatus status.Status, message string) error {
	return u.config.Facade.SetStatus(modelStatus, message, nil)
}

func (u *Undertaker) processDyingModel() error {
	watcher, err := u.config.Facade.WatchModelResources()
	if err != nil {
		return errors.Trace(err)
	}
	if err := u.catacomb.Add(watcher); err != nil {
		return errors.Trace(err)
	}
	defer watcher.Kill() // The watcher is not needed once this func returns.

	attempt := 1
	for {
		select {
		case <-u.catacomb.Dying():
			return u.catacomb.ErrDying()
		case <-watcher.Changes():
			// TODO(fwereade): this is wrong. If there's a time
			// it's ok to ignore an error, it's when we know
			// exactly what an error is/means. If there's a
			// specific code for "not done yet", *that* is what
			// we should be ignoring. But unknown errors are
			// *unknown*, and we can't just assume that it's
			// safe to continue.
			err := u.config.Facade.ProcessDyingModel()
			if err == nil {
				// ProcessDyingModel succeeded. We're free to
				// destroy any remaining environ resources.
				return nil
			}
			// Yes, we ignore the error. See comment above. But let's at least
			// surface it in status.
			u.setStatus(status.Destroying, fmt.Sprintf("attempt %d to destroy model failed (will retry):  %v", attempt, err))
		}
		attempt++
	}
}
<|endoftext|>


<commit_before>package poloniex

import (
	"encoding/json"
	"fmt"
	"net/url"
	"time"

	"github.com/franela/goreq"
	"github.com/k0kubun/pp"
	"github.com/shopspring/decimal"
)

type (
	Ticker      map[string]TickerEntry
	TickerEntry struct {
		Last        decimal.Decimal `json:",string"`
		Ask         decimal.Decimal `json:"lowestAsk,string"`
		Bid         decimal.Decimal `json:"highestBid,string"`
		Change      decimal.Decimal `json:"percentChange,string"`
		BaseVolume  decimal.Decimal `json:"baseVolume,string"`
		QuoteVolume decimal.Decimal `json:"quoteVolume,string"`
		IsFrozen    int64           `json:"isFrozen,string"`
	}

	DailyVolume          map[string]DailyVolumeEntry
	DailyVolumeEntry     map[string]decimal.Decimal
	DailyVolumeTemp      map[string]interface{}
	DailyVolumeEntryTemp map[string]interface{}

	OrderBook struct {
		Asks     []Order
		Bids     []Order
		IsFrozen bool
	}
	Order struct {
		Rate   decimal.Decimal
		Amount decimal.Decimal
	}

	OrderBookTemp struct {
		Asks     []OrderTemp
		Bids     []OrderTemp
		IsFrozen interface{}
	}
	OrderTemp        []interface{}
	OrderBookAll     map[string]OrderBook
	OrderBookAllTemp map[string]OrderBookTemp

	TradeHistory      []TradeHistoryEntry
	TradeHistoryEntry struct {
		ID     int64 `json:"globalTradeID"`
		Date   string
		Type   string
		Rate   decimal.Decimal `json:",string"`
		Amount decimal.Decimal `json:",string"`
		Total  decimal.Decimal `json:",string"`
	}

	ChartData      []ChartDataEntry
	ChartDataEntry struct {
		Date            int64
		High            decimal.Decimal
		Low             decimal.Decimal
		Open            decimal.Decimal
		Close           decimal.Decimal
		Volume          decimal.Decimal
		QuoteVolume     decimal.Decimal
		WeightedAverage decimal.Decimal
	}

	Currencies map[string]Currency
	Currency   struct {
		Name           string
		TxFee          decimal.Decimal `json:",string"`
		MinConf        decimal.Decimal
		DepositAddress string
		Disabled       int64
		Delisted       int64
		Frozen         int64
	}

	LoanOrders struct {
		Offers  []LoanOrder
		Demands []LoanOrder
	}
	LoanOrder struct {
		Rate     decimal.Decimal `json:",string"`
		Amount   decimal.Decimal `json:",string"`
		RangeMin decimal.Decimal
		RangeMax decimal.Decimal
	}
)

func (p *Poloniex) Ticker() (ticker Ticker, err error) {
	err = p.public("returnTicker", nil, &ticker)
	return
}

func (p *Poloniex) DailyVolume() (dailyVolume DailyVolume, err error) {
	dvt := DailyVolumeTemp{}
	err = p.public("return24hVolume", nil, &dvt)
	if err != nil {
		return
	}
	dailyVolume = DailyVolume{}
	for k := range dvt {
		v := dvt[k]
		dve := DailyVolumeEntry{}
		switch i := v.(type) {
		default:
			v := i.(map[string]interface{})
			for kk, vv := range v {
				dve[kk] = ToDecimal(vv)
			}
			dailyVolume[k] = dve
		case string:
			//ignore anything that isn't a map
		}
	}
	return
}

func (p *Poloniex) OrderBook(pair string) (orderBook OrderBook, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("depth", "40")
	obt := OrderBookTemp{}
	err = p.public("returnOrderBook", params, &obt)
	if err != nil {
		return
	}
	orderBook = tempToOrderBook(obt)
	return
}

func (p *Poloniex) OrderBookAll() (orderBook OrderBookAll, err error) {
	params := url.Values{}
	params.Add("depth", "5")
	params.Add("currencyPair", "all")
	obt := OrderBookAllTemp{}
	err = p.public("returnOrderBook", params, &obt)
	if err != nil {
		return
	}
	orderBook = OrderBookAll{}
	for k, v := range obt {
		orderBook[k] = tempToOrderBook(v)
	}
	return
}

func (p *Poloniex) TradeHistory(in ...interface{}) (tradeHistory TradeHistory, err error) {
	params := url.Values{}
	params.Add("currencyPair", in[0].(string))
	if len(in) > 1 {
		// we have a start date
		params.Add("start", fmt.Sprintf("%d", in[1].(int64)))
	}
	if len(in) > 2 {
		// we have an end date
		params.Add("end", fmt.Sprintf("%d", in[2].(int64)))
	}
	err = p.public("returnTradeHistory", params, &tradeHistory)
	return
}

func (p *Poloniex) ChartData(pair string) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", time.Now().Add(-24*time.Hour).Unix()))
	params.Add("end", "9999999999")
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) ChartDataPeriod(pair string, start, end time.Time) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", start.Unix()))
	params.Add("end", fmt.Sprintf("%d", end.Unix()))
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) ChartDataCurrent(pair string) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", time.Now().Add(-5*time.Minute).Unix()))
	params.Add("end", "9999999999")
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) Currencies() (currencies Currencies, err error) {
	err = p.public("returnCurrencies", nil, &currencies)
	return
}

func (p *Poloniex) LoanOrders(currency string) (loanOrders LoanOrders, err error) {
	params := url.Values{}
	params.Add("currency", currency)
	err = p.public("returnLoanOrders", params, &loanOrders)
	return
}

func tempToOrderBook(obt OrderBookTemp) (ob OrderBook) {
	asks := obt.Asks
	bids := obt.Bids
	ob.IsFrozen = obt.IsFrozen.(string) != "0"
	ob.Asks = []Order{}
	ob.Bids = []Order{}
	for k := range asks {
		v := asks[k]
		price := ToDecimal(v[0])
		amount := ToDecimal(v[1])
		o := Order{Rate: price, Amount: amount}
		ob.Asks = append(ob.Asks, o)
	}
	for k := range bids {
		v := bids[k]
		price := ToDecimal(v[0])
		amount := ToDecimal(v[1])
		o := Order{Rate: price, Amount: amount}
		ob.Bids = append(ob.Bids, o)
	}
	return
}

func (p *Poloniex) public(command string, params url.Values, retval interface{}) (err error) {
	if p.debug {
		defer un(trace("public: " + command))
	}
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if params == nil {
		params = url.Values{}
	}
	params.Add("command", command)
	req := goreq.Request{Uri: PUBLICURI, QueryString: params, Timeout: 130 * time.Second}
	res, err := req.Do()
	if err != nil {
		return
	}
	if p.debug {
		pp.Println(res.Request.URL.String())
	}

	defer res.Body.Close()

	s, err := res.Body.ToString()
	if err != nil {
		return
	}
	if p.debug {
		pp.Println(s)
	}
	err = json.Unmarshal([]byte(s), retval)
	return
}
<commit_msg>added id to ticker<commit_after>package poloniex

import (
	"encoding/json"
	"fmt"
	"net/url"
	"time"

	"github.com/franela/goreq"
	"github.com/k0kubun/pp"
	"github.com/shopspring/decimal"
)

type (
	Ticker      map[string]TickerEntry
	TickerEntry struct {
		Last        decimal.Decimal `json:",string"`
		Ask         decimal.Decimal `json:"lowestAsk,string"`
		Bid         decimal.Decimal `json:"highestBid,string"`
		Change      decimal.Decimal `json:"percentChange,string"`
		BaseVolume  decimal.Decimal `json:"baseVolume,string"`
		QuoteVolume decimal.Decimal `json:"quoteVolume,string"`
		IsFrozen    int64           `json:"isFrozen,string"`
		ID          int64           `json:"id"`
	}

	DailyVolume          map[string]DailyVolumeEntry
	DailyVolumeEntry     map[string]decimal.Decimal
	DailyVolumeTemp      map[string]interface{}
	DailyVolumeEntryTemp map[string]interface{}

	OrderBook struct {
		Asks     []Order
		Bids     []Order
		IsFrozen bool
	}
	Order struct {
		Rate   decimal.Decimal
		Amount decimal.Decimal
	}

	OrderBookTemp struct {
		Asks     []OrderTemp
		Bids     []OrderTemp
		IsFrozen interface{}
	}
	OrderTemp        []interface{}
	OrderBookAll     map[string]OrderBook
	OrderBookAllTemp map[string]OrderBookTemp

	TradeHistory      []TradeHistoryEntry
	TradeHistoryEntry struct {
		ID     int64 `json:"globalTradeID"`
		Date   string
		Type   string
		Rate   decimal.Decimal `json:",string"`
		Amount decimal.Decimal `json:",string"`
		Total  decimal.Decimal `json:",string"`
	}

	ChartData      []ChartDataEntry
	ChartDataEntry struct {
		Date            int64
		High            decimal.Decimal
		Low             decimal.Decimal
		Open            decimal.Decimal
		Close           decimal.Decimal
		Volume          decimal.Decimal
		QuoteVolume     decimal.Decimal
		WeightedAverage decimal.Decimal
	}

	Currencies map[string]Currency
	Currency   struct {
		Name           string
		TxFee          decimal.Decimal `json:",string"`
		MinConf        decimal.Decimal
		DepositAddress string
		Disabled       int64
		Delisted       int64
		Frozen         int64
	}

	LoanOrders struct {
		Offers  []LoanOrder
		Demands []LoanOrder
	}
	LoanOrder struct {
		Rate     decimal.Decimal `json:",string"`
		Amount   decimal.Decimal `json:",string"`
		RangeMin decimal.Decimal
		RangeMax decimal.Decimal
	}
)

func (p *Poloniex) Ticker() (ticker Ticker, err error) {
	err = p.public("returnTicker", nil, &ticker)
	return
}

func (p *Poloniex) DailyVolume() (dailyVolume DailyVolume, err error) {
	dvt := DailyVolumeTemp{}
	err = p.public("return24hVolume", nil, &dvt)
	if err != nil {
		return
	}
	dailyVolume = DailyVolume{}
	for k := range dvt {
		v := dvt[k]
		dve := DailyVolumeEntry{}
		switch i := v.(type) {
		default:
			v := i.(map[string]interface{})
			for kk, vv := range v {
				dve[kk] = ToDecimal(vv)
			}
			dailyVolume[k] = dve
		case string:
			//ignore anything that isn't a map
		}
	}
	return
}

func (p *Poloniex) OrderBook(pair string) (orderBook OrderBook, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("depth", "40")
	obt := OrderBookTemp{}
	err = p.public("returnOrderBook", params, &obt)
	if err != nil {
		return
	}
	orderBook = tempToOrderBook(obt)
	return
}

func (p *Poloniex) OrderBookAll() (orderBook OrderBookAll, err error) {
	params := url.Values{}
	params.Add("depth", "5")
	params.Add("currencyPair", "all")
	obt := OrderBookAllTemp{}
	err = p.public("returnOrderBook", params, &obt)
	if err != nil {
		return
	}
	orderBook = OrderBookAll{}
	for k, v := range obt {
		orderBook[k] = tempToOrderBook(v)
	}
	return
}

func (p *Poloniex) TradeHistory(in ...interface{}) (tradeHistory TradeHistory, err error) {
	params := url.Values{}
	params.Add("currencyPair", in[0].(string))
	if len(in) > 1 {
		// we have a start date
		params.Add("start", fmt.Sprintf("%d", in[1].(int64)))
	}
	if len(in) > 2 {
		// we have an end date
		params.Add("end", fmt.Sprintf("%d", in[2].(int64)))
	}
	err = p.public("returnTradeHistory", params, &tradeHistory)
	return
}

func (p *Poloniex) ChartData(pair string) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", time.Now().Add(-24*time.Hour).Unix()))
	params.Add("end", "9999999999")
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) ChartDataPeriod(pair string, start, end time.Time) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", start.Unix()))
	params.Add("end", fmt.Sprintf("%d", end.Unix()))
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) ChartDataCurrent(pair string) (chartData ChartData, err error) {
	params := url.Values{}
	params.Add("currencyPair", pair)
	params.Add("start", fmt.Sprintf("%d", time.Now().Add(-5*time.Minute).Unix()))
	params.Add("end", "9999999999")
	params.Add("period", "300")
	err = p.public("returnChartData", params, &chartData)
	return
}

func (p *Poloniex) Currencies() (currencies Currencies, err error) {
	err = p.public("returnCurrencies", nil, &currencies)
	return
}

func (p *Poloniex) LoanOrders(currency string) (loanOrders LoanOrders, err error) {
	params := url.Values{}
	params.Add("currency", currency)
	err = p.public("returnLoanOrders", params, &loanOrders)
	return
}

func tempToOrderBook(obt OrderBookTemp) (ob OrderBook) {
	asks := obt.Asks
	bids := obt.Bids
	ob.IsFrozen = obt.IsFrozen.(string) != "0"
	ob.Asks = []Order{}
	ob.Bids = []Order{}
	for k := range asks {
		v := asks[k]
		price := ToDecimal(v[0])
		amount := ToDecimal(v[1])
		o := Order{Rate: price, Amount: amount}
		ob.Asks = append(ob.Asks, o)
	}
	for k := range bids {
		v := bids[k]
		price := ToDecimal(v[0])
		amount := ToDecimal(v[1])
		o := Order{Rate: price, Amount: amount}
		ob.Bids = append(ob.Bids, o)
	}
	return
}

func (p *Poloniex) public(command string, params url.Values, retval interface{}) (err error) {
	if p.debug {
		defer un(trace("public: " + command))
	}
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if params == nil {
		params = url.Values{}
	}
	params.Add("command", command)
	req := goreq.Request{Uri: PUBLICURI, QueryString: params, Timeout: 130 * time.Second}
	res, err := req.Do()
	if err != nil {
		return
	}
	if p.debug {
		pp.Println(res.Request.URL.String())
	}

	defer res.Body.Close()

	s, err := res.Body.ToString()
	if err != nil {
		return
	}
	if p.debug {
		pp.Println(s)
	}
	err = json.Unmarshal([]byte(s), retval)
	return
}
<|endoftext|>


<commit_before>package QesyDb

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB

type Model struct {
	Cond   interface{}
	Insert map[string]string
	Update map[string]string
	Field  string
	Table  string
	Index  string
	Limit  interface{}
	Sort   string
	IsDeug int
	Tx     *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(1800)
	sqlDb.SetMaxIdleConns(400)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	fmt.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + sort + limit + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return []map[string]string{}, err
	}
	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		return []map[string]string{}, err
	}

	fields, err := rows.Columns()
	if err != nil {
		return []map[string]string{}, err
	}
	var resultsSlice []map[string]string
	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return []map[string]string{}, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			}
			if isStrArr, ok := v.([]string); ok {
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			}
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return ""
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}
<commit_msg>update<commit_after>package QesyDb

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB

type Model struct {
	Cond   interface{}
	Insert map[string]string
	Update map[string]string
	Field  string
	Table  string
	Index  string
	Limit  interface{}
	Sort   string
	IsDeug int
	Tx     *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	//defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(1800)
	sqlDb.SetMaxIdleConns(400)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	fmt.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + sort + limit + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return []map[string]string{}, err
	}
	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		return []map[string]string{}, err
	}

	fields, err := rows.Columns()
	if err != nil {
		return []map[string]string{}, err
	}
	var resultsSlice []map[string]string
	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return []map[string]string{}, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	//defer stmt.Close()
	if err != nil {
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			}
			if isStrArr, ok := v.([]string); ok {
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			}
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return ""
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}
<|endoftext|>


<commit_before>package raygun

import (
	"errors"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/sditools/goraygun"
)

type raygunHook struct {
	client *goraygun.Client
}

func NewHook(Endpoint string, ApiKey string, Enabled bool) *raygunHook {
	client := goraygun.Init(goraygun.Settings{
		ApiKey:   ApiKey,
		Endpoint: Endpoint,
		Enabled:  Enabled,
	}, goraygun.Entry{})
	return &raygunHook{client}
}

func (hook *raygunHook) Fire(logEntry *logrus.Entry) error {
	// Start with a copy of the default entry
	raygunEntry := hook.client.Entry

	if request, ok := logEntry.Data["request"]; ok {
		raygunEntry.Details.Request.Populate(*(request.(*http.Request)))
	}

	var reportErr error
	if err, ok := logEntry.Data["error"]; ok {
		reportErr = err.(error)
	} else {
		reportErr = errors.New(logEntry.Message)
	}

	hook.client.Report(reportErr, raygunEntry)

	return nil
}

func (hook *raygunHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	}
}
<commit_msg>bugfix<commit_after>package raygun

import (
	"errors"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/sditools/goraygun"
)

type raygunHook struct {
	Client *goraygun.Client
}

func NewHook(Endpoint string, ApiKey string, Enabled bool) *raygunHook {
	client := goraygun.Init(goraygun.Settings{
		ApiKey:   ApiKey,
		Endpoint: Endpoint,
		Enabled:  Enabled,
	}, goraygun.Entry{})
	return &raygunHook{client}
}

func (hook *raygunHook) Fire(logEntry *logrus.Entry) error {
	// Start with a copy of the default entry
	raygunEntry := hook.Client.Entry

	if request, ok := logEntry.Data["request"]; ok {
		raygunEntry.Details.Request.Populate(*(request.(*http.Request)))
	}

	var reportErr error
	if err, ok := logEntry.Data["error"]; ok {
		reportErr = err.(error)
	} else {
		reportErr = errors.New(logEntry.Message)
	}

	hook.Client.Report(reportErr, raygunEntry)

	return nil
}

func (hook *raygunHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	}
}
<|endoftext|>


<commit_before>// Package handlers provides HTTP request handlers.
package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/thomaso-mirodin/go-shorten/storage"
)

func GetShortHandler(store storage.Storage) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		code := p.ByName("short")

		url, err := store.Load(code)
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(w, "URL Not Found.")
			return
		}

		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": code, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, url)
		default:
			http.Redirect(w, r, url, http.StatusFound)
		}
	}
}

func SetShortHandler(store storage.Storage) httprouter.Handle {
	named, namedOk := store.(storage.NamedStorage)
	unnamed, unnamedOk := store.(storage.UnnamedStorage)

	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		// Get URL from post params based on Content-Type
		var (
			url string
			code string
			err error
		)
		switch r.Header.Get("Content-Type") {
		case "application/json":
			http.Error(w, "{'error': 'Content-Type of application/json not yet supported'}", http.StatusNotImplemented)
		default:
			url = r.PostFormValue("url")
			if url == "" {
				http.Error(w, "No URL Provided", http.StatusBadRequest)
				return
			}

			code = r.PostFormValue("code")
			if code == "" {
				// Save URL to the storage layer and get the final short code
				code = p.ByName("short")
			}
		}

		if code == "" {
			if !unnamedOk {
				http.Error(w, "Current storage layer does not support storing an unnamed url", http.StatusBadRequest)
				return
			}

			code, err = unnamed.Save(url)
		} else {
			if !namedOk {
				http.Error(w, "Current storage layer does not support storing a named url", http.StatusBadRequest)
				return
			}

			err = named.SaveName(code, url)
		}
		if err != nil {
			http.Error(w, fmt.Sprintf("Storage layer failed to save link: %s", err), http.StatusInternalServerError)
		}

		// Return the short code formatted based on Accept headers
		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": code, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/html":
			w.Header().Set("Content-Type", "text/html; charset=utf-8")
			fmt.Fprintln(w, "<html>hello world</html")
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, code)
		default:
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, code)
		}
	}

}
<commit_msg>Handler not returning on error<commit_after>// Package handlers provides HTTP request handlers.
package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/thomaso-mirodin/go-shorten/storage"
)

func GetShortHandler(store storage.Storage) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		code := p.ByName("short")

		url, err := store.Load(code)
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(w, "URL Not Found.")
			return
		}

		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": code, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, url)
		default:
			http.Redirect(w, r, url, http.StatusFound)
		}
	}
}

func SetShortHandler(store storage.Storage) httprouter.Handle {
	named, namedOk := store.(storage.NamedStorage)
	unnamed, unnamedOk := store.(storage.UnnamedStorage)

	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		// Get URL from post params based on Content-Type
		var (
			url  string
			code string
			err  error
		)
		switch r.Header.Get("Content-Type") {
		case "application/json":
			http.Error(w, "{'error': 'Content-Type of application/json not yet supported'}", http.StatusNotImplemented)
		default:
			url = r.PostFormValue("url")
			if url == "" {
				http.Error(w, "No URL Provided", http.StatusBadRequest)
				return
			}

			code = r.PostFormValue("code")
			if code == "" {
				// Save URL to the storage layer and get the final short code
				code = p.ByName("short")
			}
		}

		if code == "" {
			if !unnamedOk {
				http.Error(w, "Current storage layer does not support storing an unnamed url", http.StatusBadRequest)
				return
			}

			code, err = unnamed.Save(url)
		} else {
			if !namedOk {
				http.Error(w, "Current storage layer does not support storing a named url", http.StatusBadRequest)
				return
			}

			err = named.SaveName(code, url)
		}
		if err != nil {
			http.Error(w, fmt.Sprintf("Storage layer failed to save '%s' to '%s' because: %s", url, code, err), http.StatusInternalServerError)
			return
		}

		// Return the short code formatted based on Accept headers
		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": code, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/html":
			w.Header().Set("Content-Type", "text/html; charset=utf-8")
			fmt.Fprintln(w, "<html>hello world</html")
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, code)
		default:
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, code)
		}
	}

}
<|endoftext|>


<commit_before>package scraper

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"sort"
	"time"

	"github.com/EVE-Tools/emdr-to-nsq/lib/emds"
	"github.com/EVE-Tools/market-streamer/lib/locations/citadels"
	"github.com/EVE-Tools/market-streamer/lib/locations/locationCache"
	"github.com/EVE-Tools/market-streamer/lib/marketTypes"
	"github.com/Sirupsen/logrus"
	"github.com/antihax/goesi"
	"github.com/antihax/goesi/v1"
	"github.com/klauspost/compress/zlib"
	"golang.org/x/net/context"
)

type esiOrder goesiv1.GetMarketsRegionIdOrders200Ok

var esiClient goesi.APIClient
var esiPublicContext context.Context

// Initialize initializes the scraper
func Initialize(clientID string, secretKey string, refreshToken string) {
	httpClient := &http.Client{
		Timeout: time.Duration(time.Second * 10),
	}

	// Requests to citadel's markets are authenticated - we're just using a default key for retrieving public markets
	esiAuthenticator := goesi.NewSSOAuthenticator(
		httpClient,
		clientID,
		secretKey,
		"eveauth-e43://market-streamer",
		[]string{"esi-universe.read_structures.v1",
			"esi-search.search_structures.v1",
			"esi-markets.structure_markets.v1"})

	// Build token source for auto-refreshing tokens
	token := &goesi.CRESTToken{
		AccessToken:  "",
		TokenType:    "Bearer",
		RefreshToken: refreshToken,
		Expiry:       time.Now().AddDate(0, 0, -1),
	}

	esiPublicToken, err := esiAuthenticator.TokenSource(token)
	if err != nil {
		log.Fatalf("Error starting bootstrap ESI client: %v", err)
	}

	esiPublicContext = context.WithValue(context.TODO(), goesi.ContextOAuth2, esiPublicToken)
	esiClient = *goesi.NewAPIClient(httpClient, "Element43/market-streamer (element-43.com)")
}

// ScrapeMarket gets a market from ESI and pushes it to supported backends
func ScrapeMarket(regionID int64) ([]byte, *time.Time, error) {
	// Prepare empty rowsets with all market types
	rowsets := generateRowsetsForRegion(regionID)

	//
	// Fetch public region Orders
	//
	// // First page -> re-schedule
	params := make(map[string]interface{})
	params["page"] = int32(1)

	esiOrdersRegion, response, err := esiClient.V1.MarketApi.GetMarketsRegionIdOrders("all", int32(regionID), params)
	if err != nil {
		return nil, nil, err
	}

	expiry, err := time.Parse(time.RFC1123, response.Header.Get("expires"))
	if err != nil {
		// Will run in 10 minutes, anyway
		logrus.WithError(err).Warn("Could not parse ESI expires timestamp!")
	}

	// Re-schedule self with 5 second safety margin
	runAgain := expiry.Add(time.Second * 5)

	// Add orders to rowset
	err = appendResponseRegion(rowsets, esiOrdersRegion, response)
	if err != nil {
		return nil, nil, err
	}

	// Fetch all other pages
	for len(esiOrdersRegion) > 0 {
		params["page"] = params["page"].(int32) + 1
		esiOrdersRegion, response, err = esiClient.V1.MarketApi.GetMarketsRegionIdOrders("all", int32(regionID), params)
		if err != nil {
			return nil, nil, err
		}

		// Add orders to rowset
		err = appendResponseRegion(rowsets, esiOrdersRegion, response)
		if err != nil {
			return nil, nil, err
		}
	}

	//
	// Fetch orders in citadels
	//
	citadelIDs := citadels.GetCitadelsInRegion(regionID)

	for _, citadelID := range citadelIDs {
		params["page"] = int32(1)
		esiOrdersCitadel, response, err := esiClient.V1.MarketApi.GetMarketsStructuresStructureId(esiPublicContext, citadelID, params)
		if err != nil {
			// Blacklist and skip these citadels
			if (response != nil) && (response.StatusCode == 403) {
				citadels.BlacklistCitadel(citadelID)
				continue
			}
			return nil, nil, err
		}

		// Add orders to rowset
		err = appendResponseCitadel(rowsets, esiOrdersCitadel, response)
		if err != nil {
			return nil, nil, err
		}

		// Fetch all other pages
		for len(esiOrdersCitadel) > 0 {
			params["page"] = params["page"].(int32) + 1
			esiOrdersCitadel, response, err = esiClient.V1.MarketApi.GetMarketsStructuresStructureId(esiPublicContext, citadelID, params)
			if err != nil {
				return nil, nil, err
			}

			// Add orders to rowset
			err = appendResponseCitadel(rowsets, esiOrdersCitadel, response)
			if err != nil {
				return nil, nil, err
			}
		}
	}

	// Set generatedAt, sort slices within rowsets and deduplicate orders
	for _, rowset := range rowsets {
		// Sort
		sort.Sort(emds.ByOrderID(rowset.Rows))

		if len(rowset.Rows) > 0 {
			rowset.GeneratedAt = rowset.Rows[0].GeneratedAt
		}

		// Dedup by ID
		inititalLength := len(rowset.Rows)
		deduplicated := rowset.Rows[:0]
		numRemoved := 0
		for index, row := range rowset.Rows {
			if index > 0 && (rowset.Rows[index-1].OrderID == row.OrderID) {
				numRemoved++
				logrus.WithField("order", fmt.Sprintf("%+v", rowset.Rows[index-1])).Debug("A: ")
				logrus.WithField("order", fmt.Sprintf("%+v", rowset.Rows[index])).Debug("B: ")
			} else {
				deduplicated = append(deduplicated, row)
			}
		}

		rowset.Rows = deduplicated

		if numRemoved > 0 {
			logrus.WithFields(logrus.Fields{
				"numDuplicates": numRemoved,
				"regionID":      rowset.RegionID,
				"typeID":        rowset.TypeID,
				"lengthBefore":  inititalLength,
				"lengthAfter":   len(rowset.Rows),
			}).Debug("Removed duplicate orders.")
		}
	}

	// Serialize rowsets
	rowsetSlice := make([]emds.Rowset, len(rowsets))
	rowsetIndex := 0
	numOrders := 0
	for _, rowset := range rowsets {
		numOrders += len(rowset.Rows)
		rowsetSlice[rowsetIndex] = *rowset
		rowsetIndex++
	}

	rowsetJSON, err := emds.RowsetsToUUDIF(rowsetSlice, "Element43/market-streamer", "0.1")
	if err != nil {
		return nil, nil, err
	}

	var compressedJSONBuffer bytes.Buffer
	compressionWriter := zlib.NewWriter(&compressedJSONBuffer)
	_, err = compressionWriter.Write(rowsetJSON)
	if err != nil {
		return nil, nil, err
	}

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

	compressedJSON := compressedJSONBuffer.Bytes()

	logrus.WithFields(logrus.Fields{
		"regionID":          regionID,
		"numOrders":         numOrders,
		"bytesUncompressed": len(rowsetJSON),
		"bytesCompressed":   len(compressedJSON),
	}).Info("Uploading market.")

	return compressedJSON, &runAgain, nil
}

// Type conversion for regions
func appendResponseRegion(rowsets map[int64]*emds.Rowset, regionOrders []goesiv1.GetMarketsRegionIdOrders200Ok, response *http.Response) error {
	var orders []esiOrder

	for _, regionOrder := range regionOrders {
		orders = append(orders, esiOrder(regionOrder))
	}

	return appendResponse(rowsets, orders, response)
}

// Type conversion for citadels
func appendResponseCitadel(rowsets map[int64]*emds.Rowset, citadelOrders []goesiv1.GetMarketsStructuresStructureId200Ok, response *http.Response) error {
	var orders []esiOrder

	for _, citadelOrder := range citadelOrders {
		orders = append(orders, esiOrder(citadelOrder))
	}

	return appendResponse(rowsets, orders, response)
}

func appendResponse(rowsets map[int64]*emds.Rowset, esiOrders []esiOrder, response *http.Response) error {
	lastModified, err := time.Parse(time.RFC1123, response.Header.Get("last-modified"))
	if err != nil {
		// Default to now
		logrus.WithError(err).Warn("Could not parse ESI last-modified timestamp!")
		lastModified = time.Now()
	}

	generatedAt := lastModified.Format(time.RFC3339)

	return appendOrders(rowsets, esiOrders, generatedAt)
}

func appendOrders(rowsets map[int64]*emds.Rowset, esiOrders []esiOrder, generatedAt string) error {
	// Collect locations
	var locationIDs []int64
	for _, order := range esiOrders {
		locationIDs = append(locationIDs, order.LocationId)
	}

	locations, err := locationCache.GetLocations(locationIDs)
	if err != nil {
		return err
	}

	// Add orders including location info
	for _, order := range esiOrders {
		if location, ok := locations[order.LocationId]; ok {
			typeID := int64(order.TypeId)

			orderRange, err := emds.ConvertRange(order.Range_)
			if err != nil {
				logrus.WithError(err).Error("Could not parse range! Skipping order.")
				continue
			}

			// Create rowset for types which should not be there
			if _, ok := rowsets[typeID]; !ok {
				logrus.WithField("typeID", typeID).WithField("order", fmt.Sprintf("%+v", order)).Debug("Type not in marketTypes but in orders!")

				rowsets[typeID] = &emds.Rowset{
					GeneratedAt: generatedAt,
					RegionID:    location.Region.ID,
					TypeID:      typeID,
				}
			}

			rowset := rowsets[typeID]
			rowset.Rows = append(rowset.Rows, emds.Order{
				OrderID:       order.OrderId,
				RegionID:      rowset.RegionID,
				TypeID:        int64(order.TypeId),
				GeneratedAt:   generatedAt,
				Price:         float64(order.Price),
				VolRemaining:  int64(order.VolumeRemain),
				OrderRange:    orderRange,
				VolEntered:    int64(order.VolumeTotal),
				MinVolume:     int64(order.MinVolume),
				Bid:           order.IsBuyOrder,
				IssueDate:     order.Issued.Format(time.RFC3339),
				Duration:      int64(order.Duration),
				StationID:     order.LocationId,
				SolarSystemID: location.SolarSystem.ID,
			})

		} else {
			logrus.WithField("locationID", order.LocationId).Warn("Unknown location.")
		}
	}

	return nil
}

// Generates empty rowsets for population by scraper
func generateRowsetsForRegion(regionID int64) map[int64]*emds.Rowset {
	rowsets := map[int64]*emds.Rowset{}
	now := time.Now().Format(time.RFC3339)
	types := marketTypes.GetMarketTypes()

	for _, typeID := range types {
		rowsets[typeID] = &emds.Rowset{
			GeneratedAt: now,
			RegionID:    regionID,
			TypeID:      typeID,
		}
	}

	return rowsets
}
<commit_msg>Switch scraper to fork, too<commit_after>package scraper

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"sort"
	"time"

	"github.com/EVE-Tools/emdr-to-nsq/lib/emds"
	"github.com/EVE-Tools/goesi"
	"github.com/EVE-Tools/goesi/v1"
	"github.com/EVE-Tools/market-streamer/lib/locations/citadels"
	"github.com/EVE-Tools/market-streamer/lib/locations/locationCache"
	"github.com/EVE-Tools/market-streamer/lib/marketTypes"
	"github.com/Sirupsen/logrus"
	"github.com/klauspost/compress/zlib"
	"golang.org/x/net/context"
)

type esiOrder goesiv1.GetMarketsRegionIdOrders200Ok

var esiClient goesi.APIClient
var esiPublicContext context.Context

// Initialize initializes the scraper
func Initialize(clientID string, secretKey string, refreshToken string) {
	httpClient := &http.Client{
		Timeout: time.Duration(time.Second * 10),
	}

	// Requests to citadel's markets are authenticated - we're just using a default key for retrieving public markets
	esiAuthenticator := goesi.NewSSOAuthenticator(
		httpClient,
		clientID,
		secretKey,
		"eveauth-e43://market-streamer",
		[]string{"esi-universe.read_structures.v1",
			"esi-search.search_structures.v1",
			"esi-markets.structure_markets.v1"})

	// Build token source for auto-refreshing tokens
	token := &goesi.CRESTToken{
		AccessToken:  "",
		TokenType:    "Bearer",
		RefreshToken: refreshToken,
		Expiry:       time.Now().AddDate(0, 0, -1),
	}

	esiPublicToken, err := esiAuthenticator.TokenSource(token)
	if err != nil {
		log.Fatalf("Error starting bootstrap ESI client: %v", err)
	}

	esiPublicContext = context.WithValue(context.TODO(), goesi.ContextOAuth2, esiPublicToken)
	esiClient = *goesi.NewAPIClient(httpClient, "Element43/market-streamer (element-43.com)")
}

// ScrapeMarket gets a market from ESI and pushes it to supported backends
func ScrapeMarket(regionID int64) ([]byte, *time.Time, error) {
	// Prepare empty rowsets with all market types
	rowsets := generateRowsetsForRegion(regionID)

	//
	// Fetch public region Orders
	//
	// // First page -> re-schedule
	params := make(map[string]interface{})
	params["page"] = int32(1)

	esiOrdersRegion, response, err := esiClient.V1.MarketApi.GetMarketsRegionIdOrders("all", int32(regionID), params)
	if err != nil {
		return nil, nil, err
	}

	expiry, err := time.Parse(time.RFC1123, response.Header.Get("expires"))
	if err != nil {
		// Will run in 10 minutes, anyway
		logrus.WithError(err).Warn("Could not parse ESI expires timestamp!")
	}

	// Re-schedule self with 5 second safety margin
	runAgain := expiry.Add(time.Second * 5)

	// Add orders to rowset
	err = appendResponseRegion(rowsets, esiOrdersRegion, response)
	if err != nil {
		return nil, nil, err
	}

	// Fetch all other pages
	for len(esiOrdersRegion) > 0 {
		params["page"] = params["page"].(int32) + 1
		esiOrdersRegion, response, err = esiClient.V1.MarketApi.GetMarketsRegionIdOrders("all", int32(regionID), params)
		if err != nil {
			return nil, nil, err
		}

		// Add orders to rowset
		err = appendResponseRegion(rowsets, esiOrdersRegion, response)
		if err != nil {
			return nil, nil, err
		}
	}

	//
	// Fetch orders in citadels
	//
	citadelIDs := citadels.GetCitadelsInRegion(regionID)

	for _, citadelID := range citadelIDs {
		params["page"] = int32(1)
		esiOrdersCitadel, response, err := esiClient.V1.MarketApi.GetMarketsStructuresStructureId(esiPublicContext, citadelID, params)
		if err != nil {
			// Blacklist and skip these citadels
			if (response != nil) && (response.StatusCode == 403) {
				citadels.BlacklistCitadel(citadelID)
				continue
			}
			return nil, nil, err
		}

		// Add orders to rowset
		err = appendResponseCitadel(rowsets, esiOrdersCitadel, response)
		if err != nil {
			return nil, nil, err
		}

		// Fetch all other pages
		for len(esiOrdersCitadel) > 0 {
			params["page"] = params["page"].(int32) + 1
			esiOrdersCitadel, response, err = esiClient.V1.MarketApi.GetMarketsStructuresStructureId(esiPublicContext, citadelID, params)
			if err != nil {
				return nil, nil, err
			}

			// Add orders to rowset
			err = appendResponseCitadel(rowsets, esiOrdersCitadel, response)
			if err != nil {
				return nil, nil, err
			}
		}
	}

	// Set generatedAt, sort slices within rowsets and deduplicate orders
	for _, rowset := range rowsets {
		// Sort
		sort.Sort(emds.ByOrderID(rowset.Rows))

		if len(rowset.Rows) > 0 {
			rowset.GeneratedAt = rowset.Rows[0].GeneratedAt
		}

		// Dedup by ID
		inititalLength := len(rowset.Rows)
		deduplicated := rowset.Rows[:0]
		numRemoved := 0
		for index, row := range rowset.Rows {
			if index > 0 && (rowset.Rows[index-1].OrderID == row.OrderID) {
				numRemoved++
				logrus.WithField("order", fmt.Sprintf("%+v", rowset.Rows[index-1])).Debug("A: ")
				logrus.WithField("order", fmt.Sprintf("%+v", rowset.Rows[index])).Debug("B: ")
			} else {
				deduplicated = append(deduplicated, row)
			}
		}

		rowset.Rows = deduplicated

		if numRemoved > 0 {
			logrus.WithFields(logrus.Fields{
				"numDuplicates": numRemoved,
				"regionID":      rowset.RegionID,
				"typeID":        rowset.TypeID,
				"lengthBefore":  inititalLength,
				"lengthAfter":   len(rowset.Rows),
			}).Debug("Removed duplicate orders.")
		}
	}

	// Serialize rowsets
	rowsetSlice := make([]emds.Rowset, len(rowsets))
	rowsetIndex := 0
	numOrders := 0
	for _, rowset := range rowsets {
		numOrders += len(rowset.Rows)
		rowsetSlice[rowsetIndex] = *rowset
		rowsetIndex++
	}

	rowsetJSON, err := emds.RowsetsToUUDIF(rowsetSlice, "Element43/market-streamer", "0.1")
	if err != nil {
		return nil, nil, err
	}

	var compressedJSONBuffer bytes.Buffer
	compressionWriter := zlib.NewWriter(&compressedJSONBuffer)
	_, err = compressionWriter.Write(rowsetJSON)
	if err != nil {
		return nil, nil, err
	}

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

	compressedJSON := compressedJSONBuffer.Bytes()

	logrus.WithFields(logrus.Fields{
		"regionID":          regionID,
		"numOrders":         numOrders,
		"bytesUncompressed": len(rowsetJSON),
		"bytesCompressed":   len(compressedJSON),
	}).Info("Uploading market.")

	return compressedJSON, &runAgain, nil
}

// Type conversion for regions
func appendResponseRegion(rowsets map[int64]*emds.Rowset, regionOrders []goesiv1.GetMarketsRegionIdOrders200Ok, response *http.Response) error {
	var orders []esiOrder

	for _, regionOrder := range regionOrders {
		orders = append(orders, esiOrder(regionOrder))
	}

	return appendResponse(rowsets, orders, response)
}

// Type conversion for citadels
func appendResponseCitadel(rowsets map[int64]*emds.Rowset, citadelOrders []goesiv1.GetMarketsStructuresStructureId200Ok, response *http.Response) error {
	var orders []esiOrder

	for _, citadelOrder := range citadelOrders {
		orders = append(orders, esiOrder(citadelOrder))
	}

	return appendResponse(rowsets, orders, response)
}

func appendResponse(rowsets map[int64]*emds.Rowset, esiOrders []esiOrder, response *http.Response) error {
	lastModified, err := time.Parse(time.RFC1123, response.Header.Get("last-modified"))
	if err != nil {
		// Default to now
		logrus.WithError(err).Warn("Could not parse ESI last-modified timestamp!")
		lastModified = time.Now()
	}

	generatedAt := lastModified.Format(time.RFC3339)

	return appendOrders(rowsets, esiOrders, generatedAt)
}

func appendOrders(rowsets map[int64]*emds.Rowset, esiOrders []esiOrder, generatedAt string) error {
	// Collect locations
	var locationIDs []int64
	for _, order := range esiOrders {
		locationIDs = append(locationIDs, order.LocationId)
	}

	locations, err := locationCache.GetLocations(locationIDs)
	if err != nil {
		return err
	}

	// Add orders including location info
	for _, order := range esiOrders {
		if location, ok := locations[order.LocationId]; ok {
			typeID := int64(order.TypeId)

			orderRange, err := emds.ConvertRange(order.Range_)
			if err != nil {
				logrus.WithError(err).Error("Could not parse range! Skipping order.")
				continue
			}

			// Create rowset for types which should not be there
			if _, ok := rowsets[typeID]; !ok {
				logrus.WithField("typeID", typeID).WithField("order", fmt.Sprintf("%+v", order)).Debug("Type not in marketTypes but in orders!")

				rowsets[typeID] = &emds.Rowset{
					GeneratedAt: generatedAt,
					RegionID:    location.Region.ID,
					TypeID:      typeID,
				}
			}

			rowset := rowsets[typeID]
			rowset.Rows = append(rowset.Rows, emds.Order{
				OrderID:       order.OrderId,
				RegionID:      rowset.RegionID,
				TypeID:        int64(order.TypeId),
				GeneratedAt:   generatedAt,
				Price:         float64(order.Price),
				VolRemaining:  int64(order.VolumeRemain),
				OrderRange:    orderRange,
				VolEntered:    int64(order.VolumeTotal),
				MinVolume:     int64(order.MinVolume),
				Bid:           order.IsBuyOrder,
				IssueDate:     order.Issued.Format(time.RFC3339),
				Duration:      int64(order.Duration),
				StationID:     order.LocationId,
				SolarSystemID: location.SolarSystem.ID,
			})

		} else {
			logrus.WithField("locationID", order.LocationId).Warn("Unknown location.")
		}
	}

	return nil
}

// Generates empty rowsets for population by scraper
func generateRowsetsForRegion(regionID int64) map[int64]*emds.Rowset {
	rowsets := map[int64]*emds.Rowset{}
	now := time.Now().Format(time.RFC3339)
	types := marketTypes.GetMarketTypes()

	for _, typeID := range types {
		rowsets[typeID] = &emds.Rowset{
			GeneratedAt: now,
			RegionID:    regionID,
			TypeID:      typeID,
		}
	}

	return rowsets
}
<|endoftext|>


<commit_before>// +build noos

package syscall

import (
	"internal"
	"sync/atomic"
	"sync/fence"
	"unsafe"
)

// Event bitmask that represents events that multiple tasks or ISRs can send
// and multiple tasks (but not ISRs) can wait for. Events are intended to be
// used by low-level library rutines to implement higher level communication and
// synchronization primitives like channels and mutexes. They are specific to
// noos runtime so can be unavailable if RTOS is used.
type Event uintptr

const eventBits = uintptr(unsafe.Sizeof(Event(0)) * 8)

var (
	eventReg Event
	gen      uintptr
)

// AssignEvent returns event from some internal event pool.
// There is no any guarantee that subsequent calls of AssignEvent assigns
// different events, which means that AssignEvent can return Event already
// assigned by current or another task.
func AssignEvent() Event {
	u := atomic.AddUintptr(&gen, 1)
	return Event(1) << (u & (eventBits - 1))
}

// AssignEventFlag works like AssignEvent but guarantees that the least
// significant bit of returned value is zero.
func AssignEventFlag() Event {
	u := atomic.AddUintptr(&gen, 1)
	return Event(2) << (u % (eventBits - 1))
}

// Send sends event that means it waking up all tasks that wait for e. If some
// task isn't waiting for any event, e is saved for this task for possible
// future call of Wait. Send do not execute until all normal (not I/O) memory
// write operations before it, in program order, will be completed. In very
// simple implementation Send can do nothing.
func (e Event) Send() {
	fence.W_SMP() // Send signals that some shared variable was changed.
	atomic.OrUintptr((*uintptr)(&eventReg), uintptr(e))
	schedNext()
}

// TakeEventReg is intended tao be used by runtime to obtain accumulated events.
// It returns value of shared event register and clears it in one atomic
// operation.
func TakeEventReg() Event {
	return Event(atomic.SwapUintptr((*uintptr)(&eventReg), 0))
}

// Wait waits for event. If e == 0 it returns immediately. Wait clears all saved
// events for current task so the information about recieved events, that Wait
// hasn't waited for, is lost. Wait ensures that any normal (not I/O) memory
// operation after it, in program order, do not be executed until Wait return.
// In very simple implementation Wait can do nothing and always return
// immediatelly.
func (e Event) Wait() {
	internal.Syscall1(EVENTWAIT, uintptr(e))
}

// Assign Allarm event. Event(1) seems to be good choise for such ubiquitous
// event: it is always different from events returned by AssignEventFlag and
// different from the first 31 events assigned by AssignFlag.

// Alarm is an event that is sent by runtime when asked by using SetAlarm.
var Alarm = Event(1)

func AtomicLoadEvent(p *Event) Event {
	return Event(atomic.LoadUintptr((*uintptr)(p)))
}

func AtomicStoreEvent(p *Event, e Event) {
	atomic.StoreUintptr((*uintptr)(p), uintptr(e))
}

func AtomicAddEvent(p *Event, delta int) Event {
	return Event(atomic.AddUintptr((*uintptr)(p), uintptr(delta)))
}

func AtomicCompareAndSwapEvent(p *Event, old, new Event) bool {
	return atomic.CompareAndSwapUintptr(
		(*uintptr)(p), uintptr(old), uintptr(new),
	)
}
<commit_msg>syscall: Fix typos in Event comments.<commit_after>// +build noos

package syscall

import (
	"internal"
	"sync/atomic"
	"sync/fence"
	"unsafe"
)

// Event is bitmask that represents events that multiple tasks or ISRs can send
// and multiple tasks (but not ISRs) can wait for. Events are intended to be
// used by low-level library rutines to implement higher level communication and
// synchronization primitives like channels and mutexes. They are specific to
// noos runtime so can be unavailable if RTOS is used.
type Event uintptr

const eventBits = uintptr(unsafe.Sizeof(Event(0)) * 8)

var (
	eventReg Event
	gen      uintptr
)

// AssignEvent returns event from some internal event pool.
// There is no any guarantee that subsequent calls of AssignEvent assigns
// different events, which means that AssignEvent can return Event already
// assigned by current or another task.
func AssignEvent() Event {
	u := atomic.AddUintptr(&gen, 1)
	return Event(1) << (u & (eventBits - 1))
}

// AssignEventFlag works like AssignEvent but guarantees that the least
// significant bit of returned value is zero.
func AssignEventFlag() Event {
	u := atomic.AddUintptr(&gen, 1)
	return Event(2) << (u % (eventBits - 1))
}

// Send sends event that means it waking up all tasks that wait for e. If some
// task isn't waiting for any event, e is saved for this task for possible
// future call of Wait. Send do not execute until all normal (not I/O) memory
// write operations before it, in program order, will be completed. In very
// simple implementation Send can do nothing.
func (e Event) Send() {
	fence.W_SMP() // Send signals that some shared variable was changed.
	atomic.OrUintptr((*uintptr)(&eventReg), uintptr(e))
	schedNext()
}

// TakeEventReg is intended to be used by runtime to obtain accumulated events.
// It returns value of shared event register and clears it in one atomic
// operation.
func TakeEventReg() Event {
	return Event(atomic.SwapUintptr((*uintptr)(&eventReg), 0))
}

// Wait waits for event. If e == 0 it returns immediately. Wait clears all saved
// events for current task so the information about recieved events, that Wait
// hasn't waited for, is lost. Wait ensures that any normal (not I/O) memory
// operation after it, in program order, do not be executed until Wait return.
// In very simple implementation Wait can do nothing and always return
// immediatelly.
func (e Event) Wait() {
	internal.Syscall1(EVENTWAIT, uintptr(e))
}

// Assign Allarm event. Event(1) seems to be good choise for such ubiquitous
// event: it is always different from events returned by AssignEventFlag and
// different from the first 31 events assigned by AssignEvent.

// Alarm is an event that is sent by runtime when asked by using SetAlarm.
var Alarm = Event(1)

func AtomicLoadEvent(p *Event) Event {
	return Event(atomic.LoadUintptr((*uintptr)(p)))
}

func AtomicStoreEvent(p *Event, e Event) {
	atomic.StoreUintptr((*uintptr)(p), uintptr(e))
}

func AtomicAddEvent(p *Event, delta int) Event {
	return Event(atomic.AddUintptr((*uintptr)(p), uintptr(delta)))
}

func AtomicCompareAndSwapEvent(p *Event, old, new Event) bool {
	return atomic.CompareAndSwapUintptr(
		(*uintptr)(p), uintptr(old), uintptr(new),
	)
}
<|endoftext|>


<commit_before>package b

import (
	"io"
	"log"

	"github.com/pilosa/pilosa/roaring"
)

func cmp(a, b uint64) int {
	return int(a - b)
}

type BTreeContainers struct {
	tree *Tree

	lastKey       uint64
	lastContainer *roaring.Container
}

func NewBTreeContainers() *BTreeContainers {
	return &BTreeContainers{
		tree: TreeNew(cmp),
	}
}

func NewBTreeBitmap(a ...uint64) *roaring.Bitmap {
	log.Println("btree bitmap")
	b := &roaring.Bitmap{
		Containers: NewBTreeContainers(),
	}
	b.Add(a...)
	return b
}

func (btc *BTreeContainers) Get(key uint64) *roaring.Container {
	// Check the last* cache for same container.
	if key == btc.lastKey && btc.lastContainer != nil {
		return btc.lastContainer
	}

	var c *roaring.Container
	el, ok := btc.tree.Get(key)
	if ok {
		c = el
		btc.lastKey = key
		btc.lastContainer = c
	}
	return c
}

func (btc *BTreeContainers) Put(key uint64, c *roaring.Container) {
	// If a mapped container is added to the tree, reset the
	// lastContainer cache so that the cache is not pointing
	// at a read-only mmap.
	if c.Mapped() {
		btc.lastContainer = nil
	}
	btc.tree.Set(key, c)
}

func (u updater) update(oldV *roaring.Container, exists bool) (*roaring.Container, bool) {
	// update the existing container
	if exists {
		oldV.Update(u.containerType, u.n, u.mapped)
		return oldV, false
	}
	cont := roaring.NewContainer()
	cont.Update(u.containerType, u.n, u.mapped)
	return cont, true
}

// this struct is added to prevent the closure locals from being escaped out to the heap
type updater struct {
	key           uint64
	containerType byte
	n             int
	mapped        bool
}

func (btc *BTreeContainers) PutContainerValues(key uint64, containerType byte, n int, mapped bool) {
	a := updater{key, containerType, n, mapped}
	btc.tree.Put(key, a.update)
}

func (btc *BTreeContainers) Remove(key uint64) {
	btc.tree.Delete(key)
}

func (btc *BTreeContainers) GetOrCreate(key uint64) *roaring.Container {
	// Check the last* cache for same container.
	if key == btc.lastKey && btc.lastContainer != nil {
		return btc.lastContainer
	}

	btc.lastKey = key
	v, ok := btc.tree.Get(key)
	if !ok {
		cont := roaring.NewContainer()
		btc.tree.Set(key, cont)
		btc.lastContainer = cont
		return cont
	}

	btc.lastContainer = v
	return btc.lastContainer
}

func (btc *BTreeContainers) Clone() roaring.Containers {
	nbtc := NewBTreeContainers()

	itr, err := btc.tree.SeekFirst()
	if err == io.EOF {
		return nbtc
	}
	for {
		k, v, err := itr.Next()
		if err == io.EOF {
			break
		}
		nbtc.tree.Set(k, v.Clone())
	}
	return nbtc
}

func (btc *BTreeContainers) Last() (key uint64, c *roaring.Container) {
	if btc.tree.Len() == 0 {
		return 0, nil
	}
	k, v := btc.tree.Last()
	return k, v
}

func (btc *BTreeContainers) Size() int {
	return btc.tree.Len()
}

func (btc *BTreeContainers) Iterator(key uint64) (citer roaring.Contiterator, found bool) {
	e, ok := btc.tree.Seek(key)
	if ok {
		found = true
	}

	return &BTCIterator{
		e: e,
	}, found
}

type BTCIterator struct {
	e   *Enumerator
	key uint64
	val *roaring.Container
}

func (i *BTCIterator) Next() bool {

	k, v, err := i.e.Next()
	if err == io.EOF {
		return false
	}
	i.key = k
	i.val = v
	return true
}

func (i *BTCIterator) Value() (uint64, *roaring.Container) {
	if i.val == nil {
		return 0, nil
	}
	return i.key, i.val
}
<commit_msg>Remove leftover debug log line<commit_after>package b

import (
	"io"

	"github.com/pilosa/pilosa/roaring"
)

func cmp(a, b uint64) int {
	return int(a - b)
}

type BTreeContainers struct {
	tree *Tree

	lastKey       uint64
	lastContainer *roaring.Container
}

func NewBTreeContainers() *BTreeContainers {
	return &BTreeContainers{
		tree: TreeNew(cmp),
	}
}

func NewBTreeBitmap(a ...uint64) *roaring.Bitmap {
	b := &roaring.Bitmap{
		Containers: NewBTreeContainers(),
	}
	b.Add(a...)
	return b
}

func (btc *BTreeContainers) Get(key uint64) *roaring.Container {
	// Check the last* cache for same container.
	if key == btc.lastKey && btc.lastContainer != nil {
		return btc.lastContainer
	}

	var c *roaring.Container
	el, ok := btc.tree.Get(key)
	if ok {
		c = el
		btc.lastKey = key
		btc.lastContainer = c
	}
	return c
}

func (btc *BTreeContainers) Put(key uint64, c *roaring.Container) {
	// If a mapped container is added to the tree, reset the
	// lastContainer cache so that the cache is not pointing
	// at a read-only mmap.
	if c.Mapped() {
		btc.lastContainer = nil
	}
	btc.tree.Set(key, c)
}

func (u updater) update(oldV *roaring.Container, exists bool) (*roaring.Container, bool) {
	// update the existing container
	if exists {
		oldV.Update(u.containerType, u.n, u.mapped)
		return oldV, false
	}
	cont := roaring.NewContainer()
	cont.Update(u.containerType, u.n, u.mapped)
	return cont, true
}

// this struct is added to prevent the closure locals from being escaped out to the heap
type updater struct {
	key           uint64
	containerType byte
	n             int
	mapped        bool
}

func (btc *BTreeContainers) PutContainerValues(key uint64, containerType byte, n int, mapped bool) {
	a := updater{key, containerType, n, mapped}
	btc.tree.Put(key, a.update)
}

func (btc *BTreeContainers) Remove(key uint64) {
	btc.tree.Delete(key)
}

func (btc *BTreeContainers) GetOrCreate(key uint64) *roaring.Container {
	// Check the last* cache for same container.
	if key == btc.lastKey && btc.lastContainer != nil {
		return btc.lastContainer
	}

	btc.lastKey = key
	v, ok := btc.tree.Get(key)
	if !ok {
		cont := roaring.NewContainer()
		btc.tree.Set(key, cont)
		btc.lastContainer = cont
		return cont
	}

	btc.lastContainer = v
	return btc.lastContainer
}

func (btc *BTreeContainers) Clone() roaring.Containers {
	nbtc := NewBTreeContainers()

	itr, err := btc.tree.SeekFirst()
	if err == io.EOF {
		return nbtc
	}
	for {
		k, v, err := itr.Next()
		if err == io.EOF {
			break
		}
		nbtc.tree.Set(k, v.Clone())
	}
	return nbtc
}

func (btc *BTreeContainers) Last() (key uint64, c *roaring.Container) {
	if btc.tree.Len() == 0 {
		return 0, nil
	}
	k, v := btc.tree.Last()
	return k, v
}

func (btc *BTreeContainers) Size() int {
	return btc.tree.Len()
}

func (btc *BTreeContainers) Iterator(key uint64) (citer roaring.Contiterator, found bool) {
	e, ok := btc.tree.Seek(key)
	if ok {
		found = true
	}

	return &BTCIterator{
		e: e,
	}, found
}

type BTCIterator struct {
	e   *Enumerator
	key uint64
	val *roaring.Container
}

func (i *BTCIterator) Next() bool {

	k, v, err := i.e.Next()
	if err == io.EOF {
		return false
	}
	i.key = k
	i.val = v
	return true
}

func (i *BTCIterator) Value() (uint64, *roaring.Container) {
	if i.val == nil {
		return 0, nil
	}
	return i.key, i.val
}
<|endoftext|>


<commit_before>package concurrency

import (
	"sync"

	"golang.org/x/net/context"
)

// PlusOne returns a channel of num + 1 for nums received from in.
func PlusOne(ctx context.Context, in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		defer close(out)
		for num := range in {
			select {
			case out <- num + 1:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

type IntPipe func(context.Context, <-chan int) <-chan int

func Chain(ps ...IntPipe) IntPipe {
	return func(ctx context.Context, in <-chan int) <-chan int {
		c := in
		for _, p := range ps {
			c = p(ctx, c)
		}
		return c
	}
}

var PlusTwo = Chain(PlusOne, PlusOne)

func FanIn(ins ...<-chan int) <-chan int {
	out := make(chan int)
	var wg sync.WaitGroup
	wg.Add(len(ins))
	for _, in := range ins {
		go func(in <-chan int) {
			defer wg.Done()
			for num := range in {
				out <- num
			}
		}(in)
	}
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

func Distribute(p IntPipe, n int) IntPipe {
	return func(ctx context.Context, in <-chan int) <-chan int {
		cs := make([]<-chan int, n)
		for i := 0; i < n; i++ {
			cs[i] = p(ctx, in)
		}
		return FanIn(cs...)
	}
}

func FanIn3(in1, in2, in3 <-chan int) <-chan int {
	out := make(chan int)
	openCnt := 3
	closeChan := func(c *<-chan int) bool {
		*c = nil
		openCnt--
		return openCnt == 0
	}
	go func() {
		defer close(out)
		for {
			select {
			case n, ok := <-in1:
				if ok {
					out <- n
				} else if closeChan(&in1) {
					return
				}
			case n, ok := <-in2:
				if ok {
					out <- n
				} else if closeChan(&in2) {
					return
				}
			case n, ok := <-in3:
				if ok {
					out <- n
				} else if closeChan(&in3) {
					return
				}
			}
		}
	}()
	return out

}
<commit_msg>Context library is a standard library.<commit_after>package concurrency

import (
	"context"
	"sync"
)

// PlusOne returns a channel of num + 1 for nums received from in.
func PlusOne(ctx context.Context, in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		defer close(out)
		for num := range in {
			select {
			case out <- num + 1:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

type IntPipe func(context.Context, <-chan int) <-chan int

func Chain(ps ...IntPipe) IntPipe {
	return func(ctx context.Context, in <-chan int) <-chan int {
		c := in
		for _, p := range ps {
			c = p(ctx, c)
		}
		return c
	}
}

var PlusTwo = Chain(PlusOne, PlusOne)

func FanIn(ins ...<-chan int) <-chan int {
	out := make(chan int)
	var wg sync.WaitGroup
	wg.Add(len(ins))
	for _, in := range ins {
		go func(in <-chan int) {
			defer wg.Done()
			for num := range in {
				out <- num
			}
		}(in)
	}
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

func Distribute(p IntPipe, n int) IntPipe {
	return func(ctx context.Context, in <-chan int) <-chan int {
		cs := make([]<-chan int, n)
		for i := 0; i < n; i++ {
			cs[i] = p(ctx, in)
		}
		return FanIn(cs...)
	}
}

func FanIn3(in1, in2, in3 <-chan int) <-chan int {
	out := make(chan int)
	openCnt := 3
	closeChan := func(c *<-chan int) bool {
		*c = nil
		openCnt--
		return openCnt == 0
	}
	go func() {
		defer close(out)
		for {
			select {
			case n, ok := <-in1:
				if ok {
					out <- n
				} else if closeChan(&in1) {
					return
				}
			case n, ok := <-in2:
				if ok {
					out <- n
				} else if closeChan(&in2) {
					return
				}
			case n, ok := <-in3:
				if ok {
					out <- n
				} else if closeChan(&in3) {
					return
				}
			}
		}
	}()
	return out

}
<|endoftext|>


<commit_before>package scene

import (
	"image"
	"image/color"

	"github.com/pankona/gomo-simra/examples/sample3/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

type gameState int

const (
	readyToStart gameState = iota
	started
	readyToRestart
)

// Stage1 represents scene of Stage1.
type Stage1 struct {
	models        models
	views         views
	ball          Ball
	obstacle      [2]Obstacle
	background    [2]Background
	isTouching    bool
	remainingLife int
	life          [3]Life
	gameovertext  [2]simra.Sprite
	gamestate     gameState
}

// Life represents view part of remaining life
type Life struct {
	simra.Sprite
}

func (life *Life) getPosition() (x float32, y float32) {
	x, y = life.X, life.Y
	return
}

func (life *Life) setPosition(x float32, y float32) {
	life.X, life.Y = x, y
}

func (life *Life) setSpeed(s float64) {
}

func (life *Life) getSpeed() float64 {
	return 0
}

func (life *Life) setDirection(radian float64) {
}
func (life *Life) getDirection() float64 {
	return 0
}

func (life *Life) move() {
}

const (
	remainingLifeAtStart = 3
)

// Initialize initializes Stage1 scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (scene *Stage1) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// add global touch listener to catch touch end event
	simra.GetInstance().AddTouchListener(scene)

	// TODO: when goes to next scene, remove global touch listener
	// simra.GetInstance().RemoveTouchListener(Stage1)

	scene.resetPosition()
	scene.setupSprites()
	scene.registerViews()
	scene.registerModels()
	scene.remainingLife = remainingLifeAtStart

	simra.GetInstance().AddCollisionListener(&scene.ball, &scene.obstacle[0], &scene.models)
	simra.GetInstance().AddCollisionListener(&scene.ball, &scene.obstacle[1], &scene.models)

	scene.gamestate = readyToStart

	simra.LogDebug("[OUT]")
}

// OnTouchBegin is called when Stage1 scene is Touched.
func (scene *Stage1) OnTouchBegin(x, y float32) {
	scene.isTouching = true
}

// OnTouchMove is called when Stage1 scene is Touched and moved.
func (scene *Stage1) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when Stage1 scene is Touched and it is released.
func (scene *Stage1) OnTouchEnd(x, y float32) {
	scene.isTouching = false

	if scene.gamestate == readyToRestart {
		// TODO: methodize
		scene.resetPosition()
		scene.views.restart()
		scene.models.restart()
		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[0].Sprite)

		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[1].Sprite)

		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[2].Sprite)

		simra.GetInstance().RemoveSprite(&scene.gameovertext[0])
		simra.GetInstance().RemoveSprite(&scene.gameovertext[1])

		scene.remainingLife = remainingLifeAtStart

		scene.gamestate = readyToStart
	}
}

func (scene *Stage1) resetPosition() {
	// set size of background
	scene.background[0].W = config.ScreenWidth + 1
	scene.background[0].H = config.ScreenHeight

	// put center of screen
	scene.background[0].X = config.ScreenWidth / 2
	scene.background[0].Y = config.ScreenHeight / 2

	// set size of background
	scene.background[1].W = config.ScreenWidth + 1
	scene.background[1].H = config.ScreenHeight

	// put out of screen
	scene.background[1].X = config.ScreenWidth/2 + (config.ScreenWidth)
	scene.background[1].Y = config.ScreenHeight / 2

	// set size of ball
	scene.ball.W = float32(48)
	scene.ball.H = float32(48)

	// put center of screen at start
	scene.ball.X = config.ScreenWidth / 2
	scene.ball.Y = config.ScreenHeight / 2

	// set size of obstacle
	scene.obstacle[0].W = 50
	scene.obstacle[0].H = 100
	scene.obstacle[1].W = 50
	scene.obstacle[1].H = 100

	// put center/upper side of screen
	scene.obstacle[0].X = config.ScreenWidth + config.ScreenWidth/2
	scene.obstacle[0].Y = config.ScreenHeight / 3 * 2

	// put center/lower side of screen
	scene.obstacle[1].X = config.ScreenWidth + config.ScreenWidth/2
	scene.obstacle[1].Y = config.ScreenHeight / 3 * 1

	scene.life[0].X = 48
	scene.life[0].Y = 30
	scene.life[0].W = float32(48)
	scene.life[0].H = float32(48)
	scene.life[1].X = 48 * 2
	scene.life[1].Y = 30
	scene.life[1].W = float32(48)
	scene.life[1].H = float32(48)
	scene.life[2].X = 48 * 3
	scene.life[2].Y = 30
	scene.life[2].W = float32(48)
	scene.life[2].H = float32(48)
}

func (scene *Stage1) setupSprites() {

	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[0].Sprite)

	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[1].Sprite)

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(scene.ball.W), int(scene.ball.H)),
		&scene.ball.Sprite)

	simra.GetInstance().AddSprite("obstacle.png",
		image.Rect(0, 0, 100, 100),
		&scene.obstacle[0].Sprite)

	simra.GetInstance().AddSprite("obstacle.png",
		image.Rect(0, 0, 100, 100),
		&scene.obstacle[1].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[0].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[1].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[2].Sprite)
}

func (scene *Stage1) registerViews() {
	scene.views.registerBall(&scene.ball)
	scene.views.addEventListener(scene)
}

func (scene *Stage1) showGameover() {
	scene.gameovertext[0].X = config.ScreenWidth / 2
	scene.gameovertext[0].Y = config.ScreenHeight/6*4 - 65/2
	scene.gameovertext[0].W = config.ScreenWidth
	scene.gameovertext[0].H = 65
	simra.GetInstance().AddTextSprite("GAME OVER",
		60,
		color.RGBA{255, 0, 0, 255},
		image.Rect(0, 0, config.ScreenWidth, 65),
		&scene.gameovertext[0])

	scene.gameovertext[1].X = config.ScreenWidth / 2
	scene.gameovertext[1].Y = config.ScreenHeight/6*3 - 65/2
	scene.gameovertext[1].W = config.ScreenWidth
	scene.gameovertext[1].H = 65
	simra.GetInstance().AddTextSprite("RESTART!!",
		60,
		color.RGBA{255, 0, 0, 255},
		image.Rect(0, 0, config.ScreenWidth, 65),
		&scene.gameovertext[1])
}

func (scene *Stage1) onFinishDead() {
	if scene.remainingLife == 0 {
		scene.showGameover()
		scene.gamestate = readyToRestart
		return
	}

	// life is still remaining. continue.
	scene.resetPosition()
	scene.views.restart()
	scene.models.restart()

	simra.GetInstance().RemoveSprite(&scene.life[scene.remainingLife-1].Sprite)
	scene.remainingLife--
}

func (scene *Stage1) registerModels() {
	scene.models.registerBall(&scene.ball)
	scene.models.registerObstacle(&scene.obstacle[0], 0)
	scene.models.registerObstacle(&scene.obstacle[1], 1)
	scene.models.registerBackground(&scene.background[0], 0)
	scene.models.registerBackground(&scene.background[1], 1)
	scene.models.addEventListener(&scene.views)
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (scene *Stage1) Drive() {
	scene.models.Progress(scene.isTouching)
	scene.views.Progress(scene.isTouching)
}
<commit_msg>[#90] temporary commit.<commit_after>package scene

import (
	"image"
	"image/color"

	"github.com/pankona/gomo-simra/examples/sample3/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

type gameState int

const (
	readyToStart gameState = iota
	started
	readyToRestart
)

// Stage1 represents scene of Stage1.
type Stage1 struct {
	models        models
	views         views
	ball          Ball
	obstacle      [2]Obstacle
	background    [2]Background
	isTouching    bool
	remainingLife int
	life          [3]Life
	gameovertext  [2]simra.Sprite
	gamestate     gameState
}

// Life represents view part of remaining life
type Life struct {
	simra.Sprite
}

func (life *Life) getPosition() (x float32, y float32) {
	x, y = life.X, life.Y
	return
}

func (life *Life) setPosition(x float32, y float32) {
	life.X, life.Y = x, y
}

func (life *Life) setSpeed(s float64) {
}

func (life *Life) getSpeed() float64 {
	return 0
}

func (life *Life) setDirection(radian float64) {
}
func (life *Life) getDirection() float64 {
	return 0
}

func (life *Life) move() {
}

const (
	remainingLifeAtStart = 3
)

// Initialize initializes Stage1 scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (scene *Stage1) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// add global touch listener to catch touch end event
	simra.GetInstance().AddTouchListener(scene)

	// TODO: when goes to next scene, remove global touch listener
	// simra.GetInstance().RemoveTouchListener(Stage1)

	scene.resetPosition()
	scene.setupSprites()
	scene.registerViews()
	scene.registerModels()
	scene.remainingLife = remainingLifeAtStart

	simra.GetInstance().AddCollisionListener(&scene.ball, &scene.obstacle[0], &scene.models)
	simra.GetInstance().AddCollisionListener(&scene.ball, &scene.obstacle[1], &scene.models)

	scene.gamestate = readyToStart

	simra.LogDebug("[OUT]")
}

// OnTouchBegin is called when Stage1 scene is Touched.
func (scene *Stage1) OnTouchBegin(x, y float32) {
	scene.isTouching = true

}

// OnTouchMove is called when Stage1 scene is Touched and moved.
func (scene *Stage1) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when Stage1 scene is Touched and it is released.
func (scene *Stage1) OnTouchEnd(x, y float32) {
	scene.isTouching = false

	if scene.gamestate == readyToStart {
		scene.gamestate = started
	} else if scene.gamestate == readyToRestart {
		// TODO: methodize
		scene.resetPosition()
		scene.views.restart()
		scene.models.restart()
		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[0].Sprite)

		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[1].Sprite)

		simra.GetInstance().AddSprite("heart.png",
			image.Rect(0, 0, 384, 384),
			&scene.life[2].Sprite)

		simra.GetInstance().RemoveSprite(&scene.gameovertext[0])
		simra.GetInstance().RemoveSprite(&scene.gameovertext[1])

		scene.remainingLife = remainingLifeAtStart

		scene.gamestate = readyToStart
	}
}

func (scene *Stage1) resetPosition() {
	// set size of background
	scene.background[0].W = config.ScreenWidth + 1
	scene.background[0].H = config.ScreenHeight

	// put center of screen
	scene.background[0].X = config.ScreenWidth / 2
	scene.background[0].Y = config.ScreenHeight / 2

	// set size of background
	scene.background[1].W = config.ScreenWidth + 1
	scene.background[1].H = config.ScreenHeight

	// put out of screen
	scene.background[1].X = config.ScreenWidth/2 + (config.ScreenWidth)
	scene.background[1].Y = config.ScreenHeight / 2

	// set size of ball
	scene.ball.W = float32(48)
	scene.ball.H = float32(48)

	// put center of screen at start
	scene.ball.X = config.ScreenWidth / 2
	scene.ball.Y = config.ScreenHeight / 2

	// set size of obstacle
	scene.obstacle[0].W = 50
	scene.obstacle[0].H = 100
	scene.obstacle[1].W = 50
	scene.obstacle[1].H = 100

	// put center/upper side of screen
	scene.obstacle[0].X = config.ScreenWidth + config.ScreenWidth/2
	scene.obstacle[0].Y = config.ScreenHeight / 3 * 2

	// put center/lower side of screen
	scene.obstacle[1].X = config.ScreenWidth + config.ScreenWidth/2
	scene.obstacle[1].Y = config.ScreenHeight / 3 * 1

	scene.life[0].X = 48
	scene.life[0].Y = 30
	scene.life[0].W = float32(48)
	scene.life[0].H = float32(48)
	scene.life[1].X = 48 * 2
	scene.life[1].Y = 30
	scene.life[1].W = float32(48)
	scene.life[1].H = float32(48)
	scene.life[2].X = 48 * 3
	scene.life[2].Y = 30
	scene.life[2].W = float32(48)
	scene.life[2].H = float32(48)
}

func (scene *Stage1) setupSprites() {

	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[0].Sprite)

	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[1].Sprite)

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(scene.ball.W), int(scene.ball.H)),
		&scene.ball.Sprite)

	simra.GetInstance().AddSprite("obstacle.png",
		image.Rect(0, 0, 100, 100),
		&scene.obstacle[0].Sprite)

	simra.GetInstance().AddSprite("obstacle.png",
		image.Rect(0, 0, 100, 100),
		&scene.obstacle[1].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[0].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[1].Sprite)

	simra.GetInstance().AddSprite("heart.png",
		image.Rect(0, 0, 384, 384),
		&scene.life[2].Sprite)
}

func (scene *Stage1) registerViews() {
	scene.views.registerBall(&scene.ball)
	scene.views.addEventListener(scene)
}

func (scene *Stage1) showGameover() {
	scene.gameovertext[0].X = config.ScreenWidth / 2
	scene.gameovertext[0].Y = config.ScreenHeight/6*4 - 65/2
	scene.gameovertext[0].W = config.ScreenWidth
	scene.gameovertext[0].H = 65
	simra.GetInstance().AddTextSprite("GAME OVER",
		60,
		color.RGBA{255, 0, 0, 255},
		image.Rect(0, 0, config.ScreenWidth, 65),
		&scene.gameovertext[0])

	scene.gameovertext[1].X = config.ScreenWidth / 2
	scene.gameovertext[1].Y = config.ScreenHeight/6*3 - 65/2
	scene.gameovertext[1].W = config.ScreenWidth
	scene.gameovertext[1].H = 65
	simra.GetInstance().AddTextSprite("RESTART!!",
		60,
		color.RGBA{255, 0, 0, 255},
		image.Rect(0, 0, config.ScreenWidth, 65),
		&scene.gameovertext[1])
}

func (scene *Stage1) onFinishDead() {
	if scene.remainingLife == 0 {
		scene.showGameover()
		scene.gamestate = readyToRestart
		return
	}

	// life is still remaining. continue.
	scene.resetPosition()
	scene.views.restart()
	scene.models.restart()

	simra.GetInstance().RemoveSprite(&scene.life[scene.remainingLife-1].Sprite)
	scene.remainingLife--
}

func (scene *Stage1) registerModels() {
	scene.models.registerBall(&scene.ball)
	scene.models.registerObstacle(&scene.obstacle[0], 0)
	scene.models.registerObstacle(&scene.obstacle[1], 1)
	scene.models.registerBackground(&scene.background[0], 0)
	scene.models.registerBackground(&scene.background[1], 1)
	scene.models.addEventListener(&scene.views)
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (scene *Stage1) Drive() {
	if scene.gamestate == started {
		scene.models.Progress(scene.isTouching)
		scene.views.Progress(scene.isTouching)
	}
}
<|endoftext|>


<commit_before><commit_msg>cap color value at 1<commit_after><|endoftext|>


<commit_before><commit_msg>Handle error<commit_after><|endoftext|>


<commit_before><commit_msg>Removed httpUserAgent constant<commit_after><|endoftext|>