<commit_before>package bittrex

import (
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type client struct {
	apiKey     string
	apiSecret  string
	httpClient *http.Client
}

// NewClient return a new Bittrex HTTP client
func NewClient(apiKey, apiSecret string) (c *client) {
	return &client{apiKey, apiSecret, &http.Client{}}
}

// NewClientWithCustomHttpConfig returns a new Bittrex HTTP client using the predefined http client
func NewClientWithCustomHttpConfig(apiKey, apiSecret string, httpClient *http.Client) (c *client) {
	return &client{apiKey, apiSecret, httpClient}
}

// doTimeoutRequest do a HTTP request with timeout
func (c *client) doTimeoutRequest(timer *time.Timer, req *http.Request) (*http.Response, error) {
	// Do the request in the background so we can check the timeout
	type result struct {
		resp *http.Response
		err  error
	}
	done := make(chan result, 1)
	go func() {
		resp, err := c.httpClient.Do(req)
		done <- result{resp, err}
	}()
	// Wait for the read or the timeout
	select {
	case r := <-done:
		return r.resp, r.err
	case <-timer.C:
		return nil, errors.New("timeout on reading data from Bittrex API")
	}
}

// do prepare and process HTTP request to Bittrex API
func (c *client) do(method string, ressource string, payload string, authNeeded bool) (response []byte, err error) {
	connectTimer := time.NewTimer(DEFAULT_HTTPCLIENT_TIMEOUT * time.Second)

	var rawurl string
	if strings.HasPrefix(ressource, "http") {
		rawurl = ressource
	} else {
		rawurl = fmt.Sprintf("%s%s/%s", API_BASE, API_VERSION, ressource)
	}

	req, err := http.NewRequest(method, rawurl, strings.NewReader(payload))
	if err != nil {
		return
	}
	if method == "POST" || method == "PUT" {
		req.Header.Add("Content-Type", "application/json;charset=utf-8")
	}
	req.Header.Add("Accept", "application/json")

	// Auth
	if authNeeded {
		if len(c.apiKey) == 0 || len(c.apiSecret) == 0 {
			err = errors.New("You need to set API Key and API Secret to call this method")
			return
		}
		nonce := time.Now().UnixNano()
		q := req.URL.Query()
		q.Set("apikey", c.apiKey)
		q.Set("nonce", fmt.Sprintf("%d", nonce))
		req.URL.RawQuery = q.Encode()
		mac := hmac.New(sha512.New, []byte(c.apiSecret))
		_, err = mac.Write([]byte(req.URL.String()))
		sig := hex.EncodeToString(mac.Sum(nil))
		req.Header.Add("apisign", sig)
	}

	resp, err := c.doTimeoutRequest(connectTimer, req)
	if err != nil {
		return
	}

	defer resp.Body.Close()
	response, err = ioutil.ReadAll(resp.Body)
	//fmt.Println(fmt.Sprintf("reponse %s", response), err)
	if err != nil {
		return response, err
	}
	if resp.StatusCode != 200 {
		err = errors.New(resp.Status)
	}
	return response, err
}
<commit_msg>added httpTimeout field to client struct<commit_after>package bittrex

import (
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type client struct {
	apiKey      string
	apiSecret   string
	httpClient  *http.Client
	httpTimeout time.Duration
}

// NewClient return a new Bittrex HTTP client
func NewClient(apiKey, apiSecret string) (c *client) {
	return &client{apiKey, apiSecret, &http.Client{}, 30 * time.Second}
}

// NewClientWithCustomHttpConfig returns a new Bittrex HTTP client using the predefined http client
func NewClientWithCustomHttpConfig(apiKey, apiSecret string, httpClient *http.Client) (c *client) {
	timeout := httpClient.Timeout
	return &client{apiKey, apiSecret, httpClient, timeout}
}

// doTimeoutRequest do a HTTP request with timeout
func (c *client) doTimeoutRequest(timer *time.Timer, req *http.Request) (*http.Response, error) {
	// Do the request in the background so we can check the timeout
	type result struct {
		resp *http.Response
		err  error
	}
	done := make(chan result, 1)
	go func() {
		resp, err := c.httpClient.Do(req)
		done <- result{resp, err}
	}()
	// Wait for the read or the timeout
	select {
	case r := <-done:
		return r.resp, r.err
	case <-timer.C:
		return nil, errors.New("timeout on reading data from Bittrex API")
	}
}

// do prepare and process HTTP request to Bittrex API
func (c *client) do(method string, ressource string, payload string, authNeeded bool) (response []byte, err error) {
	connectTimer := time.NewTimer(c.httpTimeout)

	var rawurl string
	if strings.HasPrefix(ressource, "http") {
		rawurl = ressource
	} else {
		rawurl = fmt.Sprintf("%s%s/%s", API_BASE, API_VERSION, ressource)
	}

	req, err := http.NewRequest(method, rawurl, strings.NewReader(payload))
	if err != nil {
		return
	}
	if method == "POST" || method == "PUT" {
		req.Header.Add("Content-Type", "application/json;charset=utf-8")
	}
	req.Header.Add("Accept", "application/json")

	// Auth
	if authNeeded {
		if len(c.apiKey) == 0 || len(c.apiSecret) == 0 {
			err = errors.New("You need to set API Key and API Secret to call this method")
			return
		}
		nonce := time.Now().UnixNano()
		q := req.URL.Query()
		q.Set("apikey", c.apiKey)
		q.Set("nonce", fmt.Sprintf("%d", nonce))
		req.URL.RawQuery = q.Encode()
		mac := hmac.New(sha512.New, []byte(c.apiSecret))
		_, err = mac.Write([]byte(req.URL.String()))
		sig := hex.EncodeToString(mac.Sum(nil))
		req.Header.Add("apisign", sig)
	}

	resp, err := c.doTimeoutRequest(connectTimer, req)
	if err != nil {
		return
	}

	defer resp.Body.Close()
	response, err = ioutil.ReadAll(resp.Body)
	//fmt.Println(fmt.Sprintf("reponse %s", response), err)
	if err != nil {
		return response, err
	}
	if resp.StatusCode != 200 {
		err = errors.New(resp.Status)
	}
	return response, err
}
<|endoftext|>


<commit_before>package cayley

import (
	"github.com/google/cayley/graph"
	_ "github.com/google/cayley/graph/memstore"
	"github.com/google/cayley/graph/path"
	"github.com/google/cayley/quad"
	_ "github.com/google/cayley/writer"
)

type Iterator graph.Iterator
type QuadStore graph.QuadStore
type QuadWriter graph.QuadWriter

type Path path.Path

var (
	StartMorphism = path.StartMorphism
	StartPath     = path.StartPath

	RawNext        = graph.Next
	NewTransaction = graph.NewTransaction
)

type Handle struct {
	graph.QuadStore
	graph.QuadWriter
}

func Quad(subject, predicate, object, label string) quad.Quad {
	return quad.Quad{subject, predicate, object, label}
}

func NewGraph(name, dbpath string, opts graph.Options) (*Handle, error) {
	qs, err := graph.NewQuadStore(name, dbpath, opts)
	if err != nil {
		return nil, err
	}
	qw, err := graph.NewQuadWriter("single", qs, nil)
	if err != nil {
		return nil, err
	}
	return &Handle{qs, qw}, nil
}

func NewMemoryGraph() (*Handle, error) {
	return NewGraph("memstore", "", nil)
}

func (h *Handle) Close() {
	h.QuadStore.Close()
	h.QuadWriter.Close()
}
<commit_msg>add Triple function<commit_after>package cayley

import (
	"github.com/google/cayley/graph"
	_ "github.com/google/cayley/graph/memstore"
	"github.com/google/cayley/graph/path"
	"github.com/google/cayley/quad"
	_ "github.com/google/cayley/writer"
)

type Iterator graph.Iterator
type QuadStore graph.QuadStore
type QuadWriter graph.QuadWriter

type Path path.Path

var (
	StartMorphism = path.StartMorphism
	StartPath     = path.StartPath

	RawNext        = graph.Next
	NewTransaction = graph.NewTransaction
)

type Handle struct {
	graph.QuadStore
	graph.QuadWriter
}

func Triple(subject, predicate, object string) quad.Quad {
	return quad.Quad{subject, predicate, object, ""}
}

func Quad(subject, predicate, object, label string) quad.Quad {
	return quad.Quad{subject, predicate, object, label}
}

func NewGraph(name, dbpath string, opts graph.Options) (*Handle, error) {
	qs, err := graph.NewQuadStore(name, dbpath, opts)
	if err != nil {
		return nil, err
	}
	qw, err := graph.NewQuadWriter("single", qs, nil)
	if err != nil {
		return nil, err
	}
	return &Handle{qs, qw}, nil
}

func NewMemoryGraph() (*Handle, error) {
	return NewGraph("memstore", "", nil)
}

func (h *Handle) Close() {
	h.QuadStore.Close()
	h.QuadWriter.Close()
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/yosisa/fluxion/buffer"
	"github.com/yosisa/fluxion/engine"
	"github.com/yosisa/fluxion/event"
)

var eventCh = make(chan *event.Event, 100)

type ConfigFeeder func(interface{}) error

type PluginFactory func() Plugin

type Plugin interface {
	Init(ConfigFeeder) error
	Start() error
}

type OutputPlugin interface {
	Plugin
	Encode(*event.Record) (buffer.Sizer, error)
	Write([]buffer.Sizer) (int, error)
}

type FilterPlugin interface {
	Plugin
	Filter(*event.Record) (*event.Record, error)
}

type plugin struct {
	f     PluginFactory
	units map[int32]*execUnit
}

func New(f PluginFactory) *plugin {
	Log.Name = strings.SplitN(os.Args[0], "-", 2)[1]
	Log.Prefix = fmt.Sprintf("[%s] ", Log.Name)
	return &plugin{
		f:     f,
		units: make(map[int32]*execUnit),
	}
}

func (p *plugin) Run() {
	Log.Infof("Plugin created")
	go eventSender()
	p.eventListener()
}

func (p *plugin) eventListener() {
	dec := event.NewDecoder(os.Stdin)
	for {
		var ev event.Event
		if err := dec.Decode(&ev); err != nil {
			if err == io.EOF {
				return
			} else {
				Log.Warning(err)
				continue
			}
		}

		unit, ok := p.units[ev.UnitID]
		if !ok {
			unit = newExecUnit(ev.UnitID, p.f())
			p.units[ev.UnitID] = unit
		}
		unit.eventCh <- &ev
	}
}

type execUnit struct {
	ID      int32
	p       Plugin
	eventCh chan *event.Event
}

func newExecUnit(id int32, p Plugin) *execUnit {
	u := &execUnit{
		ID:      id,
		p:       p,
		eventCh: make(chan *event.Event, 100),
	}
	go u.eventLoop()
	return u
}

func (u *execUnit) eventLoop() {
	op, isOutputPlugin := u.p.(OutputPlugin)
	fp, isFilterPlugin := u.p.(FilterPlugin)
	var buf *buffer.Memory

	for ev := range u.eventCh {
		switch ev.Name {
		case "set_buffer":
			if isOutputPlugin {
				buf = buffer.NewMemory(ev.Buffer, op)
			}
		case "config":
			b := ev.Payload.([]byte)
			f := func(v interface{}) error {
				return engine.Decode(b, v)
			}
			if err := u.p.Init(f); err != nil {
				Log.Critical("Failed to configure: ", err)
				return
			}
		case "start":
			if err := u.p.Start(); err != nil {
				Log.Critical("Failed to start: ", err)
				return
			}
		case "record":
			switch {
			case isFilterPlugin:
				r, err := fp.Filter(ev.Record)
				if err != nil {
					Log.Warning("Filter error: ", err)
					continue
				}
				send(&event.Event{UnitID: u.ID, Name: "next_filter", Record: r})
			case isOutputPlugin:
				s, err := op.Encode(ev.Record)
				if err != nil {
					Log.Warning("Encode error: ", err)
					continue
				}
				if err = buf.Push(s); err != nil {
					Log.Warning("Buffering error: ", err)
				}
			}
		}
	}
}

func Emit(record *event.Record) {
	send(&event.Event{Name: "record", Record: record})
}

func send(ev *event.Event) {
	eventCh <- ev
}

func eventSender() {
	encoder := event.NewEncoder(os.Stdout)
	for ev := range eventCh {
		if err := encoder.Encode(ev); err != nil {
			if err == io.EOF {
				return
			}
			Log.Warning("Failed to send event: ", err)
		}
	}
}
<commit_msg>Make filter plugins able to drop record<commit_after>package plugin

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/yosisa/fluxion/buffer"
	"github.com/yosisa/fluxion/engine"
	"github.com/yosisa/fluxion/event"
)

var eventCh = make(chan *event.Event, 100)

type ConfigFeeder func(interface{}) error

type PluginFactory func() Plugin

type Plugin interface {
	Init(ConfigFeeder) error
	Start() error
}

type OutputPlugin interface {
	Plugin
	Encode(*event.Record) (buffer.Sizer, error)
	Write([]buffer.Sizer) (int, error)
}

type FilterPlugin interface {
	Plugin
	Filter(*event.Record) (*event.Record, error)
}

type plugin struct {
	f     PluginFactory
	units map[int32]*execUnit
}

func New(f PluginFactory) *plugin {
	Log.Name = strings.SplitN(os.Args[0], "-", 2)[1]
	Log.Prefix = fmt.Sprintf("[%s] ", Log.Name)
	return &plugin{
		f:     f,
		units: make(map[int32]*execUnit),
	}
}

func (p *plugin) Run() {
	Log.Infof("Plugin created")
	go eventSender()
	p.eventListener()
}

func (p *plugin) eventListener() {
	dec := event.NewDecoder(os.Stdin)
	for {
		var ev event.Event
		if err := dec.Decode(&ev); err != nil {
			if err == io.EOF {
				return
			} else {
				Log.Warning(err)
				continue
			}
		}

		unit, ok := p.units[ev.UnitID]
		if !ok {
			unit = newExecUnit(ev.UnitID, p.f())
			p.units[ev.UnitID] = unit
		}
		unit.eventCh <- &ev
	}
}

type execUnit struct {
	ID      int32
	p       Plugin
	eventCh chan *event.Event
}

func newExecUnit(id int32, p Plugin) *execUnit {
	u := &execUnit{
		ID:      id,
		p:       p,
		eventCh: make(chan *event.Event, 100),
	}
	go u.eventLoop()
	return u
}

func (u *execUnit) eventLoop() {
	op, isOutputPlugin := u.p.(OutputPlugin)
	fp, isFilterPlugin := u.p.(FilterPlugin)
	var buf *buffer.Memory

	for ev := range u.eventCh {
		switch ev.Name {
		case "set_buffer":
			if isOutputPlugin {
				buf = buffer.NewMemory(ev.Buffer, op)
			}
		case "config":
			b := ev.Payload.([]byte)
			f := func(v interface{}) error {
				return engine.Decode(b, v)
			}
			if err := u.p.Init(f); err != nil {
				Log.Critical("Failed to configure: ", err)
				return
			}
		case "start":
			if err := u.p.Start(); err != nil {
				Log.Critical("Failed to start: ", err)
				return
			}
		case "record":
			switch {
			case isFilterPlugin:
				r, err := fp.Filter(ev.Record)
				if err != nil {
					Log.Warning("Filter error: ", err)
					r = ev.Record
				}
				if r != nil {
					send(&event.Event{UnitID: u.ID, Name: "next_filter", Record: r})
				}
			case isOutputPlugin:
				s, err := op.Encode(ev.Record)
				if err != nil {
					Log.Warning("Encode error: ", err)
					continue
				}
				if err = buf.Push(s); err != nil {
					Log.Warning("Buffering error: ", err)
				}
			}
		}
	}
}

func Emit(record *event.Record) {
	send(&event.Event{Name: "record", Record: record})
}

func send(ev *event.Event) {
	eventCh <- ev
}

func eventSender() {
	encoder := event.NewEncoder(os.Stdout)
	for ev := range eventCh {
		if err := encoder.Encode(ev); err != nil {
			if err == io.EOF {
				return
			}
			Log.Warning("Failed to send event: ", err)
		}
	}
}
<|endoftext|>


<commit_before>// The GsBot package contains some useful utilites for working with the
// steam package. It implements authentication with sentries, server lists and
// logging messages and events.
//
// Every module is optional and requires an instance of the GsBot struct.
// Should a module have a `HandlePacket` method, you must register it with the
// steam.Client with `RegisterPacketHandler`. Any module with a `HandleEvent`
// method must be integrated into your event loop and should be called for each
// event you receive.
package gsbot

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"path"
	"reflect"
	"time"

	"github.com/Philipp15b/go-steam"
	"github.com/Philipp15b/go-steam/netutil"
	"github.com/Philipp15b/go-steam/protocol"
	"github.com/davecgh/go-spew/spew"
)

// Base structure holding common data among GsBot modules.
type GsBot struct {
	Client *steam.Client
	Log    *log.Logger
}

// Creates a new GsBot with a new steam.Client where logs are written to stdout.
func Default() *GsBot {
	return &GsBot{
		steam.NewClient(),
		log.New(os.Stdout, "", 0),
	}
}

// This module handles authentication. It logs on automatically after a ConnectedEvent
// and saves the sentry data to a file which is also used for logon if available.
// If you're logging on for the first time Steam may require an authcode. You can then
// connect again with the new logon details.
type Auth struct {
	bot             *GsBot
	details         *LogOnDetails
	sentryPath      string
	machineAuthHash []byte
}

func NewAuth(bot *GsBot, details *LogOnDetails, sentryPath string) *Auth {
	return &Auth{
		bot:        bot,
		details:    details,
		sentryPath: sentryPath,
	}
}

type LogOnDetails struct {
	Username string
	Password string
	AuthCode string
}

// This is called automatically after every ConnectedEvent, but must be called once again manually
// with an authcode if Steam requires it when logging on for the first time.
func (a *Auth) LogOn(details *LogOnDetails) {
	a.details = details
	sentry, err := ioutil.ReadFile(a.sentryPath)
	if err != nil {
		a.bot.Log.Printf("Error loading sentry file from path %v - This is normal if you're logging in for the first time.\n", a.sentryPath)
	}
	a.bot.Client.Auth.LogOn(&steam.LogOnDetails{
		Username:       details.Username,
		Password:       details.Password,
		SentryFileHash: sentry,
		AuthCode:       details.AuthCode,
		TwoFactorCode:  details.AuthCode,
	})
}

func (a *Auth) HandleEvent(event interface{}) {
	switch e := event.(type) {
	case *steam.ConnectedEvent:
		a.LogOn(a.details)
	case *steam.LoggedOnEvent:
		a.bot.Log.Printf("Logged on (%v) with SteamId %v and account flags %v", e.Result, e.ClientSteamId, e.AccountFlags)
	case *steam.MachineAuthUpdateEvent:
		a.machineAuthHash = e.Hash
		err := ioutil.WriteFile(a.sentryPath, e.Hash, 0666)
		if err != nil {
			panic(err)
		}
	}
}

// This module saves the server list from ClientCMListEvent and uses
// it when you call `Connect()`.
type ServerList struct {
	bot      *GsBot
	listPath string
}

func NewServerList(bot *GsBot, listPath string) *ServerList {
	return &ServerList{
		bot,
		listPath,
	}
}

func (s *ServerList) HandleEvent(event interface{}) {
	switch e := event.(type) {
	case *steam.ClientCMListEvent:
		d, err := json.Marshal(e.Addresses)
		if err != nil {
			panic(err)
		}
		err = ioutil.WriteFile(s.listPath, d, 0666)
		if err != nil {
			panic(err)
		}
	}
}

func (s *ServerList) Connect() (bool, error) {
	return s.ConnectBind(nil)
}

func (s *ServerList) ConnectBind(laddr *net.TCPAddr) (bool, error) {
	d, err := ioutil.ReadFile(s.listPath)
	if err != nil {
		s.bot.Log.Println("Connecting to random server.")
		s.bot.Client.Connect()
		return false, nil
	}
	var addrs []*netutil.PortAddr
	err = json.Unmarshal(d, &addrs)
	if err != nil {
		return false, err
	}
	raddr := addrs[rand.Intn(len(addrs))]
	s.bot.Log.Printf("Connecting to %v from server list\n", raddr)
	s.bot.Client.ConnectToBind(raddr, laddr)
	return true, nil
}

// This module logs incoming packets and events to a directory.
type Debug struct {
	packetId, eventId uint64
	bot               *GsBot
	base              string
}

func NewDebug(bot *GsBot, base string) (*Debug, error) {
	base = path.Join(base, fmt.Sprint(time.Now().Unix()))
	err := os.MkdirAll(path.Join(base, "events"), 0700)
	if err != nil {
		return nil, err
	}
	err = os.MkdirAll(path.Join(base, "packets"), 0700)
	if err != nil {
		return nil, err
	}
	return &Debug{
		0, 0,
		bot,
		base,
	}, nil
}

func (d *Debug) HandlePacket(packet *protocol.Packet) {
	d.packetId++
	name := path.Join(d.base, "packets", fmt.Sprintf("%d_%d_%s", time.Now().Unix(), d.packetId, packet.EMsg))

	text := packet.String() + "\n\n" + hex.Dump(packet.Data)
	err := ioutil.WriteFile(name+".txt", []byte(text), 0666)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(name+".bin", packet.Data, 0666)
	if err != nil {
		panic(err)
	}
}

func (d *Debug) HandleEvent(event interface{}) {
	d.eventId++
	name := fmt.Sprintf("%d_%d_%s.txt", time.Now().Unix(), d.eventId, name(event))
	err := ioutil.WriteFile(path.Join(d.base, "events", name), []byte(spew.Sdump(event)), 0666)
	if err != nil {
		panic(err)
	}
}

func name(obj interface{}) string {
	val := reflect.ValueOf(obj)
	ind := reflect.Indirect(val)
	if ind.IsValid() {
		return ind.Type().Name()
	} else {
		return val.Type().Name()
	}
}
<commit_msg>Added TwoFactorCode to LogOnDetails<commit_after>// The GsBot package contains some useful utilites for working with the
// steam package. It implements authentication with sentries, server lists and
// logging messages and events.
//
// Every module is optional and requires an instance of the GsBot struct.
// Should a module have a `HandlePacket` method, you must register it with the
// steam.Client with `RegisterPacketHandler`. Any module with a `HandleEvent`
// method must be integrated into your event loop and should be called for each
// event you receive.
package gsbot

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"path"
	"reflect"
	"time"

	"github.com/Philipp15b/go-steam"
	"github.com/Philipp15b/go-steam/netutil"
	"github.com/Philipp15b/go-steam/protocol"
	"github.com/davecgh/go-spew/spew"
)

// Base structure holding common data among GsBot modules.
type GsBot struct {
	Client *steam.Client
	Log    *log.Logger
}

// Creates a new GsBot with a new steam.Client where logs are written to stdout.
func Default() *GsBot {
	return &GsBot{
		steam.NewClient(),
		log.New(os.Stdout, "", 0),
	}
}

// This module handles authentication. It logs on automatically after a ConnectedEvent
// and saves the sentry data to a file which is also used for logon if available.
// If you're logging on for the first time Steam may require an authcode. You can then
// connect again with the new logon details.
type Auth struct {
	bot             *GsBot
	details         *LogOnDetails
	sentryPath      string
	machineAuthHash []byte
}

func NewAuth(bot *GsBot, details *LogOnDetails, sentryPath string) *Auth {
	return &Auth{
		bot:        bot,
		details:    details,
		sentryPath: sentryPath,
	}
}

type LogOnDetails struct {
	Username      string
	Password      string
	AuthCode      string
	TwoFactorCode string
}

// This is called automatically after every ConnectedEvent, but must be called once again manually
// with an authcode if Steam requires it when logging on for the first time.
func (a *Auth) LogOn(details *LogOnDetails) {
	a.details = details
	sentry, err := ioutil.ReadFile(a.sentryPath)
	if err != nil {
		a.bot.Log.Printf("Error loading sentry file from path %v - This is normal if you're logging in for the first time.\n", a.sentryPath)
	}
	a.bot.Client.Auth.LogOn(&steam.LogOnDetails{
		Username:       details.Username,
		Password:       details.Password,
		SentryFileHash: sentry,
		AuthCode:       details.AuthCode,
		TwoFactorCode:  details.TwoFactorCode,
	})
}

func (a *Auth) HandleEvent(event interface{}) {
	switch e := event.(type) {
	case *steam.ConnectedEvent:
		a.LogOn(a.details)
	case *steam.LoggedOnEvent:
		a.bot.Log.Printf("Logged on (%v) with SteamId %v and account flags %v", e.Result, e.ClientSteamId, e.AccountFlags)
	case *steam.MachineAuthUpdateEvent:
		a.machineAuthHash = e.Hash
		err := ioutil.WriteFile(a.sentryPath, e.Hash, 0666)
		if err != nil {
			panic(err)
		}
	}
}

// This module saves the server list from ClientCMListEvent and uses
// it when you call `Connect()`.
type ServerList struct {
	bot      *GsBot
	listPath string
}

func NewServerList(bot *GsBot, listPath string) *ServerList {
	return &ServerList{
		bot,
		listPath,
	}
}

func (s *ServerList) HandleEvent(event interface{}) {
	switch e := event.(type) {
	case *steam.ClientCMListEvent:
		d, err := json.Marshal(e.Addresses)
		if err != nil {
			panic(err)
		}
		err = ioutil.WriteFile(s.listPath, d, 0666)
		if err != nil {
			panic(err)
		}
	}
}

func (s *ServerList) Connect() (bool, error) {
	return s.ConnectBind(nil)
}

func (s *ServerList) ConnectBind(laddr *net.TCPAddr) (bool, error) {
	d, err := ioutil.ReadFile(s.listPath)
	if err != nil {
		s.bot.Log.Println("Connecting to random server.")
		s.bot.Client.Connect()
		return false, nil
	}
	var addrs []*netutil.PortAddr
	err = json.Unmarshal(d, &addrs)
	if err != nil {
		return false, err
	}
	raddr := addrs[rand.Intn(len(addrs))]
	s.bot.Log.Printf("Connecting to %v from server list\n", raddr)
	s.bot.Client.ConnectToBind(raddr, laddr)
	return true, nil
}

// This module logs incoming packets and events to a directory.
type Debug struct {
	packetId, eventId uint64
	bot               *GsBot
	base              string
}

func NewDebug(bot *GsBot, base string) (*Debug, error) {
	base = path.Join(base, fmt.Sprint(time.Now().Unix()))
	err := os.MkdirAll(path.Join(base, "events"), 0700)
	if err != nil {
		return nil, err
	}
	err = os.MkdirAll(path.Join(base, "packets"), 0700)
	if err != nil {
		return nil, err
	}
	return &Debug{
		0, 0,
		bot,
		base,
	}, nil
}

func (d *Debug) HandlePacket(packet *protocol.Packet) {
	d.packetId++
	name := path.Join(d.base, "packets", fmt.Sprintf("%d_%d_%s", time.Now().Unix(), d.packetId, packet.EMsg))

	text := packet.String() + "\n\n" + hex.Dump(packet.Data)
	err := ioutil.WriteFile(name+".txt", []byte(text), 0666)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(name+".bin", packet.Data, 0666)
	if err != nil {
		panic(err)
	}
}

func (d *Debug) HandleEvent(event interface{}) {
	d.eventId++
	name := fmt.Sprintf("%d_%d_%s.txt", time.Now().Unix(), d.eventId, name(event))
	err := ioutil.WriteFile(path.Join(d.base, "events", name), []byte(spew.Sdump(event)), 0666)
	if err != nil {
		panic(err)
	}
}

func name(obj interface{}) string {
	val := reflect.ValueOf(obj)
	ind := reflect.Indirect(val)
	if ind.IsValid() {
		return ind.Type().Name()
	} else {
		return val.Type().Name()
	}
}
<|endoftext|>


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

package odbc

import (
	"code.google.com/p/odbc/api"
	"database/sql/driver"
	"errors"
	"fmt"
	"time"
	"unsafe"
)

type BufferLen api.SQLLEN

func (l *BufferLen) IsNull() bool {
	return *l == api.SQL_NULL_DATA
}

func (l *BufferLen) GetData(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
	return api.SQLGetData(h, api.SQLUSMALLINT(idx+1), ctype,
		api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
		(*api.SQLLEN)(l))
}

func (l *BufferLen) Bind(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
	return api.SQLBindCol(h, api.SQLUSMALLINT(idx+1), ctype,
		api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
		(*api.SQLLEN)(l))
}

// Column provides access to row columns.
type Column interface {
	Name() string
	Bind(h api.SQLHSTMT, idx int) (bool, error)
	Value(h api.SQLHSTMT, idx int) (driver.Value, error)
}

func describeColumn(h api.SQLHSTMT, idx int, namebuf []uint16) (namelen int, sqltype api.SQLSMALLINT, size api.SQLULEN, ret api.SQLRETURN) {
	var l, decimal, nullable api.SQLSMALLINT
	ret = api.SQLDescribeCol(h, api.SQLUSMALLINT(idx+1),
		(*api.SQLWCHAR)(unsafe.Pointer(&namebuf[0])),
		api.SQLSMALLINT(len(namebuf)), &l,
		&sqltype, &size, &decimal, &nullable)
	return int(l), sqltype, size, ret
}

// TODO(brainman): did not check for MS SQL timestamp

func NewColumn(h api.SQLHSTMT, idx int) (Column, error) {
	namebuf := make([]uint16, 150)
	namelen, sqltype, size, ret := describeColumn(h, idx, namebuf)
	if ret == api.SQL_SUCCESS_WITH_INFO && namelen > len(namebuf) {
		// try again with bigger buffer
		namebuf = make([]uint16, namelen)
		namelen, sqltype, size, ret = describeColumn(h, idx, namebuf)
	}
	if IsError(ret) {
		return nil, NewError("SQLDescribeCol", h)
	}
	if namelen > len(namebuf) {
		// still complaining about buffer size
		return nil, errors.New("Failed to allocate column name buffer")
	}
	b := &BaseColumn{
		name: api.UTF16ToString(namebuf[:namelen]),
	}
	switch sqltype {
	case api.SQL_BIT:
		return NewBindableColumn(b, api.SQL_C_BIT, 1), nil
	case api.SQL_TINYINT, api.SQL_SMALLINT, api.SQL_INTEGER:
		return NewBindableColumn(b, api.SQL_C_LONG, 4), nil
	case api.SQL_BIGINT:
		return NewBindableColumn(b, api.SQL_C_SBIGINT, 8), nil
	case api.SQL_NUMERIC, api.SQL_DECIMAL, api.SQL_FLOAT, api.SQL_REAL, api.SQL_DOUBLE:
		return NewBindableColumn(b, api.SQL_C_DOUBLE, 8), nil
	case api.SQL_TYPE_TIMESTAMP:
		var v api.SQL_TIMESTAMP_STRUCT
		return NewBindableColumn(b, api.SQL_C_TYPE_TIMESTAMP, int(unsafe.Sizeof(v))), nil
	case api.SQL_TYPE_DATE:
		var v api.SQL_DATE_STRUCT
		return NewBindableColumn(b, api.SQL_C_DATE, int(unsafe.Sizeof(v))), nil
	case api.SQL_GUID:
		var v api.SQLGUID
		return NewBindableColumn(b, api.SQL_C_GUID, int(unsafe.Sizeof(v))), nil
	case api.SQL_CHAR, api.SQL_VARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_CHAR, size), nil
	case api.SQL_WCHAR, api.SQL_WVARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_WCHAR, size), nil
	case api.SQL_BINARY, api.SQL_VARBINARY:
		return NewVariableWidthColumn(b, api.SQL_C_BINARY, size), nil
	case api.SQL_LONGVARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_CHAR, 0), nil
	case api.SQL_WLONGVARCHAR, api.SQL_SS_XML:
		return NewVariableWidthColumn(b, api.SQL_C_WCHAR, 0), nil
	case api.SQL_LONGVARBINARY:
		return NewVariableWidthColumn(b, api.SQL_C_BINARY, 0), nil
	default:
		return nil, fmt.Errorf("unsupported column type %d", sqltype)
	}
	panic("unreachable")
}

// BaseColumn implements common column functionality.
type BaseColumn struct {
	name  string
	CType api.SQLSMALLINT
}

func (c *BaseColumn) Name() string {
	return c.name
}

func (c *BaseColumn) Value(buf []byte) (driver.Value, error) {
	var p unsafe.Pointer
	if len(buf) > 0 {
		p = unsafe.Pointer(&buf[0])
	}
	switch c.CType {
	case api.SQL_C_BIT:
		return buf[0] != 0, nil
	case api.SQL_C_LONG:
		return *((*int32)(p)), nil
	case api.SQL_C_SBIGINT:
		return *((*int64)(p)), nil
	case api.SQL_C_DOUBLE:
		return *((*float64)(p)), nil
	case api.SQL_C_CHAR:
		return buf, nil
	case api.SQL_C_WCHAR:
		if p == nil {
			return buf, nil
		}
		s := (*[1 << 20]uint16)(p)[:len(buf)/2]
		return utf16toutf8(s), nil
	case api.SQL_C_TYPE_TIMESTAMP:
		t := (*api.SQL_TIMESTAMP_STRUCT)(p)
		r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
			int(t.Hour), int(t.Minute), int(t.Second), int(t.Fraction),
			time.Local)
		return r, nil
	case api.SQL_C_GUID:
		t := (*api.SQLGUID)(p)
		var p1, p2 string
		for _, d := range t.Data4[:2] {
			p1 += fmt.Sprintf("%02x", d)
		}
		for _, d := range t.Data4[2:] {
			p2 += fmt.Sprintf("%02x", d)
		}
		r := fmt.Sprintf("%08x-%04x-%04x-%s-%s",
			t.Data1, t.Data2, t.Data3, p1, p2)
		return r, nil
	case api.SQL_C_DATE:
		t := (*api.SQL_DATE_STRUCT)(p)
		r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
			0, 0, 0, 0, time.Local)
		return r, nil
	case api.SQL_C_BINARY:
		return buf, nil
	}
	return nil, fmt.Errorf("unsupported column ctype %d", c.CType)
}

// BindableColumn allows access to columns that can have their buffers
// bound. Once bound at start, they are written to by odbc driver every
// time it fetches new row. This saves on syscall and, perhaps, some
// buffer copying. BindableColumn can be left unbound, then it behaves
// like NonBindableColumn when user reads data from it.
type BindableColumn struct {
	*BaseColumn
	IsBound         bool
	IsVariableWidth bool
	Size            int
	Len             BufferLen
	Buffer          []byte
	smallBuf        [8]byte // small inline memory buffer, so we do not need allocate external memory all the time
}

func NewBindableColumn(b *BaseColumn, ctype api.SQLSMALLINT, bufSize int) *BindableColumn {
	b.CType = ctype
	c := &BindableColumn{BaseColumn: b, Size: bufSize}
	if c.Size <= len(c.smallBuf) {
		// use inline buffer
		c.Buffer = c.smallBuf[:c.Size]
	} else {
		c.Buffer = make([]byte, c.Size)
	}
	return c
}

func NewVariableWidthColumn(b *BaseColumn, ctype api.SQLSMALLINT, colWidth api.SQLULEN) Column {
	if colWidth == 0 || colWidth > 1024 {
		b.CType = ctype
		return &NonBindableColumn{b}
	}
	l := int(colWidth)
	switch ctype {
	case api.SQL_C_WCHAR:
		l += 1 // room for null-termination character
		l *= 2 // wchars take 2 bytes each
	case api.SQL_C_CHAR:
		l += 1 // room for null-termination character
	case api.SQL_C_BINARY:
		// nothing to do
	default:
		panic(fmt.Errorf("do not know how wide column of ctype %d is", ctype))
	}
	c := NewBindableColumn(b, ctype, l)
	c.IsVariableWidth = true
	return c
}

func (c *BindableColumn) Bind(h api.SQLHSTMT, idx int) (bool, error) {
	ret := c.Len.Bind(h, idx, c.CType, c.Buffer)
	if IsError(ret) {
		return false, NewError("SQLBindCol", h)
	}
	c.IsBound = true
	return true, nil
}

func (c *BindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
	if !c.IsBound {
		ret := c.Len.GetData(h, idx, c.CType, c.Buffer)
		if IsError(ret) {
			return nil, NewError("SQLGetData", h)
		}
	}
	if c.Len.IsNull() {
		// is NULL
		return nil, nil
	}
	if !c.IsVariableWidth && int(c.Len) != c.Size {
		panic(fmt.Errorf("wrong column #%d length %d returned, %d expected", idx, c.Len, c.Size))
	}
	return c.BaseColumn.Value(c.Buffer[:c.Len])
}

// NonBindableColumn provide access to columns, that can't be bound.
// These are of character or binary type, and, usually, there is no
// limit for their width.
type NonBindableColumn struct {
	*BaseColumn
}

func (c *NonBindableColumn) Bind(h api.SQLHSTMT, idx int) (bool, error) {
	return false, nil
}

func (c *NonBindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
	var l BufferLen
	var total []byte
	b := make([]byte, 1024)
loop:
	for {
		ret := l.GetData(h, idx, c.CType, b)
		switch ret {
		case api.SQL_SUCCESS:
			if l.IsNull() {
				// is NULL
				return nil, nil
			}
			if int(l) > len(b) {
				return nil, fmt.Errorf("too much data returned: %d bytes returned, but buffer size is %d", l, cap(b))
			}
			total = append(total, b[:l]...)
			break loop
		case api.SQL_SUCCESS_WITH_INFO:
			err := NewError("SQLGetData", h).(*Error)
			if len(err.Diag) > 0 && err.Diag[0].State != "01004" {
				return nil, err
			}
			i := len(b)
			switch c.CType {
			case api.SQL_C_WCHAR:
				i -= 2 // remove wchar (2 bytes) null-termination character
			case api.SQL_C_CHAR:
				i-- // remove null-termination character
			}
			total = append(total, b[:i]...)
			if l != api.SQL_NO_TOTAL {
				// odbc gives us a hint about remaining data,
				// lets get it in one go.
				n := int(l) // total bytes for our data
				n -= i      // subtract already received
				n += 2      // room for biggest (wchar) null-terminator
				if len(b) < n {
					b = make([]byte, n)
				}
			}
		default:
			return nil, NewError("SQLGetData", h)
		}
	}
	return c.BaseColumn.Value(total)
}
<commit_msg>odbc: allow for larger (256M) fields<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package odbc

import (
	"code.google.com/p/odbc/api"
	"database/sql/driver"
	"errors"
	"fmt"
	"time"
	"unsafe"
)

type BufferLen api.SQLLEN

func (l *BufferLen) IsNull() bool {
	return *l == api.SQL_NULL_DATA
}

func (l *BufferLen) GetData(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
	return api.SQLGetData(h, api.SQLUSMALLINT(idx+1), ctype,
		api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
		(*api.SQLLEN)(l))
}

func (l *BufferLen) Bind(h api.SQLHSTMT, idx int, ctype api.SQLSMALLINT, buf []byte) api.SQLRETURN {
	return api.SQLBindCol(h, api.SQLUSMALLINT(idx+1), ctype,
		api.SQLPOINTER(unsafe.Pointer(&buf[0])), api.SQLLEN(len(buf)),
		(*api.SQLLEN)(l))
}

// Column provides access to row columns.
type Column interface {
	Name() string
	Bind(h api.SQLHSTMT, idx int) (bool, error)
	Value(h api.SQLHSTMT, idx int) (driver.Value, error)
}

func describeColumn(h api.SQLHSTMT, idx int, namebuf []uint16) (namelen int, sqltype api.SQLSMALLINT, size api.SQLULEN, ret api.SQLRETURN) {
	var l, decimal, nullable api.SQLSMALLINT
	ret = api.SQLDescribeCol(h, api.SQLUSMALLINT(idx+1),
		(*api.SQLWCHAR)(unsafe.Pointer(&namebuf[0])),
		api.SQLSMALLINT(len(namebuf)), &l,
		&sqltype, &size, &decimal, &nullable)
	return int(l), sqltype, size, ret
}

// TODO(brainman): did not check for MS SQL timestamp

func NewColumn(h api.SQLHSTMT, idx int) (Column, error) {
	namebuf := make([]uint16, 150)
	namelen, sqltype, size, ret := describeColumn(h, idx, namebuf)
	if ret == api.SQL_SUCCESS_WITH_INFO && namelen > len(namebuf) {
		// try again with bigger buffer
		namebuf = make([]uint16, namelen)
		namelen, sqltype, size, ret = describeColumn(h, idx, namebuf)
	}
	if IsError(ret) {
		return nil, NewError("SQLDescribeCol", h)
	}
	if namelen > len(namebuf) {
		// still complaining about buffer size
		return nil, errors.New("Failed to allocate column name buffer")
	}
	b := &BaseColumn{
		name: api.UTF16ToString(namebuf[:namelen]),
	}
	switch sqltype {
	case api.SQL_BIT:
		return NewBindableColumn(b, api.SQL_C_BIT, 1), nil
	case api.SQL_TINYINT, api.SQL_SMALLINT, api.SQL_INTEGER:
		return NewBindableColumn(b, api.SQL_C_LONG, 4), nil
	case api.SQL_BIGINT:
		return NewBindableColumn(b, api.SQL_C_SBIGINT, 8), nil
	case api.SQL_NUMERIC, api.SQL_DECIMAL, api.SQL_FLOAT, api.SQL_REAL, api.SQL_DOUBLE:
		return NewBindableColumn(b, api.SQL_C_DOUBLE, 8), nil
	case api.SQL_TYPE_TIMESTAMP:
		var v api.SQL_TIMESTAMP_STRUCT
		return NewBindableColumn(b, api.SQL_C_TYPE_TIMESTAMP, int(unsafe.Sizeof(v))), nil
	case api.SQL_TYPE_DATE:
		var v api.SQL_DATE_STRUCT
		return NewBindableColumn(b, api.SQL_C_DATE, int(unsafe.Sizeof(v))), nil
	case api.SQL_GUID:
		var v api.SQLGUID
		return NewBindableColumn(b, api.SQL_C_GUID, int(unsafe.Sizeof(v))), nil
	case api.SQL_CHAR, api.SQL_VARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_CHAR, size), nil
	case api.SQL_WCHAR, api.SQL_WVARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_WCHAR, size), nil
	case api.SQL_BINARY, api.SQL_VARBINARY:
		return NewVariableWidthColumn(b, api.SQL_C_BINARY, size), nil
	case api.SQL_LONGVARCHAR:
		return NewVariableWidthColumn(b, api.SQL_C_CHAR, 0), nil
	case api.SQL_WLONGVARCHAR, api.SQL_SS_XML:
		return NewVariableWidthColumn(b, api.SQL_C_WCHAR, 0), nil
	case api.SQL_LONGVARBINARY:
		return NewVariableWidthColumn(b, api.SQL_C_BINARY, 0), nil
	default:
		return nil, fmt.Errorf("unsupported column type %d", sqltype)
	}
	panic("unreachable")
}

// BaseColumn implements common column functionality.
type BaseColumn struct {
	name  string
	CType api.SQLSMALLINT
}

func (c *BaseColumn) Name() string {
	return c.name
}

func (c *BaseColumn) Value(buf []byte) (driver.Value, error) {
	var p unsafe.Pointer
	if len(buf) > 0 {
		p = unsafe.Pointer(&buf[0])
	}
	switch c.CType {
	case api.SQL_C_BIT:
		return buf[0] != 0, nil
	case api.SQL_C_LONG:
		return *((*int32)(p)), nil
	case api.SQL_C_SBIGINT:
		return *((*int64)(p)), nil
	case api.SQL_C_DOUBLE:
		return *((*float64)(p)), nil
	case api.SQL_C_CHAR:
		return buf, nil
	case api.SQL_C_WCHAR:
		if p == nil {
			return buf, nil
		}
		s := (*[1 << 28]uint16)(p)[:len(buf)/2]
		return utf16toutf8(s), nil
	case api.SQL_C_TYPE_TIMESTAMP:
		t := (*api.SQL_TIMESTAMP_STRUCT)(p)
		r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
			int(t.Hour), int(t.Minute), int(t.Second), int(t.Fraction),
			time.Local)
		return r, nil
	case api.SQL_C_GUID:
		t := (*api.SQLGUID)(p)
		var p1, p2 string
		for _, d := range t.Data4[:2] {
			p1 += fmt.Sprintf("%02x", d)
		}
		for _, d := range t.Data4[2:] {
			p2 += fmt.Sprintf("%02x", d)
		}
		r := fmt.Sprintf("%08x-%04x-%04x-%s-%s",
			t.Data1, t.Data2, t.Data3, p1, p2)
		return r, nil
	case api.SQL_C_DATE:
		t := (*api.SQL_DATE_STRUCT)(p)
		r := time.Date(int(t.Year), time.Month(t.Month), int(t.Day),
			0, 0, 0, 0, time.Local)
		return r, nil
	case api.SQL_C_BINARY:
		return buf, nil
	}
	return nil, fmt.Errorf("unsupported column ctype %d", c.CType)
}

// BindableColumn allows access to columns that can have their buffers
// bound. Once bound at start, they are written to by odbc driver every
// time it fetches new row. This saves on syscall and, perhaps, some
// buffer copying. BindableColumn can be left unbound, then it behaves
// like NonBindableColumn when user reads data from it.
type BindableColumn struct {
	*BaseColumn
	IsBound         bool
	IsVariableWidth bool
	Size            int
	Len             BufferLen
	Buffer          []byte
	smallBuf        [8]byte // small inline memory buffer, so we do not need allocate external memory all the time
}

func NewBindableColumn(b *BaseColumn, ctype api.SQLSMALLINT, bufSize int) *BindableColumn {
	b.CType = ctype
	c := &BindableColumn{BaseColumn: b, Size: bufSize}
	if c.Size <= len(c.smallBuf) {
		// use inline buffer
		c.Buffer = c.smallBuf[:c.Size]
	} else {
		c.Buffer = make([]byte, c.Size)
	}
	return c
}

func NewVariableWidthColumn(b *BaseColumn, ctype api.SQLSMALLINT, colWidth api.SQLULEN) Column {
	if colWidth == 0 || colWidth > 1024 {
		b.CType = ctype
		return &NonBindableColumn{b}
	}
	l := int(colWidth)
	switch ctype {
	case api.SQL_C_WCHAR:
		l += 1 // room for null-termination character
		l *= 2 // wchars take 2 bytes each
	case api.SQL_C_CHAR:
		l += 1 // room for null-termination character
	case api.SQL_C_BINARY:
		// nothing to do
	default:
		panic(fmt.Errorf("do not know how wide column of ctype %d is", ctype))
	}
	c := NewBindableColumn(b, ctype, l)
	c.IsVariableWidth = true
	return c
}

func (c *BindableColumn) Bind(h api.SQLHSTMT, idx int) (bool, error) {
	ret := c.Len.Bind(h, idx, c.CType, c.Buffer)
	if IsError(ret) {
		return false, NewError("SQLBindCol", h)
	}
	c.IsBound = true
	return true, nil
}

func (c *BindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
	if !c.IsBound {
		ret := c.Len.GetData(h, idx, c.CType, c.Buffer)
		if IsError(ret) {
			return nil, NewError("SQLGetData", h)
		}
	}
	if c.Len.IsNull() {
		// is NULL
		return nil, nil
	}
	if !c.IsVariableWidth && int(c.Len) != c.Size {
		panic(fmt.Errorf("wrong column #%d length %d returned, %d expected", idx, c.Len, c.Size))
	}
	return c.BaseColumn.Value(c.Buffer[:c.Len])
}

// NonBindableColumn provide access to columns, that can't be bound.
// These are of character or binary type, and, usually, there is no
// limit for their width.
type NonBindableColumn struct {
	*BaseColumn
}

func (c *NonBindableColumn) Bind(h api.SQLHSTMT, idx int) (bool, error) {
	return false, nil
}

func (c *NonBindableColumn) Value(h api.SQLHSTMT, idx int) (driver.Value, error) {
	var l BufferLen
	var total []byte
	b := make([]byte, 1024)
loop:
	for {
		ret := l.GetData(h, idx, c.CType, b)
		switch ret {
		case api.SQL_SUCCESS:
			if l.IsNull() {
				// is NULL
				return nil, nil
			}
			if int(l) > len(b) {
				return nil, fmt.Errorf("too much data returned: %d bytes returned, but buffer size is %d", l, cap(b))
			}
			total = append(total, b[:l]...)
			break loop
		case api.SQL_SUCCESS_WITH_INFO:
			err := NewError("SQLGetData", h).(*Error)
			if len(err.Diag) > 0 && err.Diag[0].State != "01004" {
				return nil, err
			}
			i := len(b)
			switch c.CType {
			case api.SQL_C_WCHAR:
				i -= 2 // remove wchar (2 bytes) null-termination character
			case api.SQL_C_CHAR:
				i-- // remove null-termination character
			}
			total = append(total, b[:i]...)
			if l != api.SQL_NO_TOTAL {
				// odbc gives us a hint about remaining data,
				// lets get it in one go.
				n := int(l) // total bytes for our data
				n -= i      // subtract already received
				n += 2      // room for biggest (wchar) null-terminator
				if len(b) < n {
					b = make([]byte, n)
				}
			}
		default:
			return nil, NewError("SQLGetData", h)
		}
	}
	return c.BaseColumn.Value(total)
}
<|endoftext|>


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

package policy

import "errors"

// Type denotes the monitoring policy type.
//
// e.g. "tcp"
type Type string

// Policy is the map containing the rules of a particular monitoring policy.
//
// e.g. "tcp" PolicyType requires 2 policy keys "port" and "frequency"
type Policy struct {
	Name     string
	AgentUID string
	Type     Type
	M        map[string]string
}

// Config is the format used to encode/decode the monitoring policy
// received from the message queue or to store in the config file
type Config []Policy

// PolicyFuncMap maps a PolicyType to a handler function
var PolicyFuncMap = map[Type]func(Policy) (<-chan Event, error){
	"tcp": tcpPolicyHandler,
}

func (p Policy) Execute() (<-chan Event, error) {
	if err := p.Valid(); err != nil {
		return nil, err
	}
	return PolicyFuncMap[p.Type](p)
}

// Valid checks whether the policy is valid.
func (p Policy) Valid() error {
	if p.Name == "" {
		return errors.New("policy name can't be empty")
	}
	if _, ok := PolicyFuncMap[p.Type]; !ok {
		return errors.New("policy type unknown")
	}
	return nil
}
<commit_msg>unexport policyFuncMap<commit_after>// Copyright 2015 CodeIgnition. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package policy

import "errors"

// Type denotes the monitoring policy type.
//
// e.g. "tcp"
type Type string

// Policy is the map containing the rules of a particular monitoring policy.
//
// e.g. "tcp" PolicyType requires 2 policy keys "port" and "frequency"
type Policy struct {
	Name     string
	AgentUID string
	Type     Type
	M        map[string]string
}

// Config is the format used to encode/decode the monitoring policy
// received from the message queue or to store in the config file
type Config []Policy

// policyFuncMap maps a PolicyType to a handler function
var policyFuncMap = map[Type]func(Policy) (<-chan Event, error){
	"tcp": tcpPolicyHandler,
}

func (p Policy) Execute() (<-chan Event, error) {
	if err := p.Valid(); err != nil {
		return nil, err
	}
	return policyFuncMap[p.Type](p)
}

// Valid checks whether the policy is valid.
func (p Policy) Valid() error {
	if p.Name == "" {
		return errors.New("policy name can't be empty")
	}
	if _, ok := policyFuncMap[p.Type]; !ok {
		return errors.New("policy type unknown")
	}
	return nil
}
<|endoftext|>


<commit_before>
package main

import (
	"fmt"
	"flag"
	"github.com/rmera/gochem"
	"github.com/rmera/gochem/qm"
	"strings"
	"os"
)
type qmdef interface{
	qm.Handle
	SetDefaults()
}

func main() {
	//flag parsing
	//Lots of options, but the defaults are sane enough that you shouldnt need to use more than the filename and qm program.
	charge:=flag.Int("charge",0,"The charge of the system.")
	multi:=flag.Int("multi",1,"The multiplicity of the system.")
	filename:=flag.String("file","file.xyz","The XYZ file containing the coordinates for the system.")
	functional:=flag.String("func", "TPSS", "The density functional used. TPSS and BP86 activate RI when possible.")
	program:=flag.String("program","qcmine", "The QM program used: qcmine, nwchem or orca.")
	basis:=flag.String("basis", "def2-SVP","the basis set to use. Use Karlsruhe ones.")
	dielectric:=flag.Float64("epsilon", -1, "The dielectric constant. -1 indicates no dielectric used.")
	optimize:=flag.Bool("opt",true,"Wether to optimize or run an SP calculation.")
	flag.Parse()
	//We set the calculation to the values in the flags. Not big deal.
	mol, err := chem.XYZRead(*filename)
	if err != nil {
		panic(err.Error())
	}
	mol.SetMulti(*multi)
	mol.SetCharge(*charge)
	calc := new(qm.Calc)
	if strings.Contains("TPSS,BP86,PBE",*functional){
		calc.RI=true
	}
	calc.Memory = 1000
	calc.Dielectric = *dielectric
	calc.Grid = 3
	if !strings.HasPrefix(*basis,"def2"){
		fmt.Println("Told ya to use Karlsruhe basis! RI cannot be activated. Happy now?")
		calc.RI=false
	}
	calc.Basis = *basis
	calc.Optimize=*optimize
	if calc.Optimize{
		calc.SCFTightness=1
	}
	calc.Disperssion="D3"
	//The preeliminar optimization will have a different name.
	namep:=strings.Replace(*filename,".xyz","OPT",-1)
	name:=strings.Replace(*filename,".xyz","",-1)
	pre:=qm.NewMopacHandle()
	pre.SetName(namep)
	pre.BuildInput(mol.Coords[0],mol,calc)
	pre.Run(true)
	ncoords,err:=pre.OptimizedGeometry(mol)
	if err!=nil{
		panic(err.Error())
	}
	//MOPAC will overwrite the method, as it doesnt support DFT. This is why we set it AFTER the preeliminar calculations
	calc.Method=*functional
	var QM qmdef
	switch *program{
		case "nwchem":
			QM=qmdef(qm.NewNWChemHandle())
		case "orca":
			QM=qmdef(qm.NewOrcaHandle())
		default:
			//There is a hicup with ChemShell since I have not implemented a few methods.
			//I should have an interface in goChem that does not require Energy() and OptimizedGeometry()
			CS:=qm.NewCSHandle()
			CS.SetDefaults()
			CS.SetName(name)
			CS.BuildInput(ncoords,mol,calc)
	}
	if QM!=nil{
		QM.SetDefaults()
		QM.SetName(name)
		QM.BuildInput(ncoords,mol,calc)
	}
	fmt.Fprintln(os.Stderr,"Apparently, we made it :-)")
}

<commit_msg>Changed the default on preopt to bp86, as qcmine does not support tpss<commit_after>
package main

import (
	"fmt"
	"flag"
	"github.com/rmera/gochem"
	"github.com/rmera/gochem/qm"
	"strings"
	"os"
)
type qmdef interface{
	qm.Handle
	SetDefaults()
}

func main() {
	//flag parsing
	//Lots of options, but the defaults are sane enough that you shouldnt need to use more than the filename and qm program.
	charge:=flag.Int("charge",0,"The charge of the system.")
	multi:=flag.Int("multi",1,"The multiplicity of the system.")
	filename:=flag.String("file","file.xyz","The XYZ file containing the coordinates for the system.")
	functional:=flag.String("func", "BP86", "The density functional used. TPSS and BP86 activate RI when possible.")
	program:=flag.String("program","qcmine", "The QM program used: qcmine, nwchem or orca.")
	basis:=flag.String("basis", "def2-SVP","the basis set to use. Use Karlsruhe ones.")
	dielectric:=flag.Float64("epsilon", -1, "The dielectric constant. -1 indicates no dielectric used.")
	optimize:=flag.Bool("opt",true,"Wether to optimize or run an SP calculation.")
	flag.Parse()
	//We set the calculation to the values in the flags. Not big deal.
	mol, err := chem.XYZRead(*filename)
	if err != nil {
		panic(err.Error())
	}
	mol.SetMulti(*multi)
	mol.SetCharge(*charge)
	calc := new(qm.Calc)
	if strings.Contains("TPSS,BP86,PBE",*functional){
		calc.RI=true
	}
	calc.Memory = 1000
	calc.Dielectric = *dielectric
	calc.Grid = 3
	if !strings.HasPrefix(*basis,"def2"){
		fmt.Println("Told ya to use Karlsruhe basis! RI cannot be activated. Happy now?")
		calc.RI=false
	}
	calc.Basis = *basis
	calc.Optimize=*optimize
	if calc.Optimize{
		calc.SCFTightness=1
	}
	calc.Disperssion="D3"
	//The preeliminar optimization will have a different name.
	namep:=strings.Replace(*filename,".xyz","OPT",-1)
	name:=strings.Replace(*filename,".xyz","",-1)
	pre:=qm.NewMopacHandle()
	pre.SetName(namep)
	pre.BuildInput(mol.Coords[0],mol,calc)
	pre.Run(true)
	ncoords,err:=pre.OptimizedGeometry(mol)
	if err!=nil{
		panic(err.Error())
	}
	//MOPAC will overwrite the method, as it doesnt support DFT. This is why we set it AFTER the preeliminar calculations
	calc.Method=*functional
	var QM qmdef
	switch *program{
		case "nwchem":
			QM=qmdef(qm.NewNWChemHandle())
		case "orca":
			QM=qmdef(qm.NewOrcaHandle())
		default:
			//There is a hicup with ChemShell since I have not implemented a few methods.
			//I should have an interface in goChem that does not require Energy() and OptimizedGeometry()
			CS:=qm.NewCSHandle()
			CS.SetDefaults()
			CS.SetName(name)
			CS.BuildInput(ncoords,mol,calc)
	}
	if QM!=nil{
		QM.SetDefaults()
		QM.SetName(name)
		QM.BuildInput(ncoords,mol,calc)
	}
	fmt.Fprintln(os.Stderr,"Apparently, we made it :-)")
}

<|endoftext|>


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

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"strings"

	"code.google.com/p/go.tools/playground/socket"
	"code.google.com/p/go.tools/present"
)

const basePkg = "code.google.com/p/go.talks/present"

var basePath string

func main() {
	httpListen := flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	flag.StringVar(&basePath, "base", "", "base path for slide template and static resources")
	flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)")
	flag.Parse()

	if basePath == "" {
		p, err := build.Default.Import(basePkg, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find gopresent files: %v\n", err)
			fmt.Fprintf(os.Stderr, basePathMessage, basePkg)
			os.Exit(1)
		}
		basePath = p.Dir
	}

	if present.PlayEnabled {
		playScript(basePath, "SocketTransport")
		http.Handle("/socket", socket.Handler)
	}
	http.Handle("/static/", http.FileServer(http.Dir(basePath)))

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") &&
		present.PlayEnabled {
		log.Print(localhostWarning)
	}

	log.Printf("Open your web browser and visit http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

func playable(c present.Code) bool {
	return present.PlayEnabled && c.Play
}

const basePathMessage = `
By default, gopresent locates the slide template files and associated
static content by looking for a %q package
in your Go workspaces (GOPATH).

You may use the -base flag to specify an alternate location.
`

const localhostWarning = `
WARNING!  WARNING!  WARNING!

The present server appears to be listening on an address that is not localhost.
Anyone with access to this address and port will have access to this machine as
the user running present.

To avoid this message, listen on localhost or run with -play=false.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`
<commit_msg>go.talks/present: add flag to use Native Client for playground code execution<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"

	"code.google.com/p/go.tools/playground/socket"
	"code.google.com/p/go.tools/present"
)

const basePkg = "code.google.com/p/go.talks/present"

var (
	basePath     string
	nativeClient bool
)

func main() {
	httpListen := flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	flag.StringVar(&basePath, "base", "", "base path for slide template and static resources")
	flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)")
	flag.BoolVar(&nativeClient, "nacl", false, "use Native Client environment playground (prevents non-Go code execution)")
	flag.Parse()

	if basePath == "" {
		p, err := build.Default.Import(basePkg, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find gopresent files: %v\n", err)
			fmt.Fprintf(os.Stderr, basePathMessage, basePkg)
			os.Exit(1)
		}
		basePath = p.Dir
	}

	if present.PlayEnabled {
		if nativeClient {
			socket.RunScripts = false
			socket.Environ = func() []string {
				if runtime.GOARCH == "amd64" {
					return environ("GOOS=nacl", "GOARCH=amd64p32")
				}
				return environ("GOOS=nacl")
			}
		}
		playScript(basePath, "SocketTransport")
		http.Handle("/socket", socket.Handler)
	}
	http.Handle("/static/", http.FileServer(http.Dir(basePath)))

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") &&
		present.PlayEnabled && !nativeClient {
		log.Print(localhostWarning)
	}

	log.Printf("Open your web browser and visit http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

func playable(c present.Code) bool {
	return present.PlayEnabled && c.Play
}

func environ(vars ...string) []string {
	env := os.Environ()
	for _, r := range vars {
		k := strings.SplitAfter(r, "=")[0]
		var found bool
		for i, v := range env {
			if strings.HasPrefix(v, k) {
				env[i] = r
				found = true
			}
		}
		if !found {
			env = append(env, r)
		}
	}
	return env
}

const basePathMessage = `
By default, gopresent locates the slide template files and associated
static content by looking for a %q package
in your Go workspaces (GOPATH).

You may use the -base flag to specify an alternate location.
`

const localhostWarning = `
WARNING!  WARNING!  WARNING!

The present server appears to be listening on an address that is not localhost.
Anyone with access to this address and port will have access to this machine as
the user running present.

To avoid this message, listen on localhost or run with -play=false.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/mgutz/ansi"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"
)

/*
*	This is the struct implementing the interface defined by the core CLI. It can
*	be found at  "github.com/cloudfoundry/cli/plugin/plugin.go"
 */
type downloadPlugin struct{}

// error struct that allows appending error messages
type cliError struct {
	err    error
	errMsg string
}

var (
	rootWorkingDirectory string
	appName              string
	instance             string
	verbose              bool
	failedDownloads      []string
	filesDownloaded      int
)

// global wait group for all download threads
var wg sync.WaitGroup

/*
*	This function must be implemented by any plugin because it is part of the
*	plugin interface defined by the core CLI.
*
*	Run(....) is the entry point when the core CLI is invoking a command defined
*	by a plugin. The first parameter, plugin.CliConnection, is a struct that can
*	be used to invoke cli commands. The second paramter, args, is a slice of
*	strings. args[0] will be the name of the command, and will be followed by
*	any additional arguments a cli user typed in.
*
*	Any error handling should be handled with the plugin itself (this means printing
*	user facing errors). The CLI will exit 0 if the plugin exits 0 and will exit
*	1 should the plugin exits nonzero.
 */
func (c *downloadPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	// start time for download timer
	start := time.Now()

	// flag variables
	maxRoutines := 200
	overWrite := false
	instance = "0"
	verbose = false

	runtime.GOMAXPROCS(maxRoutines)

	// Ensure that we called the command download
	if args[0] == "download" {

		// check for
		if len(args) < 2 {
			fmt.Println("\nError: Missing App Name")
			os.Exit(1)
		}

		workingDir, err := os.Getwd()
		check(cliError{err: err, errMsg: "Called by: Run"})
		appName = args[1]
		rootWorkingDirectory = workingDir + "/" + appName + "-download/"

		// check for misplaced flags
		if strings.HasPrefix(appName, "-") || strings.HasPrefix(appName, "--") {
			fmt.Println("\nError: App name begins with '-' or '--'. correct flag usage: 'cf download APP_NAME [--flags]'")
			return
		}

		// ensure cf_trace is disabled, otherwise parsing breaks
		if os.Getenv("CF_TRACE") == "true" {
			fmt.Println("\nError: environment variable CF_TRACE is set to true. This prevents download from succeeding.")
			return
		}

		// prevent overwriting files
		if exists(rootWorkingDirectory) && overWrite == false {
			fmt.Println("\nError: destination path", rootWorkingDirectory, "already exists and is not an empty directory. delete it or use 'cf download APP_NAME --overwrite'")
			return
		}

		// append path if provided as arguement
		startingPath := "/"
		if len(args) == 3 {
			startingPath = args[2]
			if !strings.HasSuffix(startingPath, "/") {
				startingPath += "/"
			}
		}

		// parse the directory
		files, dirs := execParseDir(startingPath)

		fmt.Printf("Files completed: %d", filesDownloaded)

		// stop consoleWriter
		quit := make(chan int)
		// disable consoleWriter if verbose
		if verbose == false {
			go consoleWriter(quit)
		}

		// Start the download
		wg.Add(1)
		download(files, dirs, startingPath, rootWorkingDirectory)

		// Wait for download goRoutines
		wg.Wait()

		// stop console writer
		if verbose == false {
			quit <- 0
		}

		// let user know if any files were inaccessible
		if len(failedDownloads) == 1 {
			fmt.Println("")
			fmt.Println(len(failedDownloads), "file was not downloaded (inaccessible or corrupt):")
			printSlice(failedDownloads)
		} else if len(failedDownloads) > 1 {
			fmt.Println("")
			fmt.Println(len(failedDownloads), "files were not downloaded (inaccessible or corrupt):")
			printSlice(failedDownloads)
		}

		// display runtime
		elapsed := time.Since(start)
		fmt.Printf("\nDownload time: %s\n", elapsed)

		msg := ansi.Color(appName+" Successfully Downloaded!", "green+b")
		fmt.Println(msg)
	}
}

/*
*	consoleWriter prints the current number of files downloaded. It is polled every 350 milleseconds
* 	disabled if using verbose flag.
 */
func consoleWriter(quit chan int) {
	count := 0
	for {
		select {
		case <-quit:
			return
		default:
			switch count = (count + 1) % 4; count {
			case 0:
				fmt.Printf("\rFiles completed: %d \\ ", filesDownloaded)
			case 1:
				fmt.Printf("\rFiles completed: %d | ", filesDownloaded)
			case 2:
				fmt.Printf("\rFiles completed: %d / ", filesDownloaded)
			case 3:
				fmt.Printf("\rFiles completed: %d --", filesDownloaded)
			}
			time.Sleep(350 * time.Millisecond)
		}
	}
}

/*
*	execParseDir() uses os/exec to shell out commands to cf files with the given readPath. The returned
*	text contains file and directory structure which is then parsed into two slices, dirs and files. dirs
*	contains the names of directories in readPath, files contians the file names. dirs and files are returned
* 	to be downloaded by download() and downloadFile() respectively.
 */
func execParseDir(readPath string) ([]string, []string) {
	// make the cf files call using exec
	cmd := exec.Command("cf", "files", appName, readPath, "-i", instance)
	output, err := cmd.CombinedOutput()
	dirSlice := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid or missing app
	if strings.Contains(dirSlice[1], "not found") {
		errmsg := ansi.Color("Error: "+appName+" app not found (check space and org)", "red+b")
		fmt.Println(errmsg)
	}

	// this usually gets called when an app is not running and you attempt to download it.
	dir := dirSlice[2]
	if strings.Contains(dir, "error code: 190001") {
		errmsg := ansi.Color("App not found, possibly not yet running", "red+b")
		fmt.Println(errmsg)
		check(cliError{err: err, errMsg: "App not found"})
	}

	// handle an empty directory
	if strings.Contains(dir, "No files found") {
		return nil, nil
	} else {
		check(cliError{err: err, errMsg: "Called by: ExecParseDir [cf files " + appName + " " + readPath + "]"})
	}

	// parse the returned output into files and dirs slices
	filesSlice := strings.Fields(dir)
	var files, dirs []string
	for i := 0; i < len(filesSlice); i += 2 {
		if strings.HasSuffix(filesSlice[i], "/") {
			dirs = append(dirs, filesSlice[i])
		} else {
			files = append(files, filesSlice[i])
		}

	}
	return files, dirs
}

/*
*	downloadFile() takes a 'readPath' which corresponds to a file in the cf app. The file is
*	downloaded using the os/exec library to call cf files with the given readPath. The output is
*	written to a file at writePath.
 */
func downloadFile(readPath, writePath string, fileDownloadGroup *sync.WaitGroup) error {
	defer fileDownloadGroup.Done()

	// call cf files using os/exec
	cmd := exec.Command("cf", "files", appName, readPath, "-i", instance)
	output, err := cmd.CombinedOutput()
	file := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid file error.
	// some files are inaccesible from the cf files (reasons unknown) this is rare but we need to
	// alert users if it occurs
	fileAsString := file[2]
	if strings.Contains(file[1], "FAILED") {
		errormsg := ansi.Color(" Server Error: '"+readPath+"' not downloaded", "red")
		failedDownloads = append(failedDownloads, errormsg)
		fmt.Println(errormsg)
		return nil
	} else {
		// check for other errors
		check(cliError{err: err, errMsg: "Called by: downloadFile 1"})
	}

	// write downloaded file to writePath
	err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)
	check(cliError{err: err, errMsg: "Called by: downloadFile 2"})
	if verbose {
		fmt.Printf("Wrote file: %s\n", readPath)
	} else {
		// increment download counter for commandline display
		// see consoleWriter()
		filesDownloaded++
	}

	return nil
}

/*
*	given file and directory names, download() will download the files from
* 	'readPath' and write them to disk on the 'writepath'.
* 	the function calls it's self recursively for each directory as it travels down the tree.
* 	Each call runs on a seperate go routine and and calls a go routine for every
* 	file download.
 */
func download(files, dirs []string, readPath, writePath string) error {
	defer wg.Done()

	//create dir if does not exist
	err := os.MkdirAll(writePath, 0755)
	check(cliError{err: err, errMsg: "Called by: download"})

	// download each file
	for _, val := range files {
		fileWPath := writePath + val
		fileRPath := readPath + val

		wg.Add(1)
		go downloadFile(fileRPath, fileWPath, &wg)
	}

	// call download on every sub directory
	for _, val := range dirs {
		dirWPath := writePath + val
		dirRPath := readPath + val
		err := os.MkdirAll(dirWPath, 0755)
		check(cliError{err: err, errMsg: "Called by: download"})

		files, dirs = execParseDir(dirRPath)

		wg.Add(1)
		go download(files, dirs, dirRPath, dirWPath)
	}
	return nil
}

/*
*	This function must be implemented as part of the	plugin interface
*	defined by the core CLI.
*
*	GetMetadata() returns a PluginMetadata struct. The first field, Name,
*	determines the name of the plugin which should generally be without spaces.
*	If there are spaces in the name a user will need to properly quote the name
*	during uninstall otherwise the name will be treated as seperate arguments.
*	The second value is a slice of Command structs. Our slice only contains one
*	Command Struct, but could contain any number of them. The first field Name
*	defines the command `cf basic-plugin-command` once installed into the CLI. The
*	second field, HelpText, is used by the core CLI to display help information
*	to the user in the core commands `cf help`, `cf`, or `cf -h`.
 */
func (c *downloadPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "download",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 1,
			Build: 1,
		},
		Commands: []plugin.Command{
			plugin.Command{
				Name:     "download",
				HelpText: "Download contents of targeted directory",

				// UsageDetails is optional
				// It is used to show help of usage of each command
				UsageDetails: plugin.Usage{
					Usage: "cf download APP_NAME [PATH] [--flags]",
					Options: map[string]string{
						"overwrite": "overwrite files",
						"verbose":   "verbose",
						"omit":      "omit directory or file",
						"routines":  "max number of concurrent subroutines (default 200)",
						"i":         "instance",
					},
				},
			},
		},
	}
}

// error check function
func check(e cliError) {
	if e.err != nil {
		fmt.Println("\nError: ", e.err)
		if e.errMsg != "" {
			fmt.Println("Message: ", e.errMsg)
		}
		os.Exit(1)
	}
}

// prints slices in readable format
func printSlice(slice []string) error {
	for index, val := range slice {
		fmt.Println(index+1, ": ", val)
	}
	return nil
}

// exists returns whether the given file or directory exists or not
func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	check(cliError{err: err, errMsg: "Called by: exists"})
	return false
}

/*
* Unlike most Go programs, the `Main()` function will not be used to run all of the
* commands provided in your plugin. Main will be used to initialize the plugin
* process, as well as any dependencies you might require for your
* plugin.
 */
func main() {
	// Any initialization for your plugin can be handled here

	// Note: The plugin's main() method is invoked at install time to collect
	// metadata. The plugin will exit 0 and the Run([]string) method will not be
	// invoked.
	plugin.Start(new(downloadPlugin))
	// Plugin code should be written in the Run([]string) method,
	// ensuring the plugin environment is bootstrapped.
}
<commit_msg>flag functionality added.<commit_after>package main

import (
	"fmt"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/mgutz/ansi"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"
    "flag"
    "strconv"
)

/*
*	This is the struct implementing the interface defined by the core CLI. It can
*	be found at  "github.com/cloudfoundry/cli/plugin/plugin.go"
 */
type downloadPlugin struct{}

// error struct that allows appending error messages
type cliError struct {
	err    error
	errMsg string
}

var (
	rootWorkingDirectory string
	appName              string
	instance             string
	verbose              bool
	failedDownloads      []string
	filesDownloaded      int
)

// global wait group for all download threads
var wg sync.WaitGroup

func getFilterList(omitString string) []string {
    var filterList []string                            // filtered list to be returned

    // Add .cfignore files to filterList
    content, err := ioutil.ReadFile(".cfignore")
    if err != nil {
        fmt.Println(err)
    } else {
        lines := strings.Split(string(content), "\n")
        filterList = append(filterList,lines[0:]...)
        if len(filterList) > 0 && filterList[len(filterList)-1] == "" {
            filterList = filterList[:len(filterList)-1]
        }
    }

    if omitString != "" {
        filterList = append(filterList, omitString)                  // add -omit param to filterList
    }

    // Remove any trailing forward slashes in the filterList[ex: app/ becomes app]
    for i, _ := range filterList {
        filterList[i] = strings.TrimSuffix(filterList[i], "/")
        filterList[i] = "/"+filterList[i]
    }

    return filterList
}
/*
*	This function must be implemented by any plugin because it is part of the
*	plugin interface defined by the core CLI.
*
*	Run(....) is the entry point when the core CLI is invoking a command defined
*	by a plugin. The first parameter, plugin.CliConnection, is a struct that can
*	be used to invoke cli commands. The second paramter, args, is a slice of
*	strings. args[0] will be the name of the command, and will be followed by
*	any additional arguments a cli user typed in.
*
*	Any error handling should be handled with the plugin itself (this means printing
*	user facing errors). The CLI will exit 0 if the plugin exits 0 and will exit
*	1 should the plugin exits nonzero.
 */
func (c *downloadPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	// start time for download timer
	start := time.Now()
    proceed := true

    if len(args) < 2 {
			fmt.Println("\nError: Missing App Name")
			proceed = false
    }

    // Create flag
    omitp := flag.String("omit", "", "--omit path/to/some/file")
    overWritep := flag.Bool("overwrite", false, "--overwrite")
    maxRoutinesp := flag.Int("routines", 200, "--routines [numOfRoutines]")
    instancep := flag.Int("i", 0, "-i [instanceNum]")
    verbosep := flag.Bool("verbose", false, "--verbose")

    copyOfArgs := make([]string, len(args))         // need to copy args[] for later as they will be overwritten

    for i := 0; i < len(args); i++ {
           copyOfArgs[i] = args[i]
    }

    os.Args = append(os.Args[:1], args[2:]...)  // flag package parses os.Args
    appName = copyOfArgs[1]

    // check for misplaced flags
    if strings.HasPrefix(appName, "-") || strings.HasPrefix(appName, "--") {
        fmt.Println("\nError: App name begins with '-' or '--'. correct flag usage: 'cf download APP_NAME [--flags]'")
        proceed = false
    }

    // make sure the flags have valid input
    for i := 2; i < len(copyOfArgs); i++ {
        if len(args) > 2 && !strings.HasPrefix(copyOfArgs[2],"-") {    // has specified app dir/file

        } else {                                                       // no specified app dir/file

            temp := strings.TrimPrefix(copyOfArgs[i],"-")
            temp = strings.TrimPrefix(temp,"-")

            switch temp {
			case "omit":
			//	fmt.Printf("omit not recognized")
			case "verbose":
			//	fmt.Printf("verbose not recognized")
			case "overwrite":
			//	fmt.Printf("overwrite not recognized")
			case "i":
			//	fmt.Printf("i not recognized")
            case "routines":
          //      fmt.Printf("routines not recognized")
            default:
             //   fmt.Printf("Argument not recognized")
			}
        }

    }

    // Parse flags
    flag.Parse()

	// flag variables
	maxRoutines := *maxRoutinesp
	overWrite := *overWritep
	instance = strconv.Itoa(*instancep)
	verbose = *verbosep

	runtime.GOMAXPROCS(maxRoutines)

    if proceed == false {
        os.Exit(1)
    } else {
        filterList := getFilterList(*omitp)             // get list of things to not download
		workingDir, err := os.Getwd()
		check(cliError{err: err, errMsg: "Called by: Run"})
		rootWorkingDirectory = workingDir + "/" + appName + "-download/"

		// ensure cf_trace is disabled, otherwise parsing breaks
		if os.Getenv("CF_TRACE") == "true" {
			fmt.Println("\nError: environment variable CF_TRACE is set to true. This prevents download from succeeding.")
			return
		}

		// prevent overwriting files
		if exists(rootWorkingDirectory) && overWrite == false {
			fmt.Println("\nError: destination path", rootWorkingDirectory, "already exists and is not an empty directory. Delete it or use 'cf download APP_NAME --overwrite'")
			return
		}

		// append path if provided as arguement
		startingPath := "/"
		if len(args) > 2 && !strings.HasPrefix(copyOfArgs[2],"-"){
			startingPath = copyOfArgs[2]
			if !strings.HasSuffix(startingPath, "/") {
				startingPath += "/"
			}
            rootWorkingDirectory += startingPath
		}

		// parse the directory
		files, dirs := execParseDir(startingPath)

		fmt.Printf("Files completed: %d", filesDownloaded)

		// stop consoleWriter
		quit := make(chan int)
		// disable consoleWriter if verbose
		if verbose == false {
			go consoleWriter(quit)
		}

		// Start the download
		wg.Add(1)
		download(files, dirs, startingPath, rootWorkingDirectory, filterList)

		// Wait for download goRoutines
		wg.Wait()

		// stop console writer
		if verbose == false {
			quit <- 0
		}

		// let user know if any files were inaccessible
		if len(failedDownloads) == 1 {
			fmt.Println("")
			fmt.Println(len(failedDownloads), "file was not downloaded (inaccessible or corrupt):")
			printSlice(failedDownloads)
		} else if len(failedDownloads) > 1 {
			fmt.Println("")
			fmt.Println(len(failedDownloads), "files were not downloaded (inaccessible or corrupt):")
			printSlice(failedDownloads)
		}

		// display runtime
		elapsed := time.Since(start)
		fmt.Printf("\nDownload time: %s\n", elapsed)

		msg := ansi.Color(appName+" Successfully Downloaded!", "green+b")
		fmt.Println(msg)
	}
}

/*
*	consoleWriter prints the current number of files downloaded. It is polled every 350 milleseconds
* 	disabled if using verbose flag.
 */
func consoleWriter(quit chan int) {
	count := 0
	for {
		select {
		case <-quit:
			return
		default:
			switch count = (count + 1) % 4; count {
			case 0:
				fmt.Printf("\rFiles completed: %d \\ ", filesDownloaded)
			case 1:
				fmt.Printf("\rFiles completed: %d | ", filesDownloaded)
			case 2:
				fmt.Printf("\rFiles completed: %d / ", filesDownloaded)
			case 3:
				fmt.Printf("\rFiles completed: %d --", filesDownloaded)
			}
			time.Sleep(350 * time.Millisecond)
		}
	}
}

/*
*	execParseDir() uses os/exec to shell out commands to cf files with the given readPath. The returned
*	text contains file and directory structure which is then parsed into two slices, dirs and files. dirs
*	contains the names of directories in readPath, files contians the file names. dirs and files are returned
* 	to be downloaded by download() and downloadFile() respectively.
 */
func execParseDir(readPath string) ([]string, []string) {
	// make the cf files call using exec
	cmd := exec.Command("cf", "files", appName, readPath, "-i", instance)
	output, err := cmd.CombinedOutput()
	dirSlice := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid or missing app
	if strings.Contains(dirSlice[1], "not found") {
		errmsg := ansi.Color("Error: "+appName+" app not found (check space and org)", "red+b")
		fmt.Println(errmsg)
	}

	// this usually gets called when an app is not running and you attempt to download it.
	dir := dirSlice[2]
	if strings.Contains(dir, "error code: 190001") {
		errmsg := ansi.Color("App not found, possibly not yet running", "red+b")
		fmt.Println(errmsg)
		check(cliError{err: err, errMsg: "App not found"})
	}

	// handle an empty directory
	if strings.Contains(dir, "No files found") {
		return nil, nil
	} else {
		check(cliError{err: err, errMsg: "Called by: ExecParseDir [cf files " + appName + " " + readPath + "]"})
	}

	// parse the returned output into files and dirs slices
	filesSlice := strings.Fields(dir)
	var files, dirs []string
	for i := 0; i < len(filesSlice); i += 2 {
		if strings.HasSuffix(filesSlice[i], "/") {
			dirs = append(dirs, filesSlice[i])
		} else {
			files = append(files, filesSlice[i])
		}

	}
	return files, dirs
}

/*
*	downloadFile() takes a 'readPath' which corresponds to a file in the cf app. The file is
*	downloaded using the os/exec library to call cf files with the given readPath. The output is
*	written to a file at writePath.
 */
func downloadFile(readPath, writePath string, fileDownloadGroup *sync.WaitGroup) error {
	defer fileDownloadGroup.Done()

	// call cf files using os/exec
	cmd := exec.Command("cf", "files", appName, readPath, "-i", instance)
	output, err := cmd.CombinedOutput()
	file := strings.SplitAfterN(string(output), "\n", 3)

	// check for invalid file error.
	// some files are inaccesible from the cf files (reasons unknown) this is rare but we need to
	// alert users if it occurs
	fileAsString := file[2]
	if strings.Contains(file[1], "FAILED") {
		errormsg := ansi.Color(" Server Error: '"+readPath+"' not downloaded", "red")
		failedDownloads = append(failedDownloads, errormsg)
		fmt.Println(errormsg)
		return nil
	} else {
		// check for other errors
		check(cliError{err: err, errMsg: "Called by: downloadFile 1"})
	}

	// write downloaded file to writePath
	err = ioutil.WriteFile(writePath, []byte(fileAsString), 0644)
	check(cliError{err: err, errMsg: "Called by: downloadFile 2"})
	if verbose {
		fmt.Printf("Wrote file: %s\n", readPath)
	} else {
		// increment download counter for commandline display
		// see consoleWriter()
		filesDownloaded++
	}

	return nil
}

func checkToFilter(appPath string, filterList []string) bool {
    appPath = strings.TrimSuffix(appPath, "/")
    comparePath1 := strings.TrimPrefix(appPath, rootWorkingDirectory)

    for _, item := range filterList {
       if comparePath1 == item {
           return true
       }
    }

    return false
}

/*
*	given file and directory names, download() will download the files from
* 	'readPath' and write them to disk on the 'writepath'.
* 	the function calls it's self recursively for each directory as it travels down the tree.
* 	Each call runs on a seperate go routine and and calls a go routine for every
* 	file download.
 */
func download(files, dirs []string, readPath, writePath string, filterList []string) error {
	defer wg.Done()

	//create dir if does not exist
	err := os.MkdirAll(writePath, 0755)
	check(cliError{err: err, errMsg: "Called by: download"})

	// download each file
	for _, val := range files {
		fileWPath := writePath + val
		fileRPath := readPath + val

        if checkToFilter(fileRPath,filterList) {
			continue
		}

		wg.Add(1)
		go downloadFile(fileRPath, fileWPath, &wg)
	}

	// call download on every sub directory
	for _, val := range dirs {
		dirWPath := writePath + val
		dirRPath := readPath + val

        if checkToFilter(dirRPath,filterList) {
			continue
		}

		err := os.MkdirAll(dirWPath, 0755)
		check(cliError{err: err, errMsg: "Called by: download"})

		files, dirs = execParseDir(dirRPath)

		wg.Add(1)
		go download(files, dirs, dirRPath, dirWPath, filterList)
	}
	return nil
}

/*
*	This function must be implemented as part of the	plugin interface
*	defined by the core CLI.
*
*	GetMetadata() returns a PluginMetadata struct. The first field, Name,
*	determines the name of the plugin which should generally be without spaces.
*	If there are spaces in the name a user will need to properly quote the name
*	during uninstall otherwise the name will be treated as seperate arguments.
*	The second value is a slice of Command structs. Our slice only contains one
*	Command Struct, but could contain any number of them. The first field Name
*	defines the command `cf basic-plugin-command` once installed into the CLI. The
*	second field, HelpText, is used by the core CLI to display help information
*	to the user in the core commands `cf help`, `cf`, or `cf -h`.
 */
func (c *downloadPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "download",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 1,
			Build: 1,
		},
		Commands: []plugin.Command{
			plugin.Command{
				Name:     "download",
				HelpText: "Download contents of targeted directory",

				// UsageDetails is optional
				// It is used to show help of usage of each command
				UsageDetails: plugin.Usage{
					Usage: "cf download APP_NAME [PATH] [--flags]",
					Options: map[string]string{
						"overwrite": "overwrite files",
						"verbose":   "verbose",
						"omit":      "omit directory or file",
						"routines":  "max number of concurrent subroutines (default 200)",
						"i":         "instance",
					},
				},
			},
		},
	}
}

// error check function
func check(e cliError) {
	if e.err != nil {
		fmt.Println("\nError: ", e.err)
		if e.errMsg != "" {
			fmt.Println("Message: ", e.errMsg)
		}
		os.Exit(1)
	}
}

// prints slices in readable format
func printSlice(slice []string) error {
	for index, val := range slice {
		fmt.Println(index+1, ": ", val)
	}
	return nil
}

// exists returns whether the given file or directory exists or not
func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	check(cliError{err: err, errMsg: "Called by: exists"})
	return false
}

/*
* Unlike most Go programs, the `Main()` function will not be used to run all of the
* commands provided in your plugin. Main will be used to initialize the plugin
* process, as well as any dependencies you might require for your
* plugin.
 */
func main() {
	// Any initialization for your plugin can be handled here

	// Note: The plugin's main() method is invoked at install time to collect
	// metadata. The plugin will exit 0 and the Run([]string) method will not be
	// invoked.
	plugin.Start(new(downloadPlugin))
	// Plugin code should be written in the Run([]string) method,
	// ensuring the plugin environment is bootstrapped.
}
<|endoftext|>


<commit_before>package logtap

import "fmt"
import "github.com/pagodabox/golang-hatchet"

type Publisher interface {
	Publish(tags []string, data string)
}

type PublishDrain struct {
	log       hatchet.Logger
	publisher Publisher
}

// NewPublishDrain creates a new publish drain and returns it
func NewPublishDrain(pub Publisher) *PublishDrain {
	return &PublishDrain{
		publisher: pub,
	}
}

// SetLogger really allows the logtap main struct
// to assign its own logger to the publsih drain
// the publsih drain doesnt use the logger but
// it is necessary to have the method to match the interface
// the assumption here is that the publisher will do its own loggin
func (p *PublishDrain) SetLogger(l hatchet.Logger) {
	p.log = l
}

// Write formats the data coming in on the message and drops it on the publish method
// in a format the publisher can use
func (p *PublishDrain) Write(msg Message) {
	p.log.Debug("[LOGTAP][publish][write]:[%s] %s", msg.Time, msg.Content)
	p.publisher.Publish([]string{"log", msg.Type}, fmt.Sprintf("{'time':%s, %s", msg.Time, msg.Content))
}
<commit_msg>better<commit_after>package logtap

import "fmt"
import "github.com/pagodabox/golang-hatchet"

type Publisher interface {
	Publish(tags []string, data string)
}

type PublishDrain struct {
	log       hatchet.Logger
	publisher Publisher
}

// NewPublishDrain creates a new publish drain and returns it
func NewPublishDrain(pub Publisher) *PublishDrain {
	return &PublishDrain{
		publisher: pub,
	}
}

// SetLogger really allows the logtap main struct
// to assign its own logger to the publsih drain
// the publsih drain doesnt use the logger but
// it is necessary to have the method to match the interface
// the assumption here is that the publisher will do its own loggin
func (p *PublishDrain) SetLogger(l hatchet.Logger) {
	p.log = l
}

// Write formats the data coming in on the message and drops it on the publish method
// in a format the publisher can use
func (p *PublishDrain) Write(msg Message) {
	p.log.Debug("[LOGTAP][publish][write]:[%s] %s", msg.Time, msg.Content)
	p.publisher.Publish([]string{"log", msg.Type}, fmt.Sprintf("{\"time\":\"%s\",\"log\":\"%s\"}", msg.Time, msg.Content))
}
<|endoftext|>


<commit_before>package pubsub

import (
	"fmt"
	"time"
)

type PubSub struct {
	subscribers []chan *Message
	Stats
}

func cloneMessage(from *Message) *Message {
	m := &Message{}
	if from != nil {
		m.CreatedAt = from.CreatedAt
		m.Duration = from.Duration
		m.Level = from.Level
		m.Payload = from.Payload
	}
	if m.CreatedAt.IsZero() {
		m.CreatedAt = time.Now()
	}
	return m
}

func (pubsub *PubSub) Publish(key, messageText string, message *Message) error {
	m := cloneMessage(message)
	m.Key = key
	m.Message = messageText
	pubsub.Stats.MessageReceived()
	var e error
	for _, s := range pubsub.subscribers {
		select {
		case s <- m:
			pubsub.Stats.MessageDispatched()
		default:
			e = fmt.Errorf("unable to publish to %v", s)
		}
	}
	return e
}

func (pubsub *PubSub) SubscribersCount() int {
	return len(pubsub.subscribers)
}

//  could not be bother to fight with locking just now
// func (pubsub *PubSub) Unsubscribe(c chan *Message) {
// implement me
// }

func (pubsub *PubSub) Subscribe(patten string, c chan *Message) chan *Message {
	pubsub.subscribers = append(pubsub.subscribers, c)
	return c
}
<commit_msg>no need to return the channel<commit_after>package pubsub

import (
	"fmt"
	"time"
)

type PubSub struct {
	subscribers []chan *Message
	Stats
}

func cloneMessage(from *Message) *Message {
	m := &Message{}
	if from != nil {
		m.CreatedAt = from.CreatedAt
		m.Duration = from.Duration
		m.Level = from.Level
		m.Payload = from.Payload
	}
	if m.CreatedAt.IsZero() {
		m.CreatedAt = time.Now()
	}
	return m
}

func (pubsub *PubSub) Publish(key, messageText string, message *Message) error {
	m := cloneMessage(message)
	m.Key = key
	m.Message = messageText
	pubsub.Stats.MessageReceived()
	var e error
	for _, s := range pubsub.subscribers {
		select {
		case s <- m:
			pubsub.Stats.MessageDispatched()
		default:
			e = fmt.Errorf("unable to publish to %v", s)
		}
	}
	return e
}

func (pubsub *PubSub) SubscribersCount() int {
	return len(pubsub.subscribers)
}

//  could not be bother to fight with locking just now
// func (pubsub *PubSub) Unsubscribe(c chan *Message) {
// implement me
// }

func (pubsub *PubSub) Subscribe(patten string, c chan *Message) {
	pubsub.subscribers = append(pubsub.subscribers, c)
}
<|endoftext|>


<commit_before>package thor

import (
	"io"
	"strconv"

	"github.com/skelterjohn/gopp"
)

const grammar = `
ignore: /^#.*\n/
ignore: /^(?:[ \t\n])+/

Doc => {type=Node} {field=Key} {/}

Table => {field=Type} {table} {field=Kids} <<Node>>*
Node => {type=Node} {field=Key} <id> ':' <Value>
Node => {type=Node} <Value>
Value => {type=Node} '{'
 '}'
Value => {type=Node} {field=Type} {num} {field=Val} <num>
Value => {type=Node} {field=Type} {bool} {field=Val} <bool>
Value => {type=Node} {field=Type} {str} {field=Val} <str>

num = /([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/
bool = /(true|false)/
str = /"((?:[^"\\]|\\.)*)"/
id = /([\pL][\pL\pN\-_]*)/
`

var (
	decFact *gopp.DecoderFactory
)

func init() {
	var err error
	decFact, err = gopp.NewDecoderFactory(grammar, "Doc")
	if err != nil {
		panic(err)
	}
	decFact.RegisterType(Node{})
}

type Node struct {
	Key  string
	Val  string
	Type string
	Kids []Node
}

func (n Node) String() string {
	s := ""
	switch n.Type {
	case "table":
		for i := range n.Kids {
			s += n.Kids[i].String()
			if i < len(n.Kids)-1 {
				s += " "
			}
		}
	case "str":
		s = strconv.Quote(n.Val)
	default:
		s = n.Val
	}
	if n.Type == "table" && n.Key != "/" {
		s = "{" + s + "}"
	}
	if n.Key != "" && n.Key != "/" {
		s = n.Key + ":" + s
	}
	return s
}

func Parse(in io.Reader) (*Node, error) {
	dec := decFact.NewDecoder(in)
	tree := &Node{}
	err := dec.Decode(tree)
	return tree, err
}
<commit_msg>Simplified whitespace regex.<commit_after>package thor

import (
	"io"
	"strconv"

	"github.com/skelterjohn/gopp"
)

const grammar = `
ignore: /^#.*\n/
ignore: /^\s+/

Doc => {type=Node} {field=Key} {/}

Table => {field=Type} {table} {field=Kids} <<Node>>*
Node => {type=Node} {field=Key} <id> ':' <Value>
Node => {type=Node} <Value>
Value => {type=Node} '{'
 '}'
Value => {type=Node} {field=Type} {num} {field=Val} <num>
Value => {type=Node} {field=Type} {bool} {field=Val} <bool>
Value => {type=Node} {field=Type} {str} {field=Val} <str>

num = /([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)/
bool = /(true|false)/
str = /"((?:[^"\\]|\\.)*)"/
id = /([\pL][\pL\pN\-_]*)/
`

var (
	decFact *gopp.DecoderFactory
)

func init() {
	var err error
	decFact, err = gopp.NewDecoderFactory(grammar, "Doc")
	if err != nil {
		panic(err)
	}
	decFact.RegisterType(Node{})
}

type Node struct {
	Key  string
	Val  string
	Type string
	Kids []Node
}

func (n Node) String() string {
	s := ""
	switch n.Type {
	case "table":
		for i := range n.Kids {
			s += n.Kids[i].String()
			if i < len(n.Kids)-1 {
				s += " "
			}
		}
	case "str":
		s = strconv.Quote(n.Val)
	default:
		s = n.Val
	}
	if n.Type == "table" && n.Key != "/" {
		s = "{" + s + "}"
	}
	if n.Key != "" && n.Key != "/" {
		s = n.Key + ":" + s
	}
	return s
}

func Parse(in io.Reader) (*Node, error) {
	dec := decFact.NewDecoder(in)
	tree := &Node{}
	err := dec.Decode(tree)
	return tree, err
}
<|endoftext|>


<commit_before>package main

var defaultSMSTemplate = []byte(`summary
== total: {{.Total}} fail: {{.FailCount}} ==
- host: {{.Host}}
- time: {{.TimeCost}}`)

var defaultTemplate = []byte(`<!DOCTYPE html>

        <meta charset="utf-8" />
		<title>travelexec report</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" type="text/css" href="style.css" />

		<link rel="stylesheet" href="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/css/bootstrap.min.css">

					Travelexec report created by: travelexec

Start time:	{{.StartTime}}

Time cost:	{{.TimeCost}}

Fail count:	{{.FailCount}}

Total:	{{.Total}}

Run host:	{{.Host}}

						<button id="btn-show-failed" class="btn btn-default btn-danger">Only Show Failed</button>

			{{range .Tasks}}

					{{.Command}} - {{.TimeCost}} {{.Error}}

						<button class="btn btn-xs btn-info view-output">view output</button>
						<button class="btn btn-xs btn-primary view-source">view source(TODO)</button>

start time: {{.StartTime}}

time cost: {{.TimeCost}}

command: {{.Command}}

{{.Source}}

{{.Output}}

			{{end}}

				&copy author: skyblue

`)
<commit_msg>fix page(which contains not exists style.css)<commit_after>package main

var defaultSMSTemplate = []byte(`summary
== total: {{.Total}} fail: {{.FailCount}} ==
- host: {{.Host}}
- time: {{.TimeCost}}`)

var defaultTemplate = []byte(`<!DOCTYPE html>

        <meta charset="utf-8" />
		<title>travelexec report</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">

		<link rel="stylesheet" href="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/css/bootstrap.min.css">

					Travelexec report created by: travelexec

Start time:	{{.StartTime}}

Time cost:	{{.TimeCost}}

Fail count:	{{.FailCount}}

Total:	{{.Total}}

Run host:	{{.Host}}

						<button id="btn-show-failed" class="btn btn-default btn-danger">Only Show Failed</button>

			{{range .Tasks}}

					{{.Command}} - {{.TimeCost}} {{.Error}}

						<button class="btn btn-xs btn-info view-output">view output</button>
						<button class="btn btn-xs btn-primary view-source">view source(TODO)</button>

start time: {{.StartTime}}

time cost: {{.TimeCost}}

command: {{.Command}}

{{.Source}}

{{.Output}}

			{{end}}

				&copy author: skyblue

`)
<|endoftext|>


<commit_before>package query

import (
	"context"
	"fmt"

	"github.com/influxdata/flux"
	"github.com/influxdata/flux/execute"
	"github.com/influxdata/flux/memory"
	"github.com/influxdata/flux/plan"
	"github.com/influxdata/influxdb/v2"
	"github.com/influxdata/influxdb/v2/storage/reads/datatypes"
	"github.com/influxdata/influxdb/v2/tsdb/cursors"
)

// StorageReader is an interface for reading tables from the storage subsystem.
type StorageReader interface {
	ReadFilter(ctx context.Context, spec ReadFilterSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadGroup(ctx context.Context, spec ReadGroupSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadWindowAggregate(ctx context.Context, spec ReadWindowAggregateSpec, alloc *memory.Allocator) (TableIterator, error)

	ReadTagKeys(ctx context.Context, spec ReadTagKeysSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadTagValues(ctx context.Context, spec ReadTagValuesSpec, alloc *memory.Allocator) (TableIterator, error)

	Close()
}

type ReadFilterSpec struct {
	OrganizationID influxdb.ID
	BucketID       influxdb.ID

	Bounds    execute.Bounds
	Predicate *datatypes.Predicate
}

type ReadGroupSpec struct {
	ReadFilterSpec

	GroupMode GroupMode
	GroupKeys []string

	AggregateMethod string
}

func (spec *ReadGroupSpec) Name() string {
	return fmt.Sprintf("readGroup(%s)", spec.AggregateMethod)
}

type ReadTagKeysSpec struct {
	ReadFilterSpec
}

type ReadTagValuesSpec struct {
	ReadFilterSpec
	TagKey string
}

type ReadWindowAggregateSpec struct {
	ReadFilterSpec
	WindowEvery int64
	Offset      int64
	Aggregates  []plan.ProcedureKind
	CreateEmpty bool
	TimeColumn  string
	Window      execute.Window
}

func (spec *ReadWindowAggregateSpec) Name() string {
	var agg string
	if len(spec.Aggregates) > 0 {
		agg = string(spec.Aggregates[0])
	}
	return fmt.Sprintf("readWindow(%s)", agg)
}

// TableIterator is a table iterator that also keeps track of cursor statistics from the storage engine.
type TableIterator interface {
	flux.TableIterator
	Statistics() cursors.CursorStats
}

type GroupMode int

const (
	// GroupModeNone merges all series into a single group.
	GroupModeNone GroupMode = iota
	// GroupModeBy produces a table for each unique value of the specified GroupKeys.
	GroupModeBy
)

// ToGroupMode accepts the group mode from Flux and produces the appropriate storage group mode.
func ToGroupMode(fluxMode flux.GroupMode) GroupMode {
	switch fluxMode {
	case flux.GroupModeNone:
		return GroupModeNone
	case flux.GroupModeBy:
		return GroupModeBy
	default:
		panic(fmt.Sprint("unknown group mode: ", fluxMode))
	}
}
<commit_msg>fix: update comment about ReadWindowAggregate semantics<commit_after>package query

import (
	"context"
	"fmt"

	"github.com/influxdata/flux"
	"github.com/influxdata/flux/execute"
	"github.com/influxdata/flux/memory"
	"github.com/influxdata/flux/plan"
	"github.com/influxdata/influxdb/v2"
	"github.com/influxdata/influxdb/v2/storage/reads/datatypes"
	"github.com/influxdata/influxdb/v2/tsdb/cursors"
)

// StorageReader is an interface for reading tables from the storage subsystem.
type StorageReader interface {
	ReadFilter(ctx context.Context, spec ReadFilterSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadGroup(ctx context.Context, spec ReadGroupSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadWindowAggregate(ctx context.Context, spec ReadWindowAggregateSpec, alloc *memory.Allocator) (TableIterator, error)

	ReadTagKeys(ctx context.Context, spec ReadTagKeysSpec, alloc *memory.Allocator) (TableIterator, error)
	ReadTagValues(ctx context.Context, spec ReadTagValuesSpec, alloc *memory.Allocator) (TableIterator, error)

	Close()
}

type ReadFilterSpec struct {
	OrganizationID influxdb.ID
	BucketID       influxdb.ID

	Bounds    execute.Bounds
	Predicate *datatypes.Predicate
}

type ReadGroupSpec struct {
	ReadFilterSpec

	GroupMode GroupMode
	GroupKeys []string

	AggregateMethod string
}

func (spec *ReadGroupSpec) Name() string {
	return fmt.Sprintf("readGroup(%s)", spec.AggregateMethod)
}

type ReadTagKeysSpec struct {
	ReadFilterSpec
}

type ReadTagValuesSpec struct {
	ReadFilterSpec
	TagKey string
}

// Window and the WindowEvery/Offset should be mutually exclusive. If you set either the WindowEvery or Offset with
// nanosecond values, then the Window will be ignored
type ReadWindowAggregateSpec struct {
	ReadFilterSpec
	WindowEvery int64
	Offset      int64
	Aggregates  []plan.ProcedureKind
	CreateEmpty bool
	TimeColumn  string
	Window      execute.Window
}

func (spec *ReadWindowAggregateSpec) Name() string {
	var agg string
	if len(spec.Aggregates) > 0 {
		agg = string(spec.Aggregates[0])
	}
	return fmt.Sprintf("readWindow(%s)", agg)
}

// TableIterator is a table iterator that also keeps track of cursor statistics from the storage engine.
type TableIterator interface {
	flux.TableIterator
	Statistics() cursors.CursorStats
}

type GroupMode int

const (
	// GroupModeNone merges all series into a single group.
	GroupModeNone GroupMode = iota
	// GroupModeBy produces a table for each unique value of the specified GroupKeys.
	GroupModeBy
)

// ToGroupMode accepts the group mode from Flux and produces the appropriate storage group mode.
func ToGroupMode(fluxMode flux.GroupMode) GroupMode {
	switch fluxMode {
	case flux.GroupModeNone:
		return GroupModeNone
	case flux.GroupModeBy:
		return GroupModeBy
	default:
		panic(fmt.Sprint("unknown group mode: ", fluxMode))
	}
}
<|endoftext|>