<commit_before>package websocket

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingloan"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingtrade"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/position"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

func (c *Client) handleChannel(socketId SocketId, msg []byte) error {
	if c.terminal {
		return fmt.Errorf("received a message after close")
	}

	var raw []interface{}
	err := json.Unmarshal(msg, &raw)
	if err != nil {
		return err
	} else if len(raw) < 2 {
		return nil
	}

	chID, ok := raw[0].(float64)
	if !ok {
		return fmt.Errorf("expected message to start with a channel id but got %#v instead", raw[0])
	}

	chanID := int64(chID)
	sub, err := c.subscriptions.lookupBySocketChannelID(chanID, socketId)
	if err != nil {
		// no subscribed channel for message
		return err
	}
	c.subscriptions.heartbeat(chanID)
	if sub.Public {
		switch data := raw[1].(type) {
		case string:
			switch data {
			case "hb":
				// no-op, already updated heartbeat timeout from this event
				return nil
			case "cs":
				if checksum, ok := raw[2].(float64); ok {
					return c.handleChecksumChannel(sub, int(checksum))
				} else {
					c.log.Error("Unable to parse checksum")
				}
			default:
				body := raw[2].([]interface{})
				return c.handlePublicChannel(sub, sub.Request.Channel, data, body, msg)
			}
		case []interface{}:
			return c.handlePublicChannel(sub, sub.Request.Channel, "", data, msg)
		}
	} else {
		return c.handlePrivateChannel(raw)
	}
	return nil
}

func (c *Client) handleChecksumChannel(sub *subscription, checksum int) error {
	symbol := sub.Request.Symbol
	// force to signed integer
	bChecksum := uint32(checksum)
	var orderbook *Orderbook
	c.mtx.Lock()
	if ob, ok := c.orderbooks[symbol]; ok {
		orderbook = ob
	}
	c.mtx.Unlock()
	if orderbook != nil {
		oChecksum := orderbook.Checksum()
		// compare bitfinex checksum with local checksum
		if bChecksum == oChecksum {
			c.log.Debugf("Orderbook '%s' checksum verification successful.", symbol)
		} else {
			c.log.Warningf("Orderbook '%s' checksum is invalid got %d bot got %d. Data Out of sync, reconnecting.",
				symbol, bChecksum, oChecksum)
			err := c.sendUnsubscribeMessage(context.Background(), sub)
			if err != nil {
				return err
			}
			newSub := &SubscriptionRequest{
				SubID:   c.nonce.GetNonce(), // generate new subID
				Event:   sub.Request.Event,
				Channel: sub.Request.Channel,
				Symbol:  sub.Request.Symbol,
			}
			_, err_sub := c.Subscribe(context.Background(), newSub)
			if err_sub != nil {
				c.log.Warningf("could not resubscribe: %s", err_sub.Error())
				return err_sub
			}
		}
	}
	return nil
}

func (c *Client) handlePublicChannel(sub *subscription, channel, objType string, data []interface{}, raw_msg []byte) error {
	// unauthenticated data slice
	// public data is returned as raw interface arrays, use a factory to convert to raw type & publish
	if factory, ok := c.factories[channel]; ok {
		// convert to type array of interfaces
		if len(data) > 0 {
			if _, ok := data[0].([]interface{}); ok {
				interfaceArray := convert.ToInterfaceArray(data)
				// snapshot item
				c.mtx.Lock()
				// lock mutex since its mutates client struct
				msg, err := factory.BuildSnapshot(sub, interfaceArray, raw_msg)
				c.mtx.Unlock()
				if err != nil {
					return err
				}
				if msg != nil {
					c.listener <- msg
				}
			} else {
				// single item
				msg, err := factory.Build(sub, objType, data, raw_msg)
				if err != nil {
					return err
				}
				if msg != nil {
					c.listener <- msg
				}
			}
		}
	} else {
		// factory lookup error
		return fmt.Errorf("could not find public factory for %s channel", channel)
	}
	return nil
}

func (c *Client) handlePrivateChannel(raw []interface{}) error {
	// authenticated data slice, or a heartbeat
	if val, ok := raw[1].(string); ok && val == "hb" {
		chanID, ok := raw[0].(float64)
		if !ok {
			c.log.Warningf("could not find chanID: %#v", raw)
			return nil
		}
		c.handleHeartbeat(int64(chanID))
	} else {
		// raw[2] is data slice
		// authenticated snapshots?
		if len(raw) > 2 {
			if arr, ok := raw[2].([]interface{}); ok {
				obj, err := c.handlePrivateDataMessage(raw[1].(string), arr)
				if err != nil {
					return err
				}
				// private data is returned as strongly typed data, publish directly
				if obj != nil {
					c.listener <- obj
				}
			}
		}
	}
	return nil
}

func (c *Client) handleHeartbeat(chanID int64) {
	c.subscriptions.heartbeat(chanID)
}

type unsubscribeMsg struct {
	Event  string `json:"event"`
	ChanID int64  `json:"chanId"`
}

// public msg: [ChanID, [Data]]
// hb (both): [ChanID, "hb"]
// private update msg: [ChanID, "type", [Data]]
// private snapshot msg: [ChanID, "type", [[Data]]]
func (c *Client) handlePrivateDataMessage(term string, data []interface{}) (ms interface{}, err error) {
	if len(data) == 0 {
		// empty data msg
		return nil, nil
	}

	if term == "hb" { // Heartbeat
		// TODO: Consider adding a switch to enable/disable passing these along.
		return &bitfinex.Heartbeat{}, nil
	}
	/*
		list, ok := data[2].([]interface{})
		if !ok {
			return ms, fmt.Errorf("expected data list in third position but got %#v in %#v", data[2], data)
		}
	*/
	ms = c.convertRaw(term, data)

	return
}

// convertRaw takes a term and the raw data attached to it to try and convert that
// untyped list into a proper type.
func (c *Client) convertRaw(term string, raw []interface{}) interface{} {
	// The things you do to get proper types.
	switch term {
	case "bu":
		o, err := bitfinex.NewBalanceInfoFromRaw(raw)
		if err != nil {
			return err
		}
		bu := bitfinex.BalanceUpdate(*o)
		return &bu
	case "ps":
		o, err := position.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "pn":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pn := position.New(*o)
		return &pn
	case "pu":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pu := position.Update(*o)
		return &pu
	case "pc":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pc := position.Cancel(*o)
		return &pc
	case "ws":
		o, err := wallet.SnapshotFromRaw(raw, wallet.FromWsRaw)
		if err != nil {
			return err
		}
		return o
	case "wu":
		o, err := wallet.FromWsRaw(raw)
		if err != nil {
			return err
		}
		wu := wallet.Update(*o)
		return &wu
	case "os":
		o, err := bitfinex.NewOrderSnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "on":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		on := bitfinex.OrderNew(*o)
		return &on
	case "ou":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		ou := bitfinex.OrderUpdate(*o)
		return &ou
	case "oc":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		oc := bitfinex.OrderCancel(*o)
		return &oc
	case "hts":
		o, err := bitfinex.NewTradeExecutionUpdateSnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		hts := bitfinex.HistoricalTradeSnapshot(*o)
		return &hts
	case "te":
		o, err := bitfinex.NewTradeExecutionFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "tu":
		tu, err := bitfinex.NewTradeExecutionUpdateFromRaw(raw)
		if err != nil {
			return err
		}
		return tu
	case "fte":
		o, err := fundingtrade.FromRaw(raw)
		if err != nil {
			return err
		}
		fte := fundingtrade.Execution(*o)
		return &fte
	case "ftu":
		o, err := fundingtrade.FromRaw(raw)
		if err != nil {
			return err
		}
		ftu := fundingtrade.Update(*o)
		return &ftu
	case "hfts":
		fts, err := fundingtrade.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		nfts := fundingtrade.HistoricalSnapshot(*fts)
		return &nfts
	case "n":
		o, err := bitfinex.NewNotificationFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fos":
		o, err := fundingoffer.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fon":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		fon := fundingoffer.New(*o)
		return &fon
	case "fou":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		fou := fundingoffer.Update(*o)
		return &fou
	case "foc":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		foc := fundingoffer.Cancel(*o)
		return &foc
	case "fiu":
		o, err := bitfinex.NewFundingInfoFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fcs":
		o, err := bitfinex.NewFundingCreditSnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fcn":
		o, err := bitfinex.NewCreditFromRaw(raw)
		if err != nil {
			return err
		}
		fcn := bitfinex.FundingCreditNew(*o)
		return &fcn
	case "fcu":
		o, err := bitfinex.NewCreditFromRaw(raw)
		if err != nil {
			return err
		}
		fcu := bitfinex.FundingCreditUpdate(*o)
		return &fcu
	case "fcc":
		o, err := bitfinex.NewCreditFromRaw(raw)
		if err != nil {
			return err
		}
		fcc := bitfinex.FundingCreditCancel(*o)
		return &fcc
	case "fls":
		o, err := fundingloan.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fln":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		fln := fundingloan.New(*o)
		return &fln
	case "flu":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		flu := fundingloan.Update(*o)
		return &flu
	case "flc":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		flc := fundingloan.Cancel(*o)
		return &flc
	//case "uac":
	case "hb":
		return &bitfinex.Heartbeat{}
	case "ats":
		// TODO: Is not in documentation, so figure out what it is.
		return nil
	case "oc-req":
		// TODO
		return nil
	case "on-req":
		// TODO
		return nil
	case "mis": // Should not be sent anymore as of 2017-04-01
		return nil
	case "miu":
		o, err := bitfinex.NewMarginInfoFromRaw(raw)
		if err != nil {
			return err
		}
		// return a strongly typed reference, rather than dereference a generic interface
		// too bad golang doesn't inherit an interface's underlying type when creating a reference to the interface
		if base, ok := o.(*bitfinex.MarginInfoBase); ok {
			return base
		}
		if update, ok := o.(*bitfinex.MarginInfoUpdate); ok {
			return update
		}
		return o // better than nothing
	default:
		c.log.Warningf("unhandled channel data, term: %s", term)
	}

	return fmt.Errorf("term %q not recognized", term)
}
<commit_msg>v2/websocket/channels.go putting new fundingcredit package to work<commit_after>package websocket

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingcredit"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingloan"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingtrade"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/position"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

func (c *Client) handleChannel(socketId SocketId, msg []byte) error {
	if c.terminal {
		return fmt.Errorf("received a message after close")
	}

	var raw []interface{}
	err := json.Unmarshal(msg, &raw)
	if err != nil {
		return err
	} else if len(raw) < 2 {
		return nil
	}

	chID, ok := raw[0].(float64)
	if !ok {
		return fmt.Errorf("expected message to start with a channel id but got %#v instead", raw[0])
	}

	chanID := int64(chID)
	sub, err := c.subscriptions.lookupBySocketChannelID(chanID, socketId)
	if err != nil {
		// no subscribed channel for message
		return err
	}
	c.subscriptions.heartbeat(chanID)
	if sub.Public {
		switch data := raw[1].(type) {
		case string:
			switch data {
			case "hb":
				// no-op, already updated heartbeat timeout from this event
				return nil
			case "cs":
				if checksum, ok := raw[2].(float64); ok {
					return c.handleChecksumChannel(sub, int(checksum))
				} else {
					c.log.Error("Unable to parse checksum")
				}
			default:
				body := raw[2].([]interface{})
				return c.handlePublicChannel(sub, sub.Request.Channel, data, body, msg)
			}
		case []interface{}:
			return c.handlePublicChannel(sub, sub.Request.Channel, "", data, msg)
		}
	} else {
		return c.handlePrivateChannel(raw)
	}
	return nil
}

func (c *Client) handleChecksumChannel(sub *subscription, checksum int) error {
	symbol := sub.Request.Symbol
	// force to signed integer
	bChecksum := uint32(checksum)
	var orderbook *Orderbook
	c.mtx.Lock()
	if ob, ok := c.orderbooks[symbol]; ok {
		orderbook = ob
	}
	c.mtx.Unlock()
	if orderbook != nil {
		oChecksum := orderbook.Checksum()
		// compare bitfinex checksum with local checksum
		if bChecksum == oChecksum {
			c.log.Debugf("Orderbook '%s' checksum verification successful.", symbol)
		} else {
			c.log.Warningf("Orderbook '%s' checksum is invalid got %d bot got %d. Data Out of sync, reconnecting.",
				symbol, bChecksum, oChecksum)
			err := c.sendUnsubscribeMessage(context.Background(), sub)
			if err != nil {
				return err
			}
			newSub := &SubscriptionRequest{
				SubID:   c.nonce.GetNonce(), // generate new subID
				Event:   sub.Request.Event,
				Channel: sub.Request.Channel,
				Symbol:  sub.Request.Symbol,
			}
			_, err_sub := c.Subscribe(context.Background(), newSub)
			if err_sub != nil {
				c.log.Warningf("could not resubscribe: %s", err_sub.Error())
				return err_sub
			}
		}
	}
	return nil
}

func (c *Client) handlePublicChannel(sub *subscription, channel, objType string, data []interface{}, raw_msg []byte) error {
	// unauthenticated data slice
	// public data is returned as raw interface arrays, use a factory to convert to raw type & publish
	if factory, ok := c.factories[channel]; ok {
		// convert to type array of interfaces
		if len(data) > 0 {
			if _, ok := data[0].([]interface{}); ok {
				interfaceArray := convert.ToInterfaceArray(data)
				// snapshot item
				c.mtx.Lock()
				// lock mutex since its mutates client struct
				msg, err := factory.BuildSnapshot(sub, interfaceArray, raw_msg)
				c.mtx.Unlock()
				if err != nil {
					return err
				}
				if msg != nil {
					c.listener <- msg
				}
			} else {
				// single item
				msg, err := factory.Build(sub, objType, data, raw_msg)
				if err != nil {
					return err
				}
				if msg != nil {
					c.listener <- msg
				}
			}
		}
	} else {
		// factory lookup error
		return fmt.Errorf("could not find public factory for %s channel", channel)
	}
	return nil
}

func (c *Client) handlePrivateChannel(raw []interface{}) error {
	// authenticated data slice, or a heartbeat
	if val, ok := raw[1].(string); ok && val == "hb" {
		chanID, ok := raw[0].(float64)
		if !ok {
			c.log.Warningf("could not find chanID: %#v", raw)
			return nil
		}
		c.handleHeartbeat(int64(chanID))
	} else {
		// raw[2] is data slice
		// authenticated snapshots?
		if len(raw) > 2 {
			if arr, ok := raw[2].([]interface{}); ok {
				obj, err := c.handlePrivateDataMessage(raw[1].(string), arr)
				if err != nil {
					return err
				}
				// private data is returned as strongly typed data, publish directly
				if obj != nil {
					c.listener <- obj
				}
			}
		}
	}
	return nil
}

func (c *Client) handleHeartbeat(chanID int64) {
	c.subscriptions.heartbeat(chanID)
}

type unsubscribeMsg struct {
	Event  string `json:"event"`
	ChanID int64  `json:"chanId"`
}

// public msg: [ChanID, [Data]]
// hb (both): [ChanID, "hb"]
// private update msg: [ChanID, "type", [Data]]
// private snapshot msg: [ChanID, "type", [[Data]]]
func (c *Client) handlePrivateDataMessage(term string, data []interface{}) (ms interface{}, err error) {
	if len(data) == 0 {
		// empty data msg
		return nil, nil
	}

	if term == "hb" { // Heartbeat
		// TODO: Consider adding a switch to enable/disable passing these along.
		return &bitfinex.Heartbeat{}, nil
	}
	/*
		list, ok := data[2].([]interface{})
		if !ok {
			return ms, fmt.Errorf("expected data list in third position but got %#v in %#v", data[2], data)
		}
	*/
	ms = c.convertRaw(term, data)

	return
}

// convertRaw takes a term and the raw data attached to it to try and convert that
// untyped list into a proper type.
func (c *Client) convertRaw(term string, raw []interface{}) interface{} {
	// The things you do to get proper types.
	switch term {
	case "bu":
		o, err := bitfinex.NewBalanceInfoFromRaw(raw)
		if err != nil {
			return err
		}
		bu := bitfinex.BalanceUpdate(*o)
		return &bu
	case "ps":
		o, err := position.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "pn":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pn := position.New(*o)
		return &pn
	case "pu":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pu := position.Update(*o)
		return &pu
	case "pc":
		o, err := position.FromRaw(raw)
		if err != nil {
			return err
		}
		pc := position.Cancel(*o)
		return &pc
	case "ws":
		o, err := wallet.SnapshotFromRaw(raw, wallet.FromWsRaw)
		if err != nil {
			return err
		}
		return o
	case "wu":
		o, err := wallet.FromWsRaw(raw)
		if err != nil {
			return err
		}
		wu := wallet.Update(*o)
		return &wu
	case "os":
		o, err := bitfinex.NewOrderSnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "on":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		on := bitfinex.OrderNew(*o)
		return &on
	case "ou":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		ou := bitfinex.OrderUpdate(*o)
		return &ou
	case "oc":
		o, err := bitfinex.NewOrderFromRaw(raw)
		if err != nil {
			return err
		}
		oc := bitfinex.OrderCancel(*o)
		return &oc
	case "hts":
		o, err := bitfinex.NewTradeExecutionUpdateSnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		hts := bitfinex.HistoricalTradeSnapshot(*o)
		return &hts
	case "te":
		o, err := bitfinex.NewTradeExecutionFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "tu":
		tu, err := bitfinex.NewTradeExecutionUpdateFromRaw(raw)
		if err != nil {
			return err
		}
		return tu
	case "fte":
		o, err := fundingtrade.FromRaw(raw)
		if err != nil {
			return err
		}
		fte := fundingtrade.Execution(*o)
		return &fte
	case "ftu":
		o, err := fundingtrade.FromRaw(raw)
		if err != nil {
			return err
		}
		ftu := fundingtrade.Update(*o)
		return &ftu
	case "hfts":
		fts, err := fundingtrade.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		nfts := fundingtrade.HistoricalSnapshot(*fts)
		return &nfts
	case "n":
		o, err := bitfinex.NewNotificationFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fos":
		o, err := fundingoffer.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fon":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		fon := fundingoffer.New(*o)
		return &fon
	case "fou":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		fou := fundingoffer.Update(*o)
		return &fou
	case "foc":
		o, err := fundingoffer.FromRaw(raw)
		if err != nil {
			return err
		}
		foc := fundingoffer.Cancel(*o)
		return &foc
	case "fiu":
		o, err := bitfinex.NewFundingInfoFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fcs":
		o, err := fundingcredit.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fcn":
		o, err := fundingcredit.FromRaw(raw)
		if err != nil {
			return err
		}
		fcn := fundingcredit.New(*o)
		return &fcn
	case "fcu":
		o, err := fundingcredit.FromRaw(raw)
		if err != nil {
			return err
		}
		fcu := fundingcredit.Update(*o)
		return &fcu
	case "fcc":
		o, err := fundingcredit.FromRaw(raw)
		if err != nil {
			return err
		}
		fcc := fundingcredit.Cancel(*o)
		return &fcc
	case "fls":
		o, err := fundingloan.SnapshotFromRaw(raw)
		if err != nil {
			return err
		}
		return o
	case "fln":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		fln := fundingloan.New(*o)
		return &fln
	case "flu":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		flu := fundingloan.Update(*o)
		return &flu
	case "flc":
		o, err := fundingloan.FromRaw(raw)
		if err != nil {
			return err
		}
		flc := fundingloan.Cancel(*o)
		return &flc
	//case "uac":
	case "hb":
		return &bitfinex.Heartbeat{}
	case "ats":
		// TODO: Is not in documentation, so figure out what it is.
		return nil
	case "oc-req":
		// TODO
		return nil
	case "on-req":
		// TODO
		return nil
	case "mis": // Should not be sent anymore as of 2017-04-01
		return nil
	case "miu":
		o, err := bitfinex.NewMarginInfoFromRaw(raw)
		if err != nil {
			return err
		}
		// return a strongly typed reference, rather than dereference a generic interface
		// too bad golang doesn't inherit an interface's underlying type when creating a reference to the interface
		if base, ok := o.(*bitfinex.MarginInfoBase); ok {
			return base
		}
		if update, ok := o.(*bitfinex.MarginInfoUpdate); ok {
			return update
		}
		return o // better than nothing
	default:
		c.log.Warningf("unhandled channel data, term: %s", term)
	}

	return fmt.Errorf("term %q not recognized", term)
}
<|endoftext|>


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

package lib

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

	"github.com/appc/acbuild/Godeps/_workspace/src/github.com/appc/spec/aci"

	"github.com/appc/acbuild/registry"
	"github.com/appc/acbuild/util"
)

var pathlist = []string{"/usr/local/sbin", "/usr/local/bin", "/usr/sbin",
	"/usr/bin", "/sbin", "/bin"}

// Run will execute the given command in the ACI being built. a.CurrentACIPath
// is where the untarred ACI is stored, a.DepStoreTarPath is the directory to
// download dependencies into, a.DepStoreExpandedPath is where the dependencies
// are expanded into, a.OverlayWorkPath is the work directory used by
// overlayfs, and insecure signifies whether downloaded images should be
// fetched over http or https.
func (a *ACBuild) Run(cmd []string, insecure bool) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	if os.Geteuid() != 0 {
		return fmt.Errorf("the run subcommand must be run as root")
	}

	err = util.RmAndMkdir(a.OverlayTargetPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayTargetPath)
	err = util.RmAndMkdir(a.OverlayWorkPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayWorkPath)
	err = os.MkdirAll(a.DepStoreExpandedPath, 0755)
	if err != nil {
		return err
	}
	err = os.MkdirAll(a.DepStoreTarPath, 0755)
	if err != nil {
		return err
	}

	man, err := util.GetManifest(a.CurrentACIPath)
	if err != nil {
		return err
	}

	if len(man.Dependencies) != 0 {
		if !supportsOverlay() {
			err := exec.Command("modprobe", "overlay").Run()
			if err != nil {
				return err
			}
			if !supportsOverlay() {
				return fmt.Errorf(
					"overlayfs support required for using run with dependencies")
			}
		}
	}

	deps, err := a.renderACI(insecure, a.Debug)
	if err != nil {
		return err
	}

	var nspawnpath string
	if deps == nil {
		nspawnpath = path.Join(a.CurrentACIPath, aci.RootfsDir)
	} else {
		for i, dep := range deps {
			deps[i] = path.Join(a.DepStoreExpandedPath, dep, aci.RootfsDir)
		}
		options := "lowerdir=" + strings.Join(deps, ":") +
			",upperdir=" + path.Join(a.CurrentACIPath, aci.RootfsDir) +
			",workdir=" + a.OverlayWorkPath
		err := syscall.Mount("overlay", a.OverlayTargetPath, "overlay", 0, options)
		if err != nil {
			return err
		}

		defer func() {
			err1 := syscall.Unmount(a.OverlayTargetPath, 0)
			if err == nil {
				err = err1
			}
		}()

		nspawnpath = a.OverlayTargetPath
	}
	nspawncmd := []string{"systemd-nspawn", "-q", "-D", nspawnpath}

	if man.App != nil {
		for _, evar := range man.App.Environment {
			nspawncmd = append(nspawncmd, "--setenv", evar.Name+"="+evar.Value)
		}
	}

	err = a.mirrorLocalZoneInfo()
	if err != nil {
		return err
	}

	if len(cmd) == 0 {
		return fmt.Errorf("command to run not set")
	}
	abscmd, err := findCmdInPath(pathlist, cmd[0], nspawnpath)
	if err != nil {
		return err
	}
	nspawncmd = append(nspawncmd, abscmd)
	nspawncmd = append(nspawncmd, cmd[1:]...)

	execCmd := exec.Command(nspawncmd[0], nspawncmd[1:]...)
	execCmd.Stdin = os.Stdin
	execCmd.Stdout = os.Stdout
	execCmd.Stderr = os.Stderr
	execCmd.Env = []string{"SYSTEMD_LOG_LEVEL=err"}

	err = execCmd.Run()
	if err != nil {
		if err == exec.ErrNotFound {
			return fmt.Errorf("systemd-nspawn is required but not found")
		}
		return err
	}

	return nil
}

// stolen from github.com/coreos/rkt/common/common.go
// supportsOverlay returns whether the system supports overlay filesystem
func supportsOverlay() bool {
	f, err := os.Open("/proc/filesystems")
	if err != nil {
		fmt.Println("error opening /proc/filesystems")
		return false
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		if s.Text() == "nodev\toverlay" {
			return true
		}
	}
	return false
}

func findCmdInPath(pathlist []string, cmd, prefix string) (string, error) {
	if path.IsAbs(cmd) {
		return cmd, nil
	}

	for _, p := range pathlist {
		_, err := os.Lstat(path.Join(prefix, p, cmd))
		switch {
		case os.IsNotExist(err):
			continue
		case err != nil:
			return "", err
		}
		return path.Join(p, cmd), nil
	}
	return "", fmt.Errorf("%s not found in any of: %v", cmd, pathlist)
}

func (a *ACBuild) renderACI(insecure, debug bool) ([]string, error) {
	reg := registry.Registry{
		DepStoreTarPath:      a.DepStoreTarPath,
		DepStoreExpandedPath: a.DepStoreExpandedPath,
		Insecure:             insecure,
		Debug:                debug,
	}

	man, err := util.GetManifest(a.CurrentACIPath)
	if err != nil {
		return nil, err
	}

	if len(man.Dependencies) == 0 {
		return nil, nil
	}

	var deplist []string
	for _, dep := range man.Dependencies {
		err := reg.FetchAndRender(dep.ImageName, dep.Labels, dep.Size)
		if err != nil {
			return nil, err
		}

		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeplist, err := genDeplist(path.Join(a.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deplist = append(deplist, subdeplist...)
	}

	return deplist, nil
}

func genDeplist(acipath string, reg registry.Registry) ([]string, error) {
	man, err := util.GetManifest(acipath)
	if err != nil {
		return nil, err
	}
	key, err := reg.GetACI(man.Name, man.Labels)
	if err != nil {
		fmt.Printf("Name: %s", man.Name)
		return nil, err
	}

	var deps []string
	for _, dep := range man.Dependencies {
		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeps, err := genDeplist(path.Join(reg.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deps = append(deps, subdeps...)
	}

	deps = append(deps, key)
	return deps, nil
}

func (a *ACBuild) mirrorLocalZoneInfo() error {
	zif, err := os.Readlink("/etc/localtime")
	if err != nil {
		return err
	}

	src, err := os.Open(zif)
	if err != nil {
		return err
	}
	defer src.Close()

	destp := filepath.Join(a.CurrentACIPath, aci.RootfsDir, zif)

	if err = os.MkdirAll(filepath.Dir(destp), 0755); err != nil {
		return err
	}

	dest, err := os.OpenFile(destp, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer dest.Close()

	_, err = io.Copy(dest, src)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>run: don't register run commands with machined<commit_after>// Copyright 2015 The appc Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lib

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

	"github.com/appc/acbuild/Godeps/_workspace/src/github.com/appc/spec/aci"

	"github.com/appc/acbuild/registry"
	"github.com/appc/acbuild/util"
)

var pathlist = []string{"/usr/local/sbin", "/usr/local/bin", "/usr/sbin",
	"/usr/bin", "/sbin", "/bin"}

// Run will execute the given command in the ACI being built. a.CurrentACIPath
// is where the untarred ACI is stored, a.DepStoreTarPath is the directory to
// download dependencies into, a.DepStoreExpandedPath is where the dependencies
// are expanded into, a.OverlayWorkPath is the work directory used by
// overlayfs, and insecure signifies whether downloaded images should be
// fetched over http or https.
func (a *ACBuild) Run(cmd []string, insecure bool) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	if os.Geteuid() != 0 {
		return fmt.Errorf("the run subcommand must be run as root")
	}

	err = util.RmAndMkdir(a.OverlayTargetPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayTargetPath)
	err = util.RmAndMkdir(a.OverlayWorkPath)
	if err != nil {
		return err
	}
	defer os.RemoveAll(a.OverlayWorkPath)
	err = os.MkdirAll(a.DepStoreExpandedPath, 0755)
	if err != nil {
		return err
	}
	err = os.MkdirAll(a.DepStoreTarPath, 0755)
	if err != nil {
		return err
	}

	man, err := util.GetManifest(a.CurrentACIPath)
	if err != nil {
		return err
	}

	if len(man.Dependencies) != 0 {
		if !supportsOverlay() {
			err := exec.Command("modprobe", "overlay").Run()
			if err != nil {
				return err
			}
			if !supportsOverlay() {
				return fmt.Errorf(
					"overlayfs support required for using run with dependencies")
			}
		}
	}

	deps, err := a.renderACI(insecure, a.Debug)
	if err != nil {
		return err
	}

	var nspawnpath string
	if deps == nil {
		nspawnpath = path.Join(a.CurrentACIPath, aci.RootfsDir)
	} else {
		for i, dep := range deps {
			deps[i] = path.Join(a.DepStoreExpandedPath, dep, aci.RootfsDir)
		}
		options := "lowerdir=" + strings.Join(deps, ":") +
			",upperdir=" + path.Join(a.CurrentACIPath, aci.RootfsDir) +
			",workdir=" + a.OverlayWorkPath
		err := syscall.Mount("overlay", a.OverlayTargetPath, "overlay", 0, options)
		if err != nil {
			return err
		}

		defer func() {
			err1 := syscall.Unmount(a.OverlayTargetPath, 0)
			if err == nil {
				err = err1
			}
		}()

		nspawnpath = a.OverlayTargetPath
	}
	nspawncmd := []string{"systemd-nspawn", "-q", "--register=no", "-D", nspawnpath}

	if man.App != nil {
		for _, evar := range man.App.Environment {
			nspawncmd = append(nspawncmd, "--setenv", evar.Name+"="+evar.Value)
		}
	}

	err = a.mirrorLocalZoneInfo()
	if err != nil {
		return err
	}

	if len(cmd) == 0 {
		return fmt.Errorf("command to run not set")
	}
	abscmd, err := findCmdInPath(pathlist, cmd[0], nspawnpath)
	if err != nil {
		return err
	}
	nspawncmd = append(nspawncmd, abscmd)
	nspawncmd = append(nspawncmd, cmd[1:]...)

	execCmd := exec.Command(nspawncmd[0], nspawncmd[1:]...)
	execCmd.Stdin = os.Stdin
	execCmd.Stdout = os.Stdout
	execCmd.Stderr = os.Stderr
	execCmd.Env = []string{"SYSTEMD_LOG_LEVEL=err"}

	err = execCmd.Run()
	if err != nil {
		if err == exec.ErrNotFound {
			return fmt.Errorf("systemd-nspawn is required but not found")
		}
		return err
	}

	return nil
}

// stolen from github.com/coreos/rkt/common/common.go
// supportsOverlay returns whether the system supports overlay filesystem
func supportsOverlay() bool {
	f, err := os.Open("/proc/filesystems")
	if err != nil {
		fmt.Println("error opening /proc/filesystems")
		return false
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		if s.Text() == "nodev\toverlay" {
			return true
		}
	}
	return false
}

func findCmdInPath(pathlist []string, cmd, prefix string) (string, error) {
	if path.IsAbs(cmd) {
		return cmd, nil
	}

	for _, p := range pathlist {
		_, err := os.Lstat(path.Join(prefix, p, cmd))
		switch {
		case os.IsNotExist(err):
			continue
		case err != nil:
			return "", err
		}
		return path.Join(p, cmd), nil
	}
	return "", fmt.Errorf("%s not found in any of: %v", cmd, pathlist)
}

func (a *ACBuild) renderACI(insecure, debug bool) ([]string, error) {
	reg := registry.Registry{
		DepStoreTarPath:      a.DepStoreTarPath,
		DepStoreExpandedPath: a.DepStoreExpandedPath,
		Insecure:             insecure,
		Debug:                debug,
	}

	man, err := util.GetManifest(a.CurrentACIPath)
	if err != nil {
		return nil, err
	}

	if len(man.Dependencies) == 0 {
		return nil, nil
	}

	var deplist []string
	for _, dep := range man.Dependencies {
		err := reg.FetchAndRender(dep.ImageName, dep.Labels, dep.Size)
		if err != nil {
			return nil, err
		}

		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeplist, err := genDeplist(path.Join(a.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deplist = append(deplist, subdeplist...)
	}

	return deplist, nil
}

func genDeplist(acipath string, reg registry.Registry) ([]string, error) {
	man, err := util.GetManifest(acipath)
	if err != nil {
		return nil, err
	}
	key, err := reg.GetACI(man.Name, man.Labels)
	if err != nil {
		fmt.Printf("Name: %s", man.Name)
		return nil, err
	}

	var deps []string
	for _, dep := range man.Dependencies {
		depkey, err := reg.GetACI(dep.ImageName, dep.Labels)
		if err != nil {
			return nil, err
		}

		subdeps, err := genDeplist(path.Join(reg.DepStoreExpandedPath, depkey), reg)
		if err != nil {
			return nil, err
		}
		deps = append(deps, subdeps...)
	}

	deps = append(deps, key)
	return deps, nil
}

func (a *ACBuild) mirrorLocalZoneInfo() error {
	zif, err := os.Readlink("/etc/localtime")
	if err != nil {
		return err
	}

	src, err := os.Open(zif)
	if err != nil {
		return err
	}
	defer src.Close()

	destp := filepath.Join(a.CurrentACIPath, aci.RootfsDir, zif)

	if err = os.MkdirAll(filepath.Dir(destp), 0755); err != nil {
		return err
	}

	dest, err := os.OpenFile(destp, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer dest.Close()

	_, err = io.Copy(dest, src)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package arn

import (
	"github.com/aerogo/api"
	"github.com/aerogo/nano"
	"github.com/animenotifier/jikan"
	"github.com/animenotifier/kitsu"
	"github.com/animenotifier/mal"
)

// Session ...
type Session map[string]interface{}

// Node represents the database node.
var Node = nano.New(5000)

// DB is the main database client.
var DB = Node.Namespace("arn").RegisterTypes(
	(*Analytics)(nil),
	(*Anime)(nil),
	(*AnimeCharacters)(nil),
	(*AnimeEpisodes)(nil),
	(*AnimeRelations)(nil),
	(*AnimeList)(nil),
	(*AniListToAnime)(nil),
	(*Character)(nil),
	(*Company)(nil),
	(*DraftIndex)(nil),
	(*MyAnimeListToAnime)(nil),
	(*EditLogEntry)(nil),
	(*EmailToUser)(nil),
	(*FacebookToUser)(nil),
	(*GoogleToUser)(nil),
	(*Group)(nil),
	(*GroupPost)(nil),
	(*Item)(nil),
	(*IDList)(nil),
	(*IgnoreAnimeDifference)(nil),
	(*Inventory)(nil),
	(*NickToUser)(nil),
	(*Notification)(nil),
	(*PayPalPayment)(nil),
	(*Post)(nil),
	(*Purchase)(nil),
	(*PushSubscriptions)(nil),
	(*Quote)(nil),
	(*Session)(nil),
	(*Settings)(nil),
	(*SoundTrack)(nil),
	(*Thread)(nil),
	(*TwitterToUser)(nil),
	(*User)(nil),
	(*UserFollows)(nil),
	(*UserNotifications)(nil),
)

// MAL is the client for the MyAnimeList database.
var MAL = Node.Namespace("mal").RegisterTypes(
	(*mal.Anime)(nil),
)

// Kitsu is the client for the Kitsu database.
var Kitsu = Node.Namespace("kitsu").RegisterTypes(
	(*kitsu.Anime)(nil),
)

// API ...
var API = api.New("/api/", DB)

// init ...
func init() {
	Node.Namespace("jikan").RegisterTypes(
		(*jikan.Anime)(nil),
		(*jikan.Character)(nil),
	)
}
<commit_msg>Added kitsu mappings<commit_after>package arn

import (
	"github.com/aerogo/api"
	"github.com/aerogo/nano"
	"github.com/animenotifier/jikan"
	"github.com/animenotifier/kitsu"
	"github.com/animenotifier/mal"
)

// Session ...
type Session map[string]interface{}

// Node represents the database node.
var Node = nano.New(5000)

// DB is the main database client.
var DB = Node.Namespace("arn").RegisterTypes(
	(*Analytics)(nil),
	(*Anime)(nil),
	(*AnimeCharacters)(nil),
	(*AnimeEpisodes)(nil),
	(*AnimeRelations)(nil),
	(*AnimeList)(nil),
	(*AniListToAnime)(nil),
	(*Character)(nil),
	(*Company)(nil),
	(*DraftIndex)(nil),
	(*MyAnimeListToAnime)(nil),
	(*EditLogEntry)(nil),
	(*EmailToUser)(nil),
	(*FacebookToUser)(nil),
	(*GoogleToUser)(nil),
	(*Group)(nil),
	(*GroupPost)(nil),
	(*Item)(nil),
	(*IDList)(nil),
	(*IgnoreAnimeDifference)(nil),
	(*Inventory)(nil),
	(*NickToUser)(nil),
	(*Notification)(nil),
	(*PayPalPayment)(nil),
	(*Post)(nil),
	(*Purchase)(nil),
	(*PushSubscriptions)(nil),
	(*Quote)(nil),
	(*Session)(nil),
	(*Settings)(nil),
	(*SoundTrack)(nil),
	(*Thread)(nil),
	(*TwitterToUser)(nil),
	(*User)(nil),
	(*UserFollows)(nil),
	(*UserNotifications)(nil),
)

// MAL is the client for the MyAnimeList database.
var MAL = Node.Namespace("mal").RegisterTypes(
	(*mal.Anime)(nil),
)

// Kitsu is the client for the Kitsu database.
var Kitsu = Node.Namespace("kitsu").RegisterTypes(
	(*kitsu.Anime)(nil),
	(*kitsu.Mapping)(nil),
)

// API ...
var API = api.New("/api/", DB)

// init ...
func init() {
	Node.Namespace("jikan").RegisterTypes(
		(*jikan.Anime)(nil),
		(*jikan.Character)(nil),
	)
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/smartystreets/goconvey/web/server/contract"
	"github.com/smartystreets/goconvey/web/server2/messaging"
)

type HTTPServer struct {
	watcher     chan messaging.ServerToWatcherCommand
	executor    contract.Executor
	latest      *contract.CompleteOutput
	currentRoot string
	longpoll    chan chan string
	paused      bool
}

func (self *HTTPServer) ReceiveUpdate(root string, update *contract.CompleteOutput) {
	self.currentRoot = root
	self.latest = update
}

func (self *HTTPServer) Watch(response http.ResponseWriter, request *http.Request) {
	if request.Method == "POST" {
		self.adjustRoot(response, request)
	} else if request.Method == "GET" {
		response.Write([]byte(self.currentRoot))
	}
}

func (self *HTTPServer) adjustRoot(response http.ResponseWriter, request *http.Request) {
	newRoot := self.parseQueryString("root", response, request)
	if newRoot == "" {
		return
	}
	info, err := os.Stat(newRoot) // TODO: how to unit test?
	if !info.IsDir() || err != nil {
		http.Error(response, err.Error(), http.StatusNotFound)
		return
	}

	self.watcher <- messaging.ServerToWatcherCommand{
		Instruction: messaging.WatcherAdjustRoot,
		Details:     newRoot,
	}
}

func (self *HTTPServer) Ignore(response http.ResponseWriter, request *http.Request) {
	paths := self.parseQueryString("paths", response, request)
	if paths != "" {
		self.watcher <- messaging.ServerToWatcherCommand{
			Instruction: messaging.WatcherIgnore,
			Details:     paths,
		}
	}
}

func (self *HTTPServer) Reinstate(response http.ResponseWriter, request *http.Request) {
	paths := self.parseQueryString("paths", response, request)
	if paths != "" {
		self.watcher <- messaging.ServerToWatcherCommand{
			Instruction: messaging.WatcherReinstate,
			Details:     paths,
		}
	}
}

func (self *HTTPServer) parseQueryString(key string, response http.ResponseWriter, request *http.Request) string {
	value := request.URL.Query()[key]

	if len(value) == 0 {
		http.Error(response, fmt.Sprintf("No '%s' query string parameter included!", key), http.StatusBadRequest)
		return ""
	}

	path := value[0]
	if path == "" {
		http.Error(response, "You must provide a non-blank path.", http.StatusBadRequest)
	}
	return path
}

func (self *HTTPServer) Status(response http.ResponseWriter, request *http.Request) {
	status := self.executor.Status()
	response.Write([]byte(status))
}

func (self *HTTPServer) LongPollStatus(response http.ResponseWriter, request *http.Request) {
	if self.executor.ClearStatusFlag() {
		response.Write([]byte(self.executor.Status()))
		return
	}

	timeout, err := strconv.Atoi(request.URL.Query().Get("timeout"))
	if err != nil || timeout > 180000 || timeout < 0 {
		timeout = 60000 // default timeout is 60 seconds
	}

	myReqChan := make(chan string)

	select {
	case self.longpoll <- myReqChan: // this case means the executor's status is changing
	case <-time.After(time.Duration(timeout) * time.Millisecond): // this case means the executor hasn't changed status
		return
	}

	out := <-myReqChan

	if out != "" { // TODO: Why is this check necessary? Sometimes it writes empty string...
		response.Write([]byte(out))
	}
}

func (self *HTTPServer) Results(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-Type", "application/json")
	response.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	response.Header().Set("Pragma", "no-cache")
	response.Header().Set("Expires", "0")
	if self.latest != nil {
		self.latest.Paused = self.paused
	}
	stuff, _ := json.Marshal(self.latest)
	response.Write(stuff)
}

func (self *HTTPServer) Execute(response http.ResponseWriter, request *http.Request) {
	go self.execute()
}

func (self *HTTPServer) execute() {
	self.watcher <- messaging.ServerToWatcherCommand{Instruction: messaging.WatcherExecute}
}

func (self *HTTPServer) TogglePause(response http.ResponseWriter, request *http.Request) {
	instruction := messaging.WatcherPause
	if self.paused {
		instruction = messaging.WatcherResume
	}

	select {
	case self.watcher <- messaging.ServerToWatcherCommand{Instruction: instruction}:
		self.paused = !self.paused
	default:
	}

	fmt.Fprint(response, self.paused) // we could write out whatever helps keep the UI honest...
}

func NewHTTPServer(
	root string,
	watcher chan messaging.ServerToWatcherCommand,
	executor contract.Executor,
	status chan chan string) *HTTPServer {

	self := new(HTTPServer)
	self.currentRoot = root
	self.watcher = watcher
	self.executor = executor
	self.longpoll = status
	return self
}
<commit_msg>Simplified send-only operation.<commit_after>package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/smartystreets/goconvey/web/server/contract"
	"github.com/smartystreets/goconvey/web/server2/messaging"
)

type HTTPServer struct {
	watcher     chan messaging.ServerToWatcherCommand
	executor    contract.Executor
	latest      *contract.CompleteOutput
	currentRoot string
	longpoll    chan chan string
	paused      bool
}

func (self *HTTPServer) ReceiveUpdate(root string, update *contract.CompleteOutput) {
	self.currentRoot = root
	self.latest = update
}

func (self *HTTPServer) Watch(response http.ResponseWriter, request *http.Request) {
	if request.Method == "POST" {
		self.adjustRoot(response, request)
	} else if request.Method == "GET" {
		response.Write([]byte(self.currentRoot))
	}
}

func (self *HTTPServer) adjustRoot(response http.ResponseWriter, request *http.Request) {
	newRoot := self.parseQueryString("root", response, request)
	if newRoot == "" {
		return
	}
	info, err := os.Stat(newRoot) // TODO: how to unit test?
	if !info.IsDir() || err != nil {
		http.Error(response, err.Error(), http.StatusNotFound)
		return
	}

	self.watcher <- messaging.ServerToWatcherCommand{
		Instruction: messaging.WatcherAdjustRoot,
		Details:     newRoot,
	}
}

func (self *HTTPServer) Ignore(response http.ResponseWriter, request *http.Request) {
	paths := self.parseQueryString("paths", response, request)
	if paths != "" {
		self.watcher <- messaging.ServerToWatcherCommand{
			Instruction: messaging.WatcherIgnore,
			Details:     paths,
		}
	}
}

func (self *HTTPServer) Reinstate(response http.ResponseWriter, request *http.Request) {
	paths := self.parseQueryString("paths", response, request)
	if paths != "" {
		self.watcher <- messaging.ServerToWatcherCommand{
			Instruction: messaging.WatcherReinstate,
			Details:     paths,
		}
	}
}

func (self *HTTPServer) parseQueryString(key string, response http.ResponseWriter, request *http.Request) string {
	value := request.URL.Query()[key]

	if len(value) == 0 {
		http.Error(response, fmt.Sprintf("No '%s' query string parameter included!", key), http.StatusBadRequest)
		return ""
	}

	path := value[0]
	if path == "" {
		http.Error(response, "You must provide a non-blank path.", http.StatusBadRequest)
	}
	return path
}

func (self *HTTPServer) Status(response http.ResponseWriter, request *http.Request) {
	status := self.executor.Status()
	response.Write([]byte(status))
}

func (self *HTTPServer) LongPollStatus(response http.ResponseWriter, request *http.Request) {
	if self.executor.ClearStatusFlag() {
		response.Write([]byte(self.executor.Status()))
		return
	}

	timeout, err := strconv.Atoi(request.URL.Query().Get("timeout"))
	if err != nil || timeout > 180000 || timeout < 0 {
		timeout = 60000 // default timeout is 60 seconds
	}

	myReqChan := make(chan string)

	select {
	case self.longpoll <- myReqChan: // this case means the executor's status is changing
	case <-time.After(time.Duration(timeout) * time.Millisecond): // this case means the executor hasn't changed status
		return
	}

	out := <-myReqChan

	if out != "" { // TODO: Why is this check necessary? Sometimes it writes empty string...
		response.Write([]byte(out))
	}
}

func (self *HTTPServer) Results(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-Type", "application/json")
	response.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	response.Header().Set("Pragma", "no-cache")
	response.Header().Set("Expires", "0")
	if self.latest != nil {
		self.latest.Paused = self.paused
	}
	stuff, _ := json.Marshal(self.latest)
	response.Write(stuff)
}

func (self *HTTPServer) Execute(response http.ResponseWriter, request *http.Request) {
	go self.execute()
}

func (self *HTTPServer) execute() {
	self.watcher <- messaging.ServerToWatcherCommand{Instruction: messaging.WatcherExecute}
}

func (self *HTTPServer) TogglePause(response http.ResponseWriter, request *http.Request) {
	instruction := messaging.WatcherPause
	if self.paused {
		instruction = messaging.WatcherResume
	}

	self.watcher <- messaging.ServerToWatcherCommand{Instruction: instruction}
	self.paused = !self.paused

	fmt.Fprint(response, self.paused) // we could write out whatever helps keep the UI honest...
}

func NewHTTPServer(
	root string,
	watcher chan messaging.ServerToWatcherCommand,
	executor contract.Executor,
	status chan chan string) *HTTPServer {

	self := new(HTTPServer)
	self.currentRoot = root
	self.watcher = watcher
	self.executor = executor
	self.longpoll = status
	return self
}
<|endoftext|>


<commit_before>package chessboard

type Board [][]byte

var starting = Board{
	{'R', 'N', 'B', 'K', 'Q', 'B', 'N', 'R'},
	{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
	{'R', 'N', 'B', 'K', 'Q', 'B', 'N', 'R'},
}

func Piece(p Point) byte {
	return starting[p.y][p.x]
}
<commit_msg>Set new Board and its initializer<commit_after>package chessboard

var starting = [8][8]byte{
	{'R', 'N', 'B', 'K', 'Q', 'B', 'N', 'R'},
	{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
	{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
	{'R', 'N', 'B', 'K', 'Q', 'B', 'N', 'R'},
}

type Board struct {
	matrix [8][8]byte
}

func NewBoard() *Board {
	board := new(Board)
	board.matrix = starting
	return board
}

func Piece(p Point) byte {
	return starting[p.y][p.x]
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
)

// createDefaultConfigFile creates a config file  -- only call this if the
// config file isn't already there
func createDefaultConfigFile(destinationPath string) error {

	dest, err := os.OpenFile(filepath.Join(destinationPath, defaultConfigFilename),
		os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer dest.Close()

	writer := bufio.NewWriter(dest)
	defaultArgs := []byte("tn3=1")
	_, err = writer.Write(defaultArgs)
	if err != nil {
		return err
	}
	writer.Flush()
	return nil
}

// litSetup performs most of the setup when lit is run, such as setting
// configuration variables, reading in key data, reading and creating files if
// they're not yet there.  It takes in a config, and returns a key.
// (maybe add the key to the config?
func litSetup(conf *litConfig) *[32]byte {
	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.  Any errors aside from the
	// help message error can be ignored here since they will be caught by
	// the final parse below.

	//	usageMessage := fmt.Sprintf("Use %s -h to show usage", "./lit")

	preParser := newConfigParser(conf, flags.HelpFlag)
	_, err := preParser.ParseArgs(os.Args)
	if err != nil {
		logging.Fatal(err)
	}

	// Load config from file and parse
	parser := newConfigParser(conf, flags.Default)

	// set default log level here
	logging.SetLogLevel(defaultLogLevel)
	// create home directory
	_, err = os.Stat(conf.LitHomeDir)
	if err != nil {
		logging.Errorf("Error while creating a directory")
	}
	if os.IsNotExist(err) {
		// first time the guy is running lit, lets set tn3 to true
		os.Mkdir(conf.LitHomeDir, 0700)
		logging.Infof("Creating a new config file")
		err := createDefaultConfigFile(conf.LitHomeDir) // Source of error
		if err != nil {
			fmt.Printf("Error creating a default config file: %v", conf.LitHomeDir)
			logging.Fatal(err)
		}
	}

	if _, err := os.Stat(filepath.Join(filepath.Join(conf.LitHomeDir), "lit.conf")); os.IsNotExist(err) {
		// if there is no config file found over at the directory, create one
		if err != nil {
			fmt.Println(err)
		}
		logging.Infof("Creating a new config file")
		err := createDefaultConfigFile(filepath.Join(conf.LitHomeDir)) // Source of error
		if err != nil {
			logging.Fatal(err)
		}
	}

	conf.ConfigFile = filepath.Join(filepath.Join(conf.LitHomeDir), "lit.conf")
	// lets parse the config file provided, if any
	err = flags.NewIniParser(parser).ParseFile(conf.ConfigFile)
	if err != nil {
		_, ok := err.(*os.PathError)
		if !ok {
			logging.Fatal(err)
		}
	}
	// Parse command line options again to ensure they take precedence.
	_, err = parser.ParseArgs(os.Args) // returns invalid flags
	if err != nil {
		logging.Fatal(err)
	}

	logFilePath := filepath.Join(conf.LitHomeDir, "lit.log")
	logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	logging.SetLogFile(logFile)

	// Log Levels:
	// 5: DebugLevel prints Panics, Fatals, Errors, Warnings, Infos and Debugs
	// 4: InfoLevel  prints Panics, Fatals, Errors, Warnings and Info
	// 3: WarnLevel  prints Panics, Fatals, Errors and Warnings
	// 2: ErrorLevel prints Panics, Fatals and Errors
	// 1: FatalLevel prints Panics, Fatals
	// 0: PanicLevel prints Panics
	// Default is level 3
	// Code for tagging logs:
	// Debug -> Useful debugging information
	// Info  -> Something noteworthy happened
	// Warn  -> You should probably take a look at this
	// Error -> Something failed but I'm not quitting
	// Fatal -> Bye

	// TODO ... what's this do?
	defer logFile.Close()

	logLevel := -1
	if len(conf.LogLevel) == 1 { // -v
		logLevel = 1
	} else if len(conf.LogLevel) == 2 { // -vv
		logLevel = 2
	} else if len(conf.LogLevel) >= 3 {
		logLevel = 3
	}
	logging.SetLogLevel(logLevel)

	// Allow node with no linked wallets, for testing.
	// TODO Should update tests and disallow nodes without wallets later.
	// Keys: the litNode, and wallits, all get 32 byte keys.
	// Right now though, they all get the *same* key.  For lit as a single binary
	// now, all using the same key makes sense; could split up later.

	keyFilePath := filepath.Join(conf.LitHomeDir, defaultKeyFileName)

	// read key file (generate if not found)
	key, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		logging.Fatal(err)
	}

	return key
}
<commit_msg>Cleaned up some config init code, with less error messages.<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
)

// createDefaultConfigFile creates a config file  -- only call this if the
// config file isn't already there
func createDefaultConfigFile(destinationPath string) error {

	dest, err := os.OpenFile(filepath.Join(destinationPath, defaultConfigFilename),
		os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer dest.Close()

	writer := bufio.NewWriter(dest)
	defaultArgs := []byte("tn3=1")
	_, err = writer.Write(defaultArgs)
	if err != nil {
		return err
	}
	writer.Flush()
	return nil
}

// litSetup performs most of the setup when lit is run, such as setting
// configuration variables, reading in key data, reading and creating files if
// they're not yet there.  It takes in a config, and returns a key.
// (maybe add the key to the config?
func litSetup(conf *litConfig) *[32]byte {
	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.  Any errors aside from the
	// help message error can be ignored here since they will be caught by
	// the final parse below.

	//	usageMessage := fmt.Sprintf("Use %s -h to show usage", "./lit")

	preParser := newConfigParser(conf, flags.HelpFlag)
	_, err := preParser.ParseArgs(os.Args)
	if err != nil {
		logging.Fatal(err)
	}

	// Load config from file and parse
	parser := newConfigParser(conf, flags.Default)

	// set default log level here
	logging.SetLogLevel(defaultLogLevel)
	// create home directory
	_, err = os.Stat(conf.LitHomeDir)
	if err != nil {
		logging.Errorf("Error while creating a directory")
	}
	if os.IsNotExist(err) {
		// first time the guy is running lit, lets set tn3 to true
		os.Mkdir(conf.LitHomeDir, 0700)
		logging.Infof("Creating a new config file")
		err := createDefaultConfigFile(conf.LitHomeDir) // Source of error
		if err != nil {
			fmt.Printf("Error creating a default config file: %v", conf.LitHomeDir)
			logging.Fatal(err)
		}
	}

	if _, err := os.Stat(filepath.Join(conf.LitHomeDir, "lit.conf")); os.IsNotExist(err) {
		// if there is no config file found over at the directory, create one
		logging.Infof("Creating a new config file")
		err := createDefaultConfigFile(filepath.Join(conf.LitHomeDir)) // Source of error
		if err != nil {
			logging.Fatal(err)
		}
	}

	conf.ConfigFile = filepath.Join(conf.LitHomeDir, "lit.conf")
	// lets parse the config file provided, if any
	err = flags.NewIniParser(parser).ParseFile(conf.ConfigFile)
	if err != nil {
		_, ok := err.(*os.PathError)
		if !ok {
			logging.Fatal(err)
		}
	}
	// Parse command line options again to ensure they take precedence.
	_, err = parser.ParseArgs(os.Args) // returns invalid flags
	if err != nil {
		logging.Fatal(err)
	}

	logFilePath := filepath.Join(conf.LitHomeDir, "lit.log")
	logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	logging.SetLogFile(logFile)

	// Log Levels:
	// 5: DebugLevel prints Panics, Fatals, Errors, Warnings, Infos and Debugs
	// 4: InfoLevel  prints Panics, Fatals, Errors, Warnings and Info
	// 3: WarnLevel  prints Panics, Fatals, Errors and Warnings
	// 2: ErrorLevel prints Panics, Fatals and Errors
	// 1: FatalLevel prints Panics, Fatals
	// 0: PanicLevel prints Panics
	// Default is level 3
	// Code for tagging logs:
	// Debug -> Useful debugging information
	// Info  -> Something noteworthy happened
	// Warn  -> You should probably take a look at this
	// Error -> Something failed but I'm not quitting
	// Fatal -> Bye

	// TODO ... what's this do?
	defer logFile.Close()

	logLevel := -1
	if len(conf.LogLevel) == 1 { // -v
		logLevel = 1
	} else if len(conf.LogLevel) == 2 { // -vv
		logLevel = 2
	} else if len(conf.LogLevel) >= 3 {
		logLevel = 3
	}
	logging.SetLogLevel(logLevel)

	// Allow node with no linked wallets, for testing.
	// TODO Should update tests and disallow nodes without wallets later.
	// Keys: the litNode, and wallits, all get 32 byte keys.
	// Right now though, they all get the *same* key.  For lit as a single binary
	// now, all using the same key makes sense; could split up later.

	keyFilePath := filepath.Join(conf.LitHomeDir, defaultKeyFileName)

	// read key file (generate if not found)
	key, err := lnutil.ReadKeyFile(keyFilePath)
	if err != nil {
		logging.Fatal(err)
	}

	return key
}
<|endoftext|>


<commit_before>package worker

import (
	"context"
	"os"
	"sync"
	"time"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagerctx"
	"github.com/concourse/concourse/worker/baggageclaim"
)

// volumeSweeper is an ifrit.Runner that periodically reports and
// garbage-collects a worker's volumes
type volumeSweeper struct {
	logger             lager.Logger
	interval           time.Duration
	tsaClient          TSAClient
	baggageclaimClient baggageclaim.Client
	maxInFlight        uint16
}

func NewVolumeSweeper(
	logger lager.Logger,
	sweepInterval time.Duration,
	tsaClient TSAClient,
	bcClient baggageclaim.Client,
	maxInFlight uint16,
) *volumeSweeper {
	return &volumeSweeper{
		logger:             logger,
		interval:           sweepInterval,
		tsaClient:          tsaClient,
		baggageclaimClient: bcClient,
		maxInFlight:        maxInFlight,
	}
}

func (sweeper *volumeSweeper) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	timer := time.NewTicker(sweeper.interval)

	close(ready)

	for {
		select {
		case <-timer.C:
			sweeper.sweep(sweeper.logger.Session("tick"))

		case sig := <-signals:
			sweeper.logger.Info("sweep-cancelled-by-signal", lager.Data{"signal": sig})
			return nil
		}
	}
}

func (sweeper *volumeSweeper) sweep(logger lager.Logger) {
	ctx := lagerctx.NewContext(context.Background(), logger)

	volumes, err := sweeper.baggageclaimClient.ListVolumes(logger.Session("list-volumes"), baggageclaim.VolumeProperties{})
	if err != nil {
		logger.Error("failed-to-list-volumes", err)
	} else {
		handles := []string{}
		for _, volume := range volumes {
			handles = append(handles, volume.Handle())
		}

		err := sweeper.tsaClient.ReportVolumes(ctx, handles)
		if err != nil {
			logger.Error("failed-to-report-volumes", err)
		}
	}

	volumeHandles, err := sweeper.tsaClient.VolumesToDestroy(ctx)
	if err != nil {
		logger.Error("failed-to-get-volumes-to-destroy", err)
	} else {
		var wg sync.WaitGroup
		maxInFlight := make(chan int, sweeper.maxInFlight)

		for _, handle := range volumeHandles {
			maxInFlight <- 1
			wg.Add(1)

			go func(handle string) {
				err := sweeper.baggageclaimClient.DestroyVolume(logger.Session("destroy-volumes"), handle)
				if err != nil {
					logger.WithData(lager.Data{"handle": handle}).Error("failed-to-destroy-volume", err)
				}

				<-maxInFlight
				wg.Done()
			}(handle)
		}
		wg.Wait()
	}
}
<commit_msg>have volume sweeper pass in ctx<commit_after>package worker

import (
	"context"
	"os"
	"sync"
	"time"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagerctx"
	"github.com/concourse/concourse/worker/baggageclaim"
)

// volumeSweeper is an ifrit.Runner that periodically reports and
// garbage-collects a worker's volumes
type volumeSweeper struct {
	logger             lager.Logger
	interval           time.Duration
	tsaClient          TSAClient
	baggageclaimClient baggageclaim.Client
	maxInFlight        uint16
}

func NewVolumeSweeper(
	logger lager.Logger,
	sweepInterval time.Duration,
	tsaClient TSAClient,
	bcClient baggageclaim.Client,
	maxInFlight uint16,
) *volumeSweeper {
	return &volumeSweeper{
		logger:             logger,
		interval:           sweepInterval,
		tsaClient:          tsaClient,
		baggageclaimClient: bcClient,
		maxInFlight:        maxInFlight,
	}
}

func (sweeper *volumeSweeper) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	timer := time.NewTicker(sweeper.interval)

	close(ready)

	for {
		select {
		case <-timer.C:
			sweeper.sweep(sweeper.logger.Session("tick"))

		case sig := <-signals:
			sweeper.logger.Info("sweep-cancelled-by-signal", lager.Data{"signal": sig})
			return nil
		}
	}
}

func (sweeper *volumeSweeper) sweep(logger lager.Logger) {
	ctx := lagerctx.NewContext(context.Background(), logger)

	volumes, err := sweeper.baggageclaimClient.ListVolumes(lagerctx.NewContext(ctx, logger.Session("list-volumes")), baggageclaim.VolumeProperties{})
	if err != nil {
		logger.Error("failed-to-list-volumes", err)
	} else {
		handles := []string{}
		for _, volume := range volumes {
			handles = append(handles, volume.Handle())
		}

		err := sweeper.tsaClient.ReportVolumes(ctx, handles)
		if err != nil {
			logger.Error("failed-to-report-volumes", err)
		}
	}

	volumeHandles, err := sweeper.tsaClient.VolumesToDestroy(ctx)
	if err != nil {
		logger.Error("failed-to-get-volumes-to-destroy", err)
	} else {
		var wg sync.WaitGroup
		maxInFlight := make(chan int, sweeper.maxInFlight)

		for _, handle := range volumeHandles {
			maxInFlight <- 1
			wg.Add(1)

			go func(handle string) {
				err := sweeper.baggageclaimClient.DestroyVolume(lagerctx.NewContext(ctx, logger.Session("destroy-volumes")), handle)
				if err != nil {
					logger.WithData(lager.Data{"handle": handle}).Error("failed-to-destroy-volume", err)
				}

				<-maxInFlight
				wg.Done()
			}(handle)
		}
		wg.Wait()
	}
}
<|endoftext|>


<commit_before>package log

import (
	"log"
	"time"
)

type LogEntryType string

type LogEntry struct {
	Timestamp time.Time    `json:"ts"`
	Type      LogEntryType `json:"type"`
	Entry     string       `json:"log"`
}

const (
	LogTypeInfo  = "info"
	LogTypeError = "error"
	LogTypeDebug = "debug"
)

var LogEntries []LogEntry
var logInput chan LogEntry

func init() {
	// wait for log entries
	logInput = make(chan LogEntry)
	go func() {
		for {
			aLog := <-logInput
			LogEntries = append(LogEntries, aLog)
			for len(LogEntries) > 100 {
				LogEntries = LogEntries[1:]
			}
		}
	}()
}

func SendLog(entry string, entryType LogEntryType) {

	logInput <- LogEntry{
		Timestamp: time.Now(),
		Entry:     entry,
		Type:      entryType,
	}
	log.Printf(entry)
}
<commit_msg>Clean up console log printing<commit_after>package log

import (
	"log"
	"time"
)

type LogEntryType string

type LogEntry struct {
	Timestamp time.Time    `json:"ts"`
	Type      LogEntryType `json:"type"`
	Entry     string       `json:"log"`
}

const (
	LogTypeInfo  = "info"
	LogTypeError = "error"
	LogTypeDebug = "debug"
)

var LogEntries []LogEntry
var logInput chan LogEntry

func init() {
	// wait for log entries
	logInput = make(chan LogEntry)
	go func() {
		for {
			aLog := <-logInput
			LogEntries = append(LogEntries, aLog)
			for len(LogEntries) > 100 {
				LogEntries = LogEntries[1:]
			}
		}
	}()
}

func SendLog(entry string, entryType LogEntryType) {
	logInput <- LogEntry{
		Timestamp: time.Now(),
		Entry:     entry,
		Type:      entryType,
	}
	log.Printf("%6s: %s", entryType, entry)
}
<|endoftext|>


<commit_before>package log

import (
	"database/sql"
	"fmt"
	"time"

	"code.google.com/p/log4go"
	_ "github.com/mattn/go-sqlite3"
	//"io"
)

type Level int

const (
	FINEST Level = iota
	FINE
	DEBUG
	TRACE
	INFO
	WARNING
	ERROR
	CRITICAL
	PANIC
)

type Logger interface {
	Info(source, message string)
	Debug(source, message string)
	Warn(source, message string)
	Error(source, message string)
	Critical(source, message string)
	Panic(source, message string)
	Close() error
}

type DBLogger struct {
	db *sql.DB
}

func NewDBLogger(name string) *DBLogger {

	db, err := sql.Open("sqlite3", name)
	if err != nil {
		return nil
	}

	db.Exec(`
		create table log(time datetime not null,level tinyint not null,source text, message text)
	`)

	return &DBLogger{db}
}

func (l *DBLogger) write(lv Level, source, message string) {
	tx, err := l.db.Begin()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	stmt, err := tx.Prepare("insert into log(time,level,source,message) values(?,?,?,?)")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer stmt.Close()

	_, err = stmt.Exec(time.Now().Format("2006-01-02 15:04:05"), int(lv), source, message)

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	tx.Commit()
}

func (l *DBLogger) Close() error {
	return l.Close()
}

func (l *DBLogger) Debug(source, message string) {
	l.write(DEBUG, source, message)
	fmt.Printf("%v : %v", source, message)
}
func (l *DBLogger) Info(source, message string) {
	l.write(INFO, source, message)
}

func (l *DBLogger) Warn(source, message string) {
	l.write(WARNING, source, message)
}

func (l *DBLogger) Critical(source, message string) {
	l.write(CRITICAL, source, message)
}

func (l *DBLogger) Error(source, message string) {
	l.write(ERROR, source, message)
}

func (l *DBLogger) Panic(source, message string) {
	l.write(PANIC, source, message)
}

type FileLogger struct {
	logger4go *log4go.FileLogWriter
}

func NewFileLogger(file string) *FileLogger {
	l := log4go.NewFileLogWriter(file, true)
	l.SetRotateDaily(true)
	return &FileLogger{l}
}

func (l *FileLogger) Close() error {
	l.logger4go.Close()
	return nil
}

func (l *FileLogger) Debug(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.DEBUG, time.Now(), source, message})
}
func (l *FileLogger) Info(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.INFO, time.Now(), source, message})
}

func (l *FileLogger) Warn(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.WARNING, time.Now(), source, message})
}

func (l *FileLogger) Critical(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.CRITICAL, time.Now(), source, message})
}

func (l *FileLogger) Error(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.ERROR, time.Now(), source, message})
}

func (l *FileLogger) Panic(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.CRITICAL, time.Now(), source, message})
}
<commit_msg>Remove DBLogger for cross-platform building.<commit_after>package log

import (
	"time"

	"code.google.com/p/log4go"
	//"io"
)

type Level int

const (
	FINEST Level = iota
	FINE
	DEBUG
	TRACE
	INFO
	WARNING
	ERROR
	CRITICAL
	PANIC
)

type Logger interface {
	Info(source, message string)
	Debug(source, message string)
	Warn(source, message string)
	Error(source, message string)
	Critical(source, message string)
	Panic(source, message string)
	Close() error
}

//type DBLogger struct {
//	db *sql.DB
//}

//func NewDBLogger(name string) *DBLogger {

//	db, err := sql.Open("sqlite3", name)
//	if err != nil {
//		return nil
//	}

//	db.Exec(`
//		create table log(time datetime not null,level tinyint not null,source text, message text)
//	`)

//	return &DBLogger{db}
//}

//func (l *DBLogger) write(lv Level, source, message string) {
//	tx, err := l.db.Begin()
//	if err != nil {
//		fmt.Println(err.Error())
//		return
//	}
//	stmt, err := tx.Prepare("insert into log(time,level,source,message) values(?,?,?,?)")
//	if err != nil {
//		fmt.Println(err.Error())
//		return
//	}
//	defer stmt.Close()

//	_, err = stmt.Exec(time.Now().Format("2006-01-02 15:04:05"), int(lv), source, message)

//	if err != nil {
//		fmt.Println(err.Error())
//		return
//	}

//	tx.Commit()
//}

//func (l *DBLogger) Close() error {
//	return l.Close()
//}

//func (l *DBLogger) Debug(source, message string) {
//	l.write(DEBUG, source, message)
//	fmt.Printf("%v : %v", source, message)
//}
//func (l *DBLogger) Info(source, message string) {
//	l.write(INFO, source, message)
//}

//func (l *DBLogger) Warn(source, message string) {
//	l.write(WARNING, source, message)
//}

//func (l *DBLogger) Critical(source, message string) {
//	l.write(CRITICAL, source, message)
//}

//func (l *DBLogger) Error(source, message string) {
//	l.write(ERROR, source, message)
//}

//func (l *DBLogger) Panic(source, message string) {
//	l.write(PANIC, source, message)
//}

type FileLogger struct {
	logger4go *log4go.FileLogWriter
}

func NewFileLogger(file string) *FileLogger {
	l := log4go.NewFileLogWriter(file, true)
	l.SetRotateDaily(true)
	return &FileLogger{l}
}

func (l *FileLogger) Close() error {
	l.logger4go.Close()
	return nil
}

func (l *FileLogger) Debug(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.DEBUG, time.Now(), source, message})
}
func (l *FileLogger) Info(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.INFO, time.Now(), source, message})
}

func (l *FileLogger) Warn(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.WARNING, time.Now(), source, message})
}

func (l *FileLogger) Critical(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.CRITICAL, time.Now(), source, message})
}

func (l *FileLogger) Error(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.ERROR, time.Now(), source, message})
}

func (l *FileLogger) Panic(source, message string) {
	l.logger4go.LogWrite(&log4go.LogRecord{log4go.CRITICAL, time.Now(), source, message})
}
<|endoftext|>


<commit_before>package grohl

import (
	"fmt"
	"io"
)

// A really basic logger that builds lines and writes to any io.Writer.  This
// expects the writers to be threadsafe.
type IoLogger struct {
	stream  io.Writer
	AddTime bool
}

func (l *IoLogger) Log(data Data) error {
	return l.Write(l.BuildLog(data))
}

func (l *IoLogger) Write(data []byte) error {
	_, err := l.stream.Write(data)
	return err
}

func (l *IoLogger) BuildLog(data Data) []byte {
	return []byte(fmt.Sprintf("%s\n", BuildLog(data, l.AddTime)))
}

type ChannelLogger struct {
	channel chan Data
}

func (l *ChannelLogger) Log(data Data) error {
	l.channel <- data
	return nil
}
<commit_msg>now an IoLogger is an io.Writer<commit_after>package grohl

import (
	"fmt"
	"io"
)

// A really basic logger that builds lines and writes to any io.Writer.  This
// expects the writers to be threadsafe.
type IoLogger struct {
	stream  io.Writer
	AddTime bool
}

func (l *IoLogger) Log(data Data) error {
	_, err := l.Write(l.BuildLog(data))
	return err
}

func (l *IoLogger) Write(data []byte) (int, error) {
	return l.stream.Write(data)
}

func (l *IoLogger) BuildLog(data Data) []byte {
	return []byte(fmt.Sprintf("%s\n", BuildLog(data, l.AddTime)))
}

type ChannelLogger struct {
	channel chan Data
}

func (l *ChannelLogger) Log(data Data) error {
	l.channel <- data
	return nil
}
<|endoftext|>


<commit_before>package los

import (
	"runtime"

	"github.com/phil-mansfield/gotetra/render/io"
	rGeom "github.com/phil-mansfield/gotetra/render/geom"
	"github.com/phil-mansfield/gotetra/los/geom"
)

type Buffers struct {
	xs []rGeom.Vec
	ts []geom.Tetra
	ss []geom.Sphere
	rhos []float64
	intr []bool
	bufHs []HaloProfiles
}

func NewBuffers(file string, hd *io.SheetHeader) *Buffers {
	buf := new(Buffers)

    sw := hd.SegmentWidth
    buf.xs = make([]rGeom.Vec, hd.GridCount)
    buf.ts = make([]geom.Tetra, 6*sw*sw*sw)
    buf.ss = make([]geom.Sphere, 6*sw*sw*sw)
    buf.rhos = make([]float64, 6*sw*sw*sw)
	buf.intr = make([]bool, 6*sw*sw*sw)

	buf.Read(file, hd)
	return buf
}

func (buf *Buffers) ParallelRead(file string, hd *io.SheetHeader) {
	workers := runtime.NumCPU()
	runtime.GOMAXPROCS(workers)
	buf.read(file, hd, workers)
}

func (buf *Buffers) Read(file string, hd *io.SheetHeader) {
	buf.read(file, hd, 1)
}

func (buf *Buffers) read(file string, hd *io.SheetHeader, workers int) {
	io.ReadSheetPositionsAt(file, buf.xs)
	tw := float32(hd.TotalWidth)
	// This can only be parallelized if we sychronize afterwards. This
	// is insignificant compared to the serial I/O time.
	for i := range buf.xs {
		for j := 0; j < 3; j++ {
			if buf.xs[i][j] < hd.Origin[j] {
				buf.xs[i][j] += tw
			}
		}
	}

	out := make(chan int, workers)
	for id := 0; id < workers - 1; id++ {
		go buf.chanRead(hd, id, workers, out)
	}
	buf.chanRead(hd, workers - 1, workers, out)

	for i := 0; i < workers; i++ { <- out }
}

func (buf *Buffers) chanRead(
	hd *io.SheetHeader, id, workers int, out chan<- int,
) {
	// Remember: Grid -> All particles; Segment -> Particles that can be turned
	// into tetrahedra.
	n := hd.SegmentWidth*hd.SegmentWidth*hd.SegmentWidth
	tw := hd.TotalWidth
	tFactor := tw*tw*tw / float64(hd.Count * 6)
	idxBuf := new(rGeom.TetraIdxs)

	jump := int64(workers)
	for segIdx := int64(id); segIdx < n; segIdx += jump {
		x, y, z := coords(segIdx, hd.SegmentWidth)
		for dir := int64(0); dir < 6; dir++ {
			ti := 6 * segIdx + dir
			idxBuf.InitCartesian(x, y, z, hd.GridWidth, int(dir))
			unpackTetra(idxBuf, buf.xs, &buf.ts[ti])
			buf.ts[ti].Orient(+1)

			buf.rhos[ti] = tFactor / buf.ts[ti].Volume()

			buf.ts[ti].BoundingSphere(&buf.ss[ti])
		}
	}

	out <- id
}

func (buf *Buffers) ParallelDensity(h *HaloProfiles) {
	workers := runtime.NumCPU()
	out := make(chan int, workers)

	for id := 0; id < workers - 1; id++ {
		go buf.chanIntersect(h, id, workers, out)
	}
	buf.chanIntersect(h, workers - 1, workers, out)
	for i := 0; i < workers; i++ { <-out }

	idxs, ok := splits(buf.intr, workers)
	if ! ok { return }

	if workers > len(h.rs) { workers = len(h.rs) }
	for id := 0; id < workers - 1; id++ {
		go buf.chanDensity(h, idxs[id], idxs[id+1], out)
	}
	buf.chanDensity(h, idxs[workers-1], idxs[workers], out)
	for i := 0; i < workers; i++ { <-out }
}

func (buf *Buffers) chanDensity(
	h *HaloProfiles, start, end int, out chan <- int,
) {
	for ri := start; ri < end; ri++ {
		r := &h.rs[ri]
		for ti := 0; ti < len(buf.ts); ti++ {
			if buf.intr[ti] { r.Density(&buf.ts[ti], buf.rhos[ti]) }
		}
	}

	out <- 0
}

func (buf *Buffers) chanIntersect(
	h *HaloProfiles, id, workers int, out chan <- int,
) {
	bufLen := len(buf.ts) / workers
	bufStart, bufEnd := id * bufLen, (id + 1) * bufLen
	if id == workers - 1 { bufEnd = len(buf.ts) }
	for i := bufStart; i < bufEnd; i++ {
		buf.intr[i] = h.Sphere.SphereIntersect(&buf.ss[i]) &&
			!h.minSphere.TetraContain(&buf.ts[i])
	}
	out <- id
}

func splits(intr []bool, workers int) (idxs []int, ok bool) {
	n := 0
	for _, ok := range intr {
		if ok { n++ }
	}

	if n == 0 { return nil, false }
	idxs = make([]int, workers + 1)

	spacing := n / workers
	// When m == spacing, insert a split at index j and reset m.
	m, j := 0, 1
	for i, ok := range intr {
		if ok {
			m++
			if m == spacing {
				idxs[j] = i + 1
				j++
				m = 0
				if j == workers { break }
			}
		}
	}

	for j = j; j <= workers ; j++ {
		idxs[j] = len(intr)
	}

	return idxs, true
}

func coords(idx, cells int64) (x, y, z int64) {
    x = idx % cells
    y = (idx % (cells * cells)) / cells
    z = idx / (cells * cells)
    return x, y, z
}

func index(x, y, z, cells int64) int64 {
    return x + y * cells + z * cells * cells
}

func unpackTetra(idxs *rGeom.TetraIdxs, xs []rGeom.Vec, t *geom.Tetra) {
    for i := 0; i < 4; i++ {
		t[i] = geom.Vec(xs[idxs[i]])
    }
}

// WrapHalo updates the coordinates of a slice of HaloProfiles so that they
// as close to the given sheet as periodic boundary conditions will allow.
func WrapHalo(hps []*HaloProfiles, hd *io.SheetHeader) {
	tw := float32(hd.TotalWidth)
	newC := &geom.Vec{}
	for i := range hps {
		h := hps[i]
		for j := 0; j < 3; j++ {
			if h.cCopy[j] + h.R < hd.Origin[j] {
				newC[j] = h.cCopy[j] + tw
			} else {
				newC[j] = h.cCopy[j]
			}
		}
		h.ChangeCenter(newC)
	}
}
<commit_msg>Reset channel allocation strategy anf also skipped any NaN/Inf halo densities.<commit_after>package los

import (
	"math"
	"runtime"

	"github.com/phil-mansfield/gotetra/render/io"
	rGeom "github.com/phil-mansfield/gotetra/render/geom"
	"github.com/phil-mansfield/gotetra/los/geom"
)

type Buffers struct {
	xs []rGeom.Vec
	ts []geom.Tetra
	ss []geom.Sphere
	rhos []float64
	intr []bool
	bufHs []HaloProfiles
}

func NewBuffers(file string, hd *io.SheetHeader) *Buffers {
	buf := new(Buffers)

    sw := hd.SegmentWidth
    buf.xs = make([]rGeom.Vec, hd.GridCount)
    buf.ts = make([]geom.Tetra, 6*sw*sw*sw)
    buf.ss = make([]geom.Sphere, 6*sw*sw*sw)
    buf.rhos = make([]float64, 6*sw*sw*sw)
	buf.intr = make([]bool, 6*sw*sw*sw)

	buf.Read(file, hd)
	return buf
}

func (buf *Buffers) ParallelRead(file string, hd *io.SheetHeader) {
	workers := runtime.NumCPU()
	runtime.GOMAXPROCS(workers)
	buf.read(file, hd, workers)
}

func (buf *Buffers) Read(file string, hd *io.SheetHeader) {
	buf.read(file, hd, 1)
}

func (buf *Buffers) read(file string, hd *io.SheetHeader, workers int) {
	io.ReadSheetPositionsAt(file, buf.xs)
	tw := float32(hd.TotalWidth)
	// This can only be parallelized if we sychronize afterwards. This
	// is insignificant compared to the serial I/O time.
	for i := range buf.xs {
		for j := 0; j < 3; j++ {
			if buf.xs[i][j] < hd.Origin[j] {
				buf.xs[i][j] += tw
			}
		}
	}

	out := make(chan int, workers)
	for id := 0; id < workers - 1; id++ {
		go buf.chanRead(hd, id, workers, out)
	}
	buf.chanRead(hd, workers - 1, workers, out)

	for i := 0; i < workers; i++ { <- out }
}

func (buf *Buffers) chanRead(
	hd *io.SheetHeader, id, workers int, out chan<- int,
) {
	// Remember: Grid -> All particles; Segment -> Particles that can be turned
	// into tetrahedra.
	n := hd.SegmentWidth*hd.SegmentWidth*hd.SegmentWidth
	tw := hd.TotalWidth
	tFactor := tw*tw*tw / float64(hd.Count * 6)
	idxBuf := new(rGeom.TetraIdxs)

	jump := int64(workers)
	for segIdx := int64(id); segIdx < n; segIdx += jump {
		x, y, z := coords(segIdx, hd.SegmentWidth)
		for dir := int64(0); dir < 6; dir++ {
			ti := 6 * segIdx + dir
			idxBuf.InitCartesian(x, y, z, hd.GridWidth, int(dir))
			unpackTetra(idxBuf, buf.xs, &buf.ts[ti])
			buf.ts[ti].Orient(+1)

			buf.rhos[ti] = tFactor / buf.ts[ti].Volume()

			buf.ts[ti].BoundingSphere(&buf.ss[ti])
		}
	}

	out <- id
}

func (buf *Buffers) ParallelDensity(h *HaloProfiles) {
	workers := runtime.NumCPU()
	out := make(chan int, workers)

	for id := 0; id < workers - 1; id++ {
		go buf.chanIntersect(h, id, workers, out)
	}
	buf.chanIntersect(h, workers - 1, workers, out)
	for i := 0; i < workers; i++ { <-out }

	if workers > len(h.rs) { workers = len(h.rs) }
	for id := 0; id < workers - 1; id++ {
		go buf.chanDensity(h, id, workers, out)
	}
	buf.chanDensity(h, workers - 1, workers, out)
	for i := 0; i < workers; i++ { <-out }
}

func (buf *Buffers) chanDensity(
	h *HaloProfiles, id, workers int, out chan <- int,
) {
	for ri := id; ri < len(h.rs); ri += workers {
		r := &h.rs[ri]
		for ti := 0; ti < len(buf.ts); ti++ {
			if math.IsNaN(buf.rhos[ti]) || math.IsInf(buf.rhos[ti], 0) {
				continue
			}

			if buf.intr[ti] { r.Density(&buf.ts[ti], buf.rhos[ti]) }
		}
	}
	out <- id
}

func (buf *Buffers) chanIntersect(
	h *HaloProfiles, id, workers int, out chan <- int,
) {
	bufLen := len(buf.ts) / workers
	bufStart, bufEnd := id * bufLen, (id + 1) * bufLen
	if id == workers - 1 { bufEnd = len(buf.ts) }
	for i := bufStart; i < bufEnd; i++ {
		buf.intr[i] = h.Sphere.SphereIntersect(&buf.ss[i]) &&
			!h.minSphere.TetraContain(&buf.ts[i])
	}
	out <- id
}

func splits(intr []bool, workers int) (idxs []int, ok bool) {
	n := 0
	for _, ok := range intr {
		if ok { n++ }
	}

	if n == 0 { return nil, false }
	idxs = make([]int, workers + 1)

	spacing := n / workers
	// When m == spacing, insert a split at index j and reset m.
	m, j := 0, 1
	for i, ok := range intr {
		if ok {
			m++
			if m == spacing {
				idxs[j] = i + 1
				j++
				m = 0
				if j == workers { break }
			}
		}
	}

	for j = j; j <= workers ; j++ {
		idxs[j] = len(intr)
	}

	return idxs, true
}

func coords(idx, cells int64) (x, y, z int64) {
    x = idx % cells
    y = (idx % (cells * cells)) / cells
    z = idx / (cells * cells)
    return x, y, z
}

func index(x, y, z, cells int64) int64 {
    return x + y * cells + z * cells * cells
}

func unpackTetra(idxs *rGeom.TetraIdxs, xs []rGeom.Vec, t *geom.Tetra) {
    for i := 0; i < 4; i++ {
		t[i] = geom.Vec(xs[idxs[i]])
    }
}

// WrapHalo updates the coordinates of a slice of HaloProfiles so that they
// as close to the given sheet as periodic boundary conditions will allow.
func WrapHalo(hps []*HaloProfiles, hd *io.SheetHeader) {
	tw := float32(hd.TotalWidth)
	newC := &geom.Vec{}
	for i := range hps {
		h := hps[i]
		for j := 0; j < 3; j++ {
			if h.cCopy[j] + h.R < hd.Origin[j] {
				newC[j] = h.cCopy[j] + tw
			} else {
				newC[j] = h.cCopy[j]
			}
		}
		h.ChangeCenter(newC)
	}
}
<|endoftext|>


<commit_before>package prefer

import (
	"bufio"
	"os"
)

type Loader interface {
	Load(identifier string) ([]byte, error)
}

func NewLoader(identifier string) (loader Loader, err error) {
	switch identifier {
	default:
		return loader, nil
	}
}

type FileLoader struct{}

func (loader FileLoader) Load(identifier string) (result []byte, err error) {
	file, err := os.Open(identifier)
	check(err)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		result = append(result, scanner.Bytes()...)
	}

	return result, err
}
<commit_msg>Make FileLoader the default.<commit_after>package prefer

import (
	"bufio"
	"os"
)

type Loader interface {
	Load(identifier string) ([]byte, error)
}

func NewLoader(identifier string) (Loader, error) {
	switch identifier {
	default:
		return FileLoader{}, nil
	}
}

type FileLoader struct{}

func (loader FileLoader) Load(identifier string) (result []byte, err error) {
	file, err := os.Open(identifier)
	check(err)
	defer file.Close()

	for scanner := bufio.NewScanner(file); scanner.Scan(); {
		result = append(result, scanner.Bytes()...)
	}

	return result, err
}
<|endoftext|>


<commit_before>package log

import (
``	"io"
	"os"

	"github.com/Sirupsen/logrus"
)

var (
	logger	*logrus.Entry
)

func init() {
	logger = logrus.StandardLogger().WithFields(logrus.Fields{})
	logrus.SetOutput(os.Stdout)
}

func Context(context interface{}) *logrus.Entry {
	return logger.WithField("context", context)
}

func SetOutput(out io.Writer) {
	logrus.SetOutput(out)
}

func SetFormatter(formatter logrus.Formatter) {
	logrus.SetFormatter(formatter)
}

func SetLevel(level string) {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return
	}
	logrus.SetLevel(lvl)
}

func GetLevel() logrus.Level {
	return logrus.GetLevel()
}

func AddHook(hook logrus.Hook) {
	logrus.AddHook(hook)
}

func WithError(err error) *logrus.Entry {
	return logger.WithError(err)
}

func WithField(key string, value interface{}) *logrus.Entry {
	return logger.WithField(key, value)
}

func WithFields(fields logrus.Fields) *logrus.Entry {
	return logger.WithFields(fields)
}

func Debug(args ...interface{}) {
	logger.Debug(args...)
}

func Print(args ...interface{}) {
	logger.Print(args...)
}

func Info(args ...interface{}) {
	logger.Info(args...)
}

func Warn(args ...interface{}) {
	logger.Warn(args...)
}

func Warning(args ...interface{}) {
	logger.Warning(args...)
}

func Error(args ...interface{}) {
	logger.Error(args...)
}

func Panic(args ...interface{}) {
	logger.Panic(args...)
}

func Fatal(args ...interface{}) {
	logger.Fatal(args...)
}

func Debugf(format string, args ...interface{}) {
	logger.Debugf(format, args...)
}

func Printf(format string, args ...interface{}) {
	logger.Printf(format, args...)
}

func Infof(format string, args ...interface{}) {
	logger.Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
	logger.Warnf(format, args...)
}

func Warningf(format string, args ...interface{}) {
	logger.Warningf(format, args...)
}

func Errorf(format string, args ...interface{}) {
	logger.Errorf(format, args...)
}

func Panicf(format string, args ...interface{}) {
	logger.Panicf(format, args...)
}

func Fatalf(format string, args ...interface{}) {
	logger.Fatalf(format, args...)
}

func Debugln(args ...interface{}) {
	logger.Debugln(args...)
}

func Println(args ...interface{}) {
	logger.Println(args...)
}

func Infoln(args ...interface{}) {
	logger.Infoln(args...)
}

func Warnln(args ...interface{}) {
	logger.Warnln(args...)
}

func Warningln(args ...interface{}) {
	logger.Warningln(args...)
}

func Errorln(args ...interface{}) {
	logger.Errorln(args...)
}

func Panicln(args ...interface{}) {
	logger.Panicln(args...)
}

func Fatalln(args ...interface{}) {
	logger.Fatalln(args...)
}

func Writer() *io.PipeWriter {
	return WriterLevel(logrus.InfoLevel)
}

func WriterLevel(level logrus.Level) *io.PipeWriter {
	return logger.WriterLevel(level)
}
<commit_msg>Changed logger<commit_after>package log

import (
	"io"
	"os"

	"github.com/Sirupsen/logrus"
)

var (
	logger	*logrus.Entry
)

func init() {
	logger = logrus.StandardLogger().WithFields(logrus.Fields{})
	logrus.SetOutput(os.Stdout)
}

func Context(context interface{}) *logrus.Entry {
	return logger.WithField("context", context)
}

func SetOutput(out io.Writer) {
	logrus.SetOutput(out)
}

func SetFormatter(formatter logrus.Formatter) {
	logrus.SetFormatter(formatter)
}

func SetLevel(level string) {
	lvl, err := logrus.ParseLevel(level)
	if err != nil {
		return
	}
	logrus.SetLevel(lvl)
}

func GetLevel() logrus.Level {
	return logrus.GetLevel()
}

func AddHook(hook logrus.Hook) {
	logrus.AddHook(hook)
}

func WithError(err error) *logrus.Entry {
	return logger.WithError(err)
}

func WithField(key string, value interface{}) *logrus.Entry {
	return logger.WithField(key, value)
}

func WithFields(fields logrus.Fields) *logrus.Entry {
	return logger.WithFields(fields)
}

func Debug(args ...interface{}) {
	logger.Debug(args...)
}

func Print(args ...interface{}) {
	logger.Print(args...)
}

func Info(args ...interface{}) {
	logger.Info(args...)
}

func Warn(args ...interface{}) {
	logger.Warn(args...)
}

func Warning(args ...interface{}) {
	logger.Warning(args...)
}

func Error(args ...interface{}) {
	logger.Error(args...)
}

func Panic(args ...interface{}) {
	logger.Panic(args...)
}

func Fatal(args ...interface{}) {
	logger.Fatal(args...)
}

func Debugf(format string, args ...interface{}) {
	logger.Debugf(format, args...)
}

func Printf(format string, args ...interface{}) {
	logger.Printf(format, args...)
}

func Infof(format string, args ...interface{}) {
	logger.Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
	logger.Warnf(format, args...)
}

func Warningf(format string, args ...interface{}) {
	logger.Warningf(format, args...)
}

func Errorf(format string, args ...interface{}) {
	logger.Errorf(format, args...)
}

func Panicf(format string, args ...interface{}) {
	logger.Panicf(format, args...)
}

func Fatalf(format string, args ...interface{}) {
	logger.Fatalf(format, args...)
}

func Debugln(args ...interface{}) {
	logger.Debugln(args...)
}

func Println(args ...interface{}) {
	logger.Println(args...)
}

func Infoln(args ...interface{}) {
	logger.Infoln(args...)
}

func Warnln(args ...interface{}) {
	logger.Warnln(args...)
}

func Warningln(args ...interface{}) {
	logger.Warningln(args...)
}

func Errorln(args ...interface{}) {
	logger.Errorln(args...)
}

func Panicln(args ...interface{}) {
	logger.Panicln(args...)
}

func Fatalln(args ...interface{}) {
	logger.Fatalln(args...)
}

func Writer() *io.PipeWriter {
	return WriterLevel(logrus.InfoLevel)
}

func WriterLevel(level logrus.Level) *io.PipeWriter {
	return logger.WriterLevel(level)
}
<|endoftext|>


<commit_before>/*
Package log provides an logger that logs to the $LOG log file. If $LOG is not provided, stderr is used.
$LOGPREF is the logging prefix and $LOGFLG is the logging flag. If $LOGFLG isn't provided, log.LstdFlags is used.
See standard go log package for more info.
*/
package log

import (
	"fmt"
	golog "log"
	"os"
	"strconv"
)

var logger *golog.Logger

func init() {
	var (
		logFileName = os.Getenv("$LOG")
		logPref     = os.Getenv("$LOGPREF")
		logFlg      = os.Getenv("$LOGFLG")
		logFlgI     int
		logFile     *os.File
		openErr     error
		atoiErr     error
	)

	if logFileName != "" {
		logFile, openErr = os.Create(logFileName)
		if openErr != nil {
			logFile = os.Stderr
		}
	} else {
		logFile = os.Stderr
	}

	if logFlg != "" {
		logFlgI, atoiErr = strconv.Atoi(logFlg)
	}
	if logFlg == "" || atoiErr != nil {
		logFlgI = golog.LstdFlags
	}

	logger = golog.New(logFile, logPref, logFlgI)

	if openErr != nil {
		fmt.Printf("Error opening log file with Name: %v Error: %v\n", logFileName, openErr)
	}
	if atoiErr != nil {
		fmt.Printf("Bad Log Flag: %v Error: %v\n ", logFlg, atoiErr)
	}
}

/*
Logger returns the rns logger
*/
func Logger() *golog.Logger {
	return logger
}
<commit_msg>Changed log from env config to using a Config function compatible with command line switch configuration.<commit_after>/*
Package log provides a configured instance of a log package logger that is shared within an executable.
Typically the executable will provide -log, -logpref and -logflg command line switches containing respectively the log file name, log prefix and log flag values.
The executable's init will parse these command line flags and then configure this log instance with them.

See standard go log package for more info.
*/
package log

import (
	golog "log"
	"os"
)

var logger *golog.Logger

/*
Config initializes the shared log instance. It should be called from an executable's init function. If it is not called, a default log instance that logs to os.Stderr is created.
*/
func Config(logname, logpref string, logflg int) {
	var (
		logFile *os.File
		openErr error
	)

	if logname != "" {
		logFile, openErr = os.Create(logname)
		if openErr != nil {
			logFile = os.Stderr
		}
	} else {
		logFile = os.Stderr
	}

	logger = golog.New(logFile, logpref, logflg)

	if openErr != nil {
		logger.Printf("Logging to stderr because opening log file with Name: %v failed with Error: %v\n", logname, openErr)
	}
}

/*
Logger returns the shared logger
*/
func Logger() *golog.Logger {
	if logger == nil {
		Config("", "", 0)
	}
	return logger
}
<|endoftext|>