<commit_before>package rollrus

import (
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/stvp/roll"
)

var defaultTriggerLevels = []log.Level{
	log.ErrorLevel,
	log.FatalLevel,
	log.PanicLevel,
}

// Hook wrapper for the rollbar Client
// May be used as a rollbar client itself
type Hook struct {
	roll.Client
	triggers []log.Level
}

// SetupLogging sets up logging. If token is not an empty string a rollbar
// hook is added with the environment set to env. The log formatter is set to a
// TextFormatter with timestamps disabled, which is suitable for use on Heroku.
func SetupLogging(token, env string) {
	setupLogging(token, env, defaultTriggerLevels)
}

// SetupInstanceLogging sets up logging just like SetupLogging, but it works
// against an instance of a logrus Logger, rather than the package level/global
// logger.
func SetupInstanceLogging(l *log.Logger, token, env string) {
	setupInstanceLogging(l, token, env, defaultTriggerLevels)
}

// SetupLoggingForLevels works like SetupLogging, but allows you to
// set the levels on which to trigger this hook.
func SetupLoggingForLevels(token, env string, levels []log.Level) {
	setupLogging(token, env, levels)
}

// SetupInstanceLoggingForLevels works like SetupInstanceLogging, but allows
// you to set the levels on which to trigger this hook.
func SetupInstanceLoggingForLevels(l *log.Logger, token, env string, levels []log.Level) {
	setupInstanceLogging(l, token, env, levels)
}

func setupLogging(token, env string, levels []log.Level) {
	log.SetFormatter(&log.TextFormatter{DisableTimestamp: true})

	if token != "" {
		log.AddHook(&Hook{Client: roll.New(token, env), triggers: levels})
	}
}

func setupInstanceLogging(l *log.Logger, token, env string, levels []log.Level) {
	if token != "" {
		l.Hooks.Add(&Hook{Client: roll.New(token, env), triggers: levels})
	}
}

// ReportPanic attempts to report the panic to rollbar using the provided
// client and then re-panic. If it can't report the panic it will print an
// error to stderr.
func (r *Hook) ReportPanic() {
	if p := recover(); p != nil {
		if _, err := r.Client.Critical(fmt.Errorf("panic: %q", p), nil); err != nil {
			fmt.Fprintf(os.Stderr, "reporting_panic=false err=%q\n", err)
		}
		panic(p)
	}
}

// ReportPanic attempts to report the panic to rollbar if the token is set
func ReportPanic(token, env string) {
	if token != "" {
		h := &Hook{Client: roll.New(token, env)}
		h.ReportPanic()
	}
}

// Fire the hook. This is called by Logrus for entries that match the levels
// returned by Levels(). See below.
func (r *Hook) Fire(entry *log.Entry) (err error) {
	e := fmt.Errorf(entry.Message)
	m := convertFields(entry.Data)
	if _, exists := m["time"]; !exists {
		m["time"] = entry.Time.Format(time.RFC3339)
	}

	switch entry.Level {
	case log.FatalLevel, log.PanicLevel:
		_, err = r.Client.Critical(e, m)
	case log.ErrorLevel:
		_, err = r.Client.Error(e, m)
	case log.WarnLevel:
		_, err = r.Client.Warning(e, m)
	case log.InfoLevel:
		_, err = r.Client.Info(entry.Message, m)
	case log.DebugLevel:
		_, err = r.Client.Debug(entry.Message, m)
	default:
		return fmt.Errorf("Unknown level: %s", entry.Level)
	}

	return err
}

// Levels returns the logrus log levels that this hook handles
func (r *Hook) Levels() []log.Level {
	if r.triggers == nil {
		return defaultTriggerLevels
	}
	return r.triggers
}

// convertFields converts from log.Fields to map[string]string so that we can
// report extra fields to Rollbar
func convertFields(fields log.Fields) map[string]string {
	m := make(map[string]string)
	for k, v := range fields {
		switch t := v.(type) {
		case time.Time:
			m[k] = t.Format(time.RFC3339)
		default:
			if s, ok := v.(fmt.Stringer); ok {
				m[k] = s.String()
			} else {
				m[k] = fmt.Sprintf("%+v", t)
			}
		}
	}

	return m
}
<commit_msg>Provide a NewHook() method<commit_after>package rollrus

import (
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/stvp/roll"
)

var defaultTriggerLevels = []log.Level{
	log.ErrorLevel,
	log.FatalLevel,
	log.PanicLevel,
}

// Hook wrapper for the rollbar Client
// May be used as a rollbar client itself
type Hook struct {
	roll.Client
	triggers []log.Level
}

// Setup a new hook with default reporting levels, useful for adding to
// your own logger instance.
func NewHook(token string, env string) Hook {
	return Hook{
		Client: roll.New(token, env),
		triggers: defaultTriggerLevels,
	}
}

// Setup a new hook with specified reporting levels, useful for adding to
// your own logger instance.
func NewHookForLevels(token string, env string, levels []log.Level) *Hook {
	return &Hook{
		Client: roll.New(token, env),
		triggers: levels,
	}
}

// SetupLogging sets up logging. If token is not an empty string a rollbar
// hook is added with the environment set to env. The log formatter is set to a
// TextFormatter with timestamps disabled, which is suitable for use on Heroku.
func SetupLogging(token, env string) {
	setupLogging(token, env, defaultTriggerLevels)
}

// SetupLoggingForLevels works like SetupLogging, but allows you to
// set the levels on which to trigger this hook.
func SetupLoggingForLevels(token, env string, levels []log.Level) {
	setupLogging(token, env, levels)
}

func setupLogging(token, env string, levels []log.Level) {
	log.SetFormatter(&log.TextFormatter{DisableTimestamp: true})

	if token != "" {
		log.AddHook(NewHookForLevels(token, env, levels))
	}
}

// ReportPanic attempts to report the panic to rollbar using the provided
// client and then re-panic. If it can't report the panic it will print an
// error to stderr.
func (r *Hook) ReportPanic() {
	if p := recover(); p != nil {
		if _, err := r.Client.Critical(fmt.Errorf("panic: %q", p), nil); err != nil {
			fmt.Fprintf(os.Stderr, "reporting_panic=false err=%q\n", err)
		}
		panic(p)
	}
}

// ReportPanic attempts to report the panic to rollbar if the token is set
func ReportPanic(token, env string) {
	if token != "" {
		h := &Hook{Client: roll.New(token, env)}
		h.ReportPanic()
	}
}

// Fire the hook. This is called by Logrus for entries that match the levels
// returned by Levels(). See below.
func (r *Hook) Fire(entry *log.Entry) (err error) {
	e := fmt.Errorf(entry.Message)
	m := convertFields(entry.Data)
	if _, exists := m["time"]; !exists {
		m["time"] = entry.Time.Format(time.RFC3339)
	}

	switch entry.Level {
	case log.FatalLevel, log.PanicLevel:
		_, err = r.Client.Critical(e, m)
	case log.ErrorLevel:
		_, err = r.Client.Error(e, m)
	case log.WarnLevel:
		_, err = r.Client.Warning(e, m)
	case log.InfoLevel:
		_, err = r.Client.Info(entry.Message, m)
	case log.DebugLevel:
		_, err = r.Client.Debug(entry.Message, m)
	default:
		return fmt.Errorf("Unknown level: %s", entry.Level)
	}

	return err
}

// Levels returns the logrus log levels that this hook handles
func (r *Hook) Levels() []log.Level {
	if r.triggers == nil {
		return defaultTriggerLevels
	}
	return r.triggers
}

// convertFields converts from log.Fields to map[string]string so that we can
// report extra fields to Rollbar
func convertFields(fields log.Fields) map[string]string {
	m := make(map[string]string)
	for k, v := range fields {
		switch t := v.(type) {
		case time.Time:
			m[k] = t.Format(time.RFC3339)
		default:
			if s, ok := v.(fmt.Stringer); ok {
				m[k] = s.String()
			} else {
				m[k] = fmt.Sprintf("%+v", t)
			}
		}
	}

	return m
}
<|endoftext|>


<commit_before>package dht

import (
	"bytes"
	"encoding/json"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	peer "github.com/jbenet/go-ipfs/peer"
	kb "github.com/jbenet/go-ipfs/routing/kbucket"
	u "github.com/jbenet/go-ipfs/util"
)

// This file implements the Routing interface for the IpfsDHT struct.

// Basic Put/Get

// PutValue adds value corresponding to given Key.
// This is the top level "Store" operation of the DHT
func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error {
	peers := []*peer.Peer{}

	// get the peers we need to announce to
	for _, route := range dht.routingTables {
		npeers := route.NearestPeers(kb.ConvertKey(key), KValue)
		peers = append(peers, npeers...)
	}

	query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		u.DOut("[%s] PutValue qry part %v\n", dht.self.ID.Pretty(), p.ID.Pretty())
		err := dht.putValueToNetwork(ctx, p, string(key), value)
		if err != nil {
			return nil, err
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err := query.Run(ctx, peers)
	u.DOut("[%s] PutValue %v %v\n", dht.self.ID.Pretty(), key, value)
	return err
}

// GetValue searches for the value corresponding to given Key.
// If the search does not succeed, a multiaddr string of a closer peer is
// returned along with util.ErrSearchIncomplete
func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
	ll := startNewRPC("GET")
	defer ll.EndAndPrint()

	// If we have it local, dont bother doing an RPC!
	// NOTE: this might not be what we want to do...
	val, err := dht.getLocal(key)
	if err == nil {
		ll.Success = true
		return val, nil
	}

	// get closest peers in the routing tables
	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertKey(key), PoolSize)
	if closest == nil || len(closest) == 0 {
		return nil, nil
	}

	// setup the Query
	query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {

		val, peers, err := dht.getValueOrPeers(ctx, p, key, routeLevel)
		if err != nil {
			return nil, err
		}

		res := &dhtQueryResult{value: val, closerPeers: peers}
		if val != nil {
			res.success = true
		}

		return res, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	u.DOut("[%s] GetValue %v %v\n", dht.self.ID.Pretty(), key, result.value)
	if result.value == nil {
		return nil, u.ErrNotFound
	}

	return result.value, nil
}

// Value provider layer of indirection.
// This is what DSHTs (Coral and MainlineDHT) do to store large values in a DHT.

// Provide makes this node announce that it can provide a value for the given key
func (dht *IpfsDHT) Provide(ctx context.Context, key u.Key) error {

	dht.providers.AddProvider(key, dht.self)
	peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), PoolSize)
	if len(peers) == 0 {
		// Early out for no targets
		return nil
	}

	//TODO FIX: this doesn't work! it needs to be sent to the actual nearest peers.
	// `peers` are the closest peers we have, not the ones that should get the value.
	for _, p := range peers {
		err := dht.putProvider(ctx, p, string(key))
		if err != nil {
			return err
		}
	}
	return nil
}

// NB: not actually async. Used to keep the interface consistent while the
// actual async method, FindProvidersAsync2 is under construction
func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan *peer.Peer {
	ch := make(chan *peer.Peer)
	providers, err := dht.FindProviders(ctx, key)
	if err != nil {
		close(ch)
		return ch
	}
	go func() {
		defer close(ch)
		for _, p := range providers {
			ch <- p
		}
	}()
	return ch
}

// FIXME: there's a bug here!
func (dht *IpfsDHT) FindProvidersAsync2(ctx context.Context, key u.Key, count int) <-chan *peer.Peer {
	peerOut := make(chan *peer.Peer, count)
	go func() {
		ps := newPeerSet()
		provs := dht.providers.GetProviders(key)
		for _, p := range provs {
			count--
			// NOTE: assuming that this list of peers is unique
			ps.Add(p)
			peerOut <- p
			if count <= 0 {
				return
			}
		}

		peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), AlphaValue)
		for _, pp := range peers {
			go func(p *peer.Peer) {
				pmes, err := dht.findProvidersSingle(p, key, 0, timeout)
				if err != nil {
					u.PErr("%v\n", err)
					return
				}
				dht.addPeerListAsync(key, pmes.GetPeers(), ps, count, peerOut)
			}(pp)
		}

	}()
	return peerOut
}

//TODO: this function could also be done asynchronously
func (dht *IpfsDHT) addPeerListAsync(k u.Key, peers []*Message_Peer, ps *peerSet, count int, out chan *peer.Peer) {
	for _, pbp := range peers {

		// construct new peer
		p, err := dht.ensureConnectedToPeer(pbp)
		if err != nil {
			continue
		}

		dht.providers.AddProvider(k, p)
		if ps.AddIfSmallerThan(p, count) {
			out <- p
		} else if ps.Size() >= count {
			return
		}
	}
}

// FindProviders searches for peers who can provide the value for given key.
func (dht *IpfsDHT) FindProviders(ctx context.Context, key u.Key) ([]*peer.Peer, error) {
	ll := startNewRPC("FindProviders")
	ll.EndAndPrint()

	// get closest peer
	u.DOut("Find providers for: '%s'\n", key)
	p := dht.routingTables[0].NearestPeer(kb.ConvertKey(key))
	if p == nil {
		return nil, nil
	}

	for level := 0; level < len(dht.routingTables); {

		// attempt retrieving providers
		pmes, err := dht.findProvidersSingle(ctx, p, key, level)
		if err != nil {
			return nil, err
		}

		// handle providers
		provs := pmes.GetProviderPeers()
		if provs != nil {
			u.DOut("Got providers back from findProviders call!\n")
			return dht.addProviders(key, provs), nil
		}

		u.DOut("Didnt get providers, just closer peers.\n")
		closer := pmes.GetCloserPeers()
		if len(closer) == 0 {
			level++
			continue
		}

		np, err := dht.peerFromInfo(closer[0])
		if err != nil {
			u.DOut("no peerFromInfo")
			level++
			continue
		}
		p = np
	}
	return nil, u.ErrNotFound
}

// Find specific Peer

// FindPeer searches for a peer with given ID.
func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (*peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.Find(id)
	if p != nil {
		return p, nil
	}

	// @whyrusleeping why is this here? doesn't the dht.Find above cover it?
	routeLevel := 0
	p = dht.routingTables[routeLevel].NearestPeer(kb.ConvertPeerID(id))
	if p == nil {
		return nil, nil
	}
	if p.ID.Equal(id) {
		return p, nil
	}

	for routeLevel < len(dht.routingTables) {
		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		plist := pmes.GetCloserPeers()
		if plist == nil || len(plist) == 0 {
			routeLevel++
			continue
		}
		found := plist[0]

		nxtPeer, err := dht.ensureConnectedToPeer(found)
		if err != nil {
			routeLevel++
			continue
		}

		if nxtPeer.ID.Equal(id) {
			return nxtPeer, nil
		}

		p = nxtPeer
	}
	return nil, u.ErrNotFound
}

func (dht *IpfsDHT) findPeerMultiple(ctx context.Context, id peer.ID) (*peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.Find(id)
	if p != nil {
		return p, nil
	}

	// get the peers we need to announce to
	routeLevel := 0
	peers := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
	if len(peers) == 0 {
		return nil, nil
	}

	// setup query function
	query := newQuery(u.Key(id), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		if err != nil {
			u.DErr("getPeer error: %v\n", err)
			return nil, err
		}

		plist := pmes.GetCloserPeers()
		if len(plist) == 0 {
			routeLevel++
		}

		nxtprs := make([]*peer.Peer, len(plist))
		for i, fp := range plist {
			nxtp, err := dht.peerFromInfo(fp)
			if err != nil {
				u.DErr("findPeer error: %v\n", err)
				continue
			}

			if nxtp.ID.Equal(id) {
				return &dhtQueryResult{peer: nxtp, success: true}, nil
			}

			nxtprs[i] = nxtp
		}

		return &dhtQueryResult{closerPeers: nxtprs}, nil
	})

	result, err := query.Run(ctx, peers)
	if err != nil {
		return nil, err
	}

	if result.peer == nil {
		return nil, u.ErrNotFound
	}
	return result.peer, nil
}

// Ping a peer, log the time it took
func (dht *IpfsDHT) Ping(ctx context.Context, p *peer.Peer) error {
	// Thoughts: maybe this should accept an ID and do a peer lookup?
	u.DOut("[%s] ping %s start\n", dht.self.ID.Pretty(), p.ID.Pretty())

	pmes := newMessage(Message_PING, "", 0)
	_, err := dht.sendRequest(ctx, p, pmes)
	u.DOut("[%s] ping %s end (err = %s)\n", dht.self.ID.Pretty(), p.ID.Pretty(), err)
	return err
}

func (dht *IpfsDHT) getDiagnostic(ctx context.Context) ([]*diagInfo, error) {

	u.DOut("Begin Diagnostic")
	peers := dht.routingTables[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
	var out []*diagInfo

	query := newQuery(dht.self.Key(), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		pmes := newMessage(Message_DIAGNOSTIC, "", 0)
		rpmes, err := dht.sendRequest(ctx, p, pmes)
		if err != nil {
			return nil, err
		}

		dec := json.NewDecoder(bytes.NewBuffer(rpmes.GetValue()))
		for {
			di := new(diagInfo)
			err := dec.Decode(di)
			if err != nil {
				break
			}

			out = append(out, di)
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err := query.Run(ctx, peers)
	return out, err
}
<commit_msg>add routing resolver test<commit_after>package dht

import (
	"bytes"
	"encoding/json"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	peer "github.com/jbenet/go-ipfs/peer"
	kb "github.com/jbenet/go-ipfs/routing/kbucket"
	u "github.com/jbenet/go-ipfs/util"
)

// This file implements the Routing interface for the IpfsDHT struct.

// Basic Put/Get

// PutValue adds value corresponding to given Key.
// This is the top level "Store" operation of the DHT
func (dht *IpfsDHT) PutValue(key u.Key, value []byte) error {
	err := dht.putLocal(key, value)
	if err != nil {
		return err
	}

	var peers []*peer.Peer
	for _, route := range dht.routingTables {
		npeers := route.NearestPeers(kb.ConvertKey(key), KValue)
		peers = append(peers, npeers...)
	}

	query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		u.DOut("[%s] PutValue qry part %v\n", dht.self.ID.Pretty(), p.ID.Pretty())
		err := dht.putValueToNetwork(ctx, p, string(key), value)
		if err != nil {
			return nil, err
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err := query.Run(ctx, peers)
	u.DOut("[%s] PutValue %v %v\n", dht.self.ID.Pretty(), key, value)
	return err
}

// GetValue searches for the value corresponding to given Key.
// If the search does not succeed, a multiaddr string of a closer peer is
// returned along with util.ErrSearchIncomplete
func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
	ll := startNewRPC("GET")
	defer ll.EndAndPrint()

	// If we have it local, dont bother doing an RPC!
	// NOTE: this might not be what we want to do...
	val, err := dht.getLocal(key)
	if err == nil {
		ll.Success = true
		return val, nil
	}

	// get closest peers in the routing tables
	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertKey(key), PoolSize)
	if closest == nil || len(closest) == 0 {
		return nil, nil
	}

	// setup the Query
	query := newQuery(key, func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {

		val, peers, err := dht.getValueOrPeers(ctx, p, key, routeLevel)
		if err != nil {
			return nil, err
		}

		res := &dhtQueryResult{value: val, closerPeers: peers}
		if val != nil {
			res.success = true
		}

		return res, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	u.DOut("[%s] GetValue %v %v\n", dht.self.ID.Pretty(), key, result.value)
	if result.value == nil {
		return nil, u.ErrNotFound
	}

	return result.value, nil
}

// Value provider layer of indirection.
// This is what DSHTs (Coral and MainlineDHT) do to store large values in a DHT.

// Provide makes this node announce that it can provide a value for the given key
func (dht *IpfsDHT) Provide(ctx context.Context, key u.Key) error {

	dht.providers.AddProvider(key, dht.self)
	peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), PoolSize)
	if len(peers) == 0 {
		// Early out for no targets
		return nil
	}

	//TODO FIX: this doesn't work! it needs to be sent to the actual nearest peers.
	// `peers` are the closest peers we have, not the ones that should get the value.
	for _, p := range peers {
		err := dht.putProvider(ctx, p, string(key))
		if err != nil {
			return err
		}
	}
	return nil
}

// NB: not actually async. Used to keep the interface consistent while the
// actual async method, FindProvidersAsync2 is under construction
func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan *peer.Peer {
	ch := make(chan *peer.Peer)
	providers, err := dht.FindProviders(ctx, key)
	if err != nil {
		close(ch)
		return ch
	}
	go func() {
		defer close(ch)
		for _, p := range providers {
			ch <- p
		}
	}()
	return ch
}

// FIXME: there's a bug here!
func (dht *IpfsDHT) FindProvidersAsync2(ctx context.Context, key u.Key, count int) <-chan *peer.Peer {
	peerOut := make(chan *peer.Peer, count)
	go func() {
		ps := newPeerSet()
		provs := dht.providers.GetProviders(key)
		for _, p := range provs {
			count--
			// NOTE: assuming that this list of peers is unique
			ps.Add(p)
			peerOut <- p
			if count <= 0 {
				return
			}
		}

		peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), AlphaValue)
		for _, pp := range peers {
			go func(p *peer.Peer) {
				pmes, err := dht.findProvidersSingle(p, key, 0, timeout)
				if err != nil {
					u.PErr("%v\n", err)
					return
				}
				dht.addPeerListAsync(key, pmes.GetPeers(), ps, count, peerOut)
			}(pp)
		}

	}()
	return peerOut
}

//TODO: this function could also be done asynchronously
func (dht *IpfsDHT) addPeerListAsync(k u.Key, peers []*Message_Peer, ps *peerSet, count int, out chan *peer.Peer) {
	for _, pbp := range peers {

		// construct new peer
		p, err := dht.ensureConnectedToPeer(pbp)
		if err != nil {
			continue
		}

		dht.providers.AddProvider(k, p)
		if ps.AddIfSmallerThan(p, count) {
			out <- p
		} else if ps.Size() >= count {
			return
		}
	}
}

// FindProviders searches for peers who can provide the value for given key.
func (dht *IpfsDHT) FindProviders(ctx context.Context, key u.Key) ([]*peer.Peer, error) {
	ll := startNewRPC("FindProviders")
	ll.EndAndPrint()

	// get closest peer
	u.DOut("Find providers for: '%s'\n", key)
	p := dht.routingTables[0].NearestPeer(kb.ConvertKey(key))
	if p == nil {
		return nil, nil
	}

	for level := 0; level < len(dht.routingTables); {

		// attempt retrieving providers
		pmes, err := dht.findProvidersSingle(ctx, p, key, level)
		if err != nil {
			return nil, err
		}

		// handle providers
		provs := pmes.GetProviderPeers()
		if provs != nil {
			u.DOut("Got providers back from findProviders call!\n")
			return dht.addProviders(key, provs), nil
		}

		u.DOut("Didnt get providers, just closer peers.\n")
		closer := pmes.GetCloserPeers()
		if len(closer) == 0 {
			level++
			continue
		}

		np, err := dht.peerFromInfo(closer[0])
		if err != nil {
			u.DOut("no peerFromInfo")
			level++
			continue
		}
		p = np
	}
	return nil, u.ErrNotFound
}

// Find specific Peer

// FindPeer searches for a peer with given ID.
func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (*peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.Find(id)
	if p != nil {
		return p, nil
	}

	// @whyrusleeping why is this here? doesn't the dht.Find above cover it?
	routeLevel := 0
	p = dht.routingTables[routeLevel].NearestPeer(kb.ConvertPeerID(id))
	if p == nil {
		return nil, nil
	}
	if p.ID.Equal(id) {
		return p, nil
	}

	for routeLevel < len(dht.routingTables) {
		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		plist := pmes.GetCloserPeers()
		if plist == nil || len(plist) == 0 {
			routeLevel++
			continue
		}
		found := plist[0]

		nxtPeer, err := dht.ensureConnectedToPeer(found)
		if err != nil {
			routeLevel++
			continue
		}

		if nxtPeer.ID.Equal(id) {
			return nxtPeer, nil
		}

		p = nxtPeer
	}
	return nil, u.ErrNotFound
}

func (dht *IpfsDHT) findPeerMultiple(ctx context.Context, id peer.ID) (*peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.Find(id)
	if p != nil {
		return p, nil
	}

	// get the peers we need to announce to
	routeLevel := 0
	peers := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
	if len(peers) == 0 {
		return nil, nil
	}

	// setup query function
	query := newQuery(u.Key(id), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		if err != nil {
			u.DErr("getPeer error: %v\n", err)
			return nil, err
		}

		plist := pmes.GetCloserPeers()
		if len(plist) == 0 {
			routeLevel++
		}

		nxtprs := make([]*peer.Peer, len(plist))
		for i, fp := range plist {
			nxtp, err := dht.peerFromInfo(fp)
			if err != nil {
				u.DErr("findPeer error: %v\n", err)
				continue
			}

			if nxtp.ID.Equal(id) {
				return &dhtQueryResult{peer: nxtp, success: true}, nil
			}

			nxtprs[i] = nxtp
		}

		return &dhtQueryResult{closerPeers: nxtprs}, nil
	})

	result, err := query.Run(ctx, peers)
	if err != nil {
		return nil, err
	}

	if result.peer == nil {
		return nil, u.ErrNotFound
	}
	return result.peer, nil
}

// Ping a peer, log the time it took
func (dht *IpfsDHT) Ping(ctx context.Context, p *peer.Peer) error {
	// Thoughts: maybe this should accept an ID and do a peer lookup?
	u.DOut("[%s] ping %s start\n", dht.self.ID.Pretty(), p.ID.Pretty())

	pmes := newMessage(Message_PING, "", 0)
	_, err := dht.sendRequest(ctx, p, pmes)
	u.DOut("[%s] ping %s end (err = %s)\n", dht.self.ID.Pretty(), p.ID.Pretty(), err)
	return err
}

func (dht *IpfsDHT) getDiagnostic(ctx context.Context) ([]*diagInfo, error) {

	u.DOut("Begin Diagnostic")
	peers := dht.routingTables[0].NearestPeers(kb.ConvertPeerID(dht.self.ID), 10)
	var out []*diagInfo

	query := newQuery(dht.self.Key(), func(ctx context.Context, p *peer.Peer) (*dhtQueryResult, error) {
		pmes := newMessage(Message_DIAGNOSTIC, "", 0)
		rpmes, err := dht.sendRequest(ctx, p, pmes)
		if err != nil {
			return nil, err
		}

		dec := json.NewDecoder(bytes.NewBuffer(rpmes.GetValue()))
		for {
			di := new(diagInfo)
			err := dec.Decode(di)
			if err != nil {
				break
			}

			out = append(out, di)
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err := query.Run(ctx, peers)
	return out, err
}
<|endoftext|>


<commit_before>package shinywaffle

import (
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/hatstand/shinywaffle/mocks"

	. "github.com/smartystreets/goconvey/convey"
)

func WithBusAndPins(t *testing.T, f func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101)) func() {
	return func() {
		mock := gomock.NewController(t)
		defer mock.Finish()
		bus := mocks.NewMockSPIBus(mock)
		gdo0 := mocks.NewMockDigitalPin(mock)
		gdo2 := mocks.NewMockDigitalPin(mock)
		cc1101 := &CC1101{
			bus:  bus,
			gdo0: gdo0,
			gdo2: gdo2,
		}
		f(bus, gdo0, gdo2, cc1101)
	}
}

func WithBus(t *testing.T, f func(bus *mocks.MockSPIBus, cc1101 *CC1101)) func() {
	return WithBusAndPins(t, func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101) {
		f(bus, cc1101)
	})
}

func TestSelfTest(t *testing.T) {
	Convey("Init", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{VERSION | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x14})
		bus.EXPECT().TransferAndReceiveData([]byte{PARTNUM | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x00})

		So(cc1101.SelfTest(), ShouldBeNil)
	}))
}

func TestStrobe(t *testing.T) {
	Convey("Strobe", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{0x42, 0x00}).Return(nil).SetArg(0, []byte{0x43, 0x00})

		ret, err := cc1101.Strobe(0x42)
		So(err, ShouldBeNil)
		So(ret, ShouldEqual, 0x43)
	}))
}

func TestReset(t *testing.T) {
	Convey("Reset", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SRES, 0x00}).Return(nil)

		So(cc1101.Reset(), ShouldBeNil)
	}))
}

func TestSetState(t *testing.T) {
	Convey("RX", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SRX, 0x00}).Return(nil)
		So(cc1101.SetRx(), ShouldBeNil)
	}))
	Convey("TX", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{STX, 0x00}).Return(nil)
		So(cc1101.SetTx(), ShouldBeNil)
	}))
	Convey("IDLE", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}).Return(nil)
		So(cc1101.SetIdle(), ShouldBeNil)
	}))
	Convey("Flush RX buffer", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		gomock.InOrder(
			bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}).Return(nil),
			bus.EXPECT().TransferAndReceiveData([]byte{SFRX, 0x00}).Return(nil),
		)
		cc1101.FlushRx()
	}))
}

func TestSendPacket(t *testing.T) {
	Convey("Send", t, WithBusAndPins(t, func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101) {
		packet := []byte{0x42, 0x43, 0x44}
		gomock.InOrder(
			// Write the packet length.
			bus.EXPECT().TransferAndReceiveData([]byte{TXFIFO | WRITE_SINGLE_BYTE, 3}),
			// Write the packet data.
			bus.EXPECT().TransferAndReceiveData([]byte{TXFIFO | WRITE_BURST, 0x42, 0x43, 0x44}),
			// Switch to send mode.
			bus.EXPECT().TransferAndReceiveData([]byte{STX, 0x00}),
			// Wait for sync word to transmit (rising edge on gdo2).
			gdo2.EXPECT().Read().Return(1, nil),
			// Wait for packet data to transmit (falling edge on gdo2).
			gdo2.EXPECT().Read().Return(0, nil),
			// Switch back to idle mode when finished.
			bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}),
			// Flush the TX buffer.
			bus.EXPECT().TransferAndReceiveData([]byte{SFTX, 0x00}),
			// Return to RX mode.
			bus.EXPECT().TransferAndReceiveData([]byte{SRX, 0x00}),
		)
		cc1101.Send(packet)
	}))
}
<commit_msg>Test receiving packets<commit_after>package shinywaffle

import (
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/hatstand/shinywaffle/mocks"

	. "github.com/smartystreets/goconvey/convey"
)

func WithBusAndPins(t *testing.T, f func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101)) func() {
	return func() {
		mock := gomock.NewController(t)
		defer mock.Finish()
		bus := mocks.NewMockSPIBus(mock)
		gdo0 := mocks.NewMockDigitalPin(mock)
		gdo2 := mocks.NewMockDigitalPin(mock)
		cc1101 := &CC1101{
			bus:  bus,
			gdo0: gdo0,
			gdo2: gdo2,
		}
		f(bus, gdo0, gdo2, cc1101)
	}
}

func WithBus(t *testing.T, f func(bus *mocks.MockSPIBus, cc1101 *CC1101)) func() {
	return WithBusAndPins(t, func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101) {
		f(bus, cc1101)
	})
}

func TestSelfTest(t *testing.T) {
	Convey("Init", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{VERSION | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x14})
		bus.EXPECT().TransferAndReceiveData([]byte{PARTNUM | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x00})

		So(cc1101.SelfTest(), ShouldBeNil)
	}))
}

func TestStrobe(t *testing.T) {
	Convey("Strobe", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{0x42, 0x00}).Return(nil).SetArg(0, []byte{0x43, 0x00})

		ret, err := cc1101.Strobe(0x42)
		So(err, ShouldBeNil)
		So(ret, ShouldEqual, 0x43)
	}))
}

func TestReset(t *testing.T) {
	Convey("Reset", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SRES, 0x00}).Return(nil)

		So(cc1101.Reset(), ShouldBeNil)
	}))
}

func TestSetState(t *testing.T) {
	Convey("RX", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SRX, 0x00}).Return(nil)
		So(cc1101.SetRx(), ShouldBeNil)
	}))
	Convey("TX", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{STX, 0x00}).Return(nil)
		So(cc1101.SetTx(), ShouldBeNil)
	}))
	Convey("IDLE", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}).Return(nil)
		So(cc1101.SetIdle(), ShouldBeNil)
	}))
	Convey("Flush RX buffer", t, WithBus(t, func(bus *mocks.MockSPIBus, cc1101 *CC1101) {
		gomock.InOrder(
			bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}).Return(nil),
			bus.EXPECT().TransferAndReceiveData([]byte{SFRX, 0x00}).Return(nil),
		)
		cc1101.FlushRx()
	}))
}

func TestSendPacket(t *testing.T) {
	Convey("Send", t, WithBusAndPins(t, func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101) {
		packet := []byte{0x42, 0x43, 0x44}
		gomock.InOrder(
			// Write the packet length.
			bus.EXPECT().TransferAndReceiveData([]byte{TXFIFO | WRITE_SINGLE_BYTE, 3}),
			// Write the packet data.
			bus.EXPECT().TransferAndReceiveData([]byte{TXFIFO | WRITE_BURST, 0x42, 0x43, 0x44}),
			// Switch to send mode.
			bus.EXPECT().TransferAndReceiveData([]byte{STX, 0x00}),
			// Wait for sync word to transmit (rising edge on gdo2).
			gdo2.EXPECT().Read().Return(1, nil),
			// Wait for packet data to transmit (falling edge on gdo2).
			gdo2.EXPECT().Read().Return(0, nil),
			// Switch back to idle mode when finished.
			bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}),
			// Flush the TX buffer.
			bus.EXPECT().TransferAndReceiveData([]byte{SFTX, 0x00}),
			// Return to RX mode.
			bus.EXPECT().TransferAndReceiveData([]byte{SRX, 0x00}),
		)
		cc1101.Send(packet)
	}))
}

func TestReceivePacket(t *testing.T) {
	Convey("Send", t, WithBusAndPins(t, func(bus *mocks.MockSPIBus, gdo0 *mocks.MockDigitalPin, gdo2 *mocks.MockDigitalPin, cc1101 *CC1101) {
		addr := byte(RXFIFO | READ_BURST)
		packet := []byte{0x42, 0x43, 0x44}
		response := []byte{0x00}
		response = append(response, packet...)
		gomock.InOrder(
			// Read RXBYTES for fifo length and overflow.
			bus.EXPECT().TransferAndReceiveData([]byte{RXBYTES | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x03}),
			// Read first RXFIFO byte for packet length.
			bus.EXPECT().TransferAndReceiveData([]byte{RXFIFO | READ_SINGLE_BYTE, 0x00}).Return(nil).SetArg(0, []byte{0x00, 0x03}),
			// Read packet data out of RXFIFO.
			bus.EXPECT().TransferAndReceiveData([]byte{
				addr,
				addr + 1*8 | READ_BURST,
				addr + 2*8 | READ_BURST,
				addr + 3*8 | READ_BURST,
			}).SetArg(0, response),
			// Read packet status bytes.
			bus.EXPECT().TransferAndReceiveData([]byte{
				addr,
				addr + 1*8 | READ_BURST,
				addr + 2*8 | READ_BURST,
			}),
			// Flush RX buffer.
			bus.EXPECT().TransferAndReceiveData([]byte{SIDLE, 0x00}),
			bus.EXPECT().TransferAndReceiveData([]byte{SFRX, 0x00}),
		)
		recv, err := cc1101.Receive()
		So(err, ShouldBeNil)
		So(recv, ShouldResemble, packet)
	}))
}
<|endoftext|>


<commit_before>package sandman

import (
	"github.com/sbinet/go-python"
	"log"
)

func init() {
	err := python.Initialize()
	if err != nil {
		panic(err.Error())
	}
}

func GetFunction(module_name string, function_name string) *python.PyObject {

	Module := python.PyImport_ImportModule(module_name)
	if Module == nil {
		log.Fatal("Failed to load the "+ module_name+" module")
	}

	var MethodDesired *python.PyObject
	if Module.HasAttrString(function_name) == 1 {
		MethodDesired = Module.GetAttrString(function_name)
	}
	if !MethodDesired.Check_Callable() {
		log.Fatal(module_name+" is not callable")
	}
	return MethodDesired

}
func Highlight(code string, lexer string) string {
	GetFormatterByName := GetFunction("pygments.formatters", "HtmlFormatter")
	FormatterArgs := python.PyTuple_New(0)

	Formatter:= GetFormatterByName.CallObject(FormatterArgs)

	if Formatter == nil {
		log.Fatal("Couldn't get formatter")
	}
	if Formatter.HasAttrString("encoding") == 0 {
		log.Fatal("Wrong formatter")
	}
	Formatter.SetAttrString("encoding", python.PyString_FromString("utf-8"))

	GetLexerByName := GetFunction("pygments.lexers", "get_lexer_by_name")
	LexerArgs := python.PyTuple_New(1)
	python.PyTuple_SetItem(LexerArgs, 0, python.PyString_FromString(lexer))
	Lexer:= GetLexerByName.CallObject(LexerArgs)
	if Lexer == nil{
		log.Fatal("Couldn't get lexer")
	}

	Highlighter := GetFunction("pygments", "highlight")
	if Highlighter  == nil{
		log.Fatal("aaasa")
	}
	HighlighterArgs := python.PyTuple_New(3)
	python.PyTuple_SetItem(HighlighterArgs, 0, python.PyString_FromString(code))
	python.PyTuple_SetItem(HighlighterArgs, 1, Lexer)
	python.PyTuple_SetItem(HighlighterArgs, 2, Formatter)

	highlighted := Highlighter.CallObject(HighlighterArgs)
	if highlighted == nil {
		log.Fatal("Couldn't highlight")
	}
	return python.PyString_AsString(highlighted)

}
<commit_msg>line nos<commit_after>package sandman

import (
	"github.com/sbinet/go-python"
	"log"
)

func init() {
	err := python.Initialize()
	if err != nil {
		panic(err.Error())
	}
}

func GetFunction(module_name string, function_name string) *python.PyObject {

	Module := python.PyImport_ImportModule(module_name)
	if Module == nil {
		log.Fatal("Failed to load the "+ module_name+" module")
	}

	var MethodDesired *python.PyObject
	if Module.HasAttrString(function_name) == 1 {
		MethodDesired = Module.GetAttrString(function_name)
	}
	if !MethodDesired.Check_Callable() {
		log.Fatal(module_name+" is not callable")
	}
	return MethodDesired

}
func Highlight(code string, lexer string, linenos bool) string {
	lnos := 0
	if linenos {
		lnos = 1
	}

	GetFormatterByName := GetFunction("pygments.formatters", "HtmlFormatter")
	FormatterArgs := python.PyTuple_New(0)

	Formatter:= GetFormatterByName.CallObject(FormatterArgs)

	if Formatter == nil {
		log.Fatal("Couldn't get formatter")
	}
	if Formatter.HasAttrString("encoding") == 0 {
		log.Fatal("Wrong formatter")
	}
	if Formatter.HasAttrString("linenos") == 0 {
		log.Fatal("Wrong formatter")
	}

	Formatter.SetAttrString("encoding", python.PyString_FromString("utf-8"))
	Formatter.SetAttrString("linenos", python.PyBool_FromLong(lnos))

	GetLexerByName := GetFunction("pygments.lexers", "get_lexer_by_name")
	LexerArgs := python.PyTuple_New(1)
	python.PyTuple_SetItem(LexerArgs, 0, python.PyString_FromString(lexer))
	Lexer:= GetLexerByName.CallObject(LexerArgs)
	if Lexer == nil{
		log.Fatal("Couldn't get lexer")
	}

	Highlighter := GetFunction("pygments", "highlight")
	if Highlighter  == nil{
		log.Fatal("aaasa")
	}
	HighlighterArgs := python.PyTuple_New(3)
	python.PyTuple_SetItem(HighlighterArgs, 0, python.PyString_FromString(code))
	python.PyTuple_SetItem(HighlighterArgs, 1, Lexer)
	python.PyTuple_SetItem(HighlighterArgs, 2, Formatter)

	highlighted := Highlighter.CallObject(HighlighterArgs)
	if highlighted == nil {
		log.Fatal("Couldn't highlight")
	}
	return python.PyString_AsString(highlighted)

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type (
	Protocol struct {
		XMLName    xml.Name    `xml:"protocol"`
		Name       string      `xml:"name,attr"`
		Copyright  string      `xml:"copyright"`
		Interfaces []Interface `xml:"interface"`
	}

	Description struct {
		XMLName     xml.Name `xml:"description"`
		Summary     string   `xml:"summary,attr"`
		Description string   `xml:"description"`
	}

	Interface struct {
		XMLName     xml.Name    `xml:"interface"`
		Name        string      `xml:"name,attr"`
		Version     int         `xml:"version,attr"`
		Since       int         `xml:"since,attr"` // maybe in future versions
		Description Description `xml:"description"`
		Requests    []Request   `xml:"request"`
		Events      []Event     `xml:"event"`
		Enums       []Enum      `xml:"enum"`
	}

	Request struct {
		XMLName     xml.Name    `xml:"request"`
		Name        string      `xml:"name,attr"`
		Type        string      `xml:"type,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Arg struct {
		XMLName   xml.Name `xml:"arg"`
		Name      string   `xml:"name,attr"`
		Type      string   `xml:"type,attr"`
		Interface string   `xml:"interface,attr"`
		Enum      string   `xml:"enum,attr"`
		AllowNull bool     `xml:"allow-null,attr"`
		Summary   string   `xml:"summary,attr"`
	}

	Event struct {
		XMLName     xml.Name    `xml:"event"`
		Name        string      `xml:"name,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Enum struct {
		XMLName     xml.Name    `xml:"enum"`
		Name        string      `xml:"name,attr"`
		BitField    bool        `xml:"bitfield,attr"`
		Description Description `xml:"description"`
		Entries     []Entry     `xml:"entry"`
	}

	Entry struct {
		XMLName xml.Name `xml:"entry"`
		Name    string   `xml:"name,attr"`
		Value   string   `xml:"value,attr"`
		Summary string   `xml:"summary,attr"`
	}
)

var (
	wlTypes map[string]string = map[string]string{
		"int":    "int32",
		"uint":   "uint32",
		"string": "string",
		"fd":     "uintptr",
		"fixed":  "float32",
		"array":  "[]int32",
	}

	wlNames        map[string]string
	constBuffer    bytes.Buffer
	ifaceBuffer    bytes.Buffer
	reqCodesBuffer bytes.Buffer

	overwrite = flag.Bool("o", false, "Overwrite existing client.go file")
	develXml  = flag.Bool("dev", false, "Get development version of wayland.xml from repository")
)

func init() {
	flag.Parse()
	log.SetFlags(0)
}

func main() {
	var xmlFile *os.File

	if *develXml {
		file, err := getDevelXml()
		if err != nil {
			file.Close()
			log.Fatalf("Error while reading xml file: %s", err)
		}
		xmlFile = file
		xmlFile.Seek(0, 0)
	} else {
		xmlFilePath, err := filepath.Abs("wayland.xml")
		if err != nil {
			log.Fatalf("Cannot find wayland.xml: %s", err)
		}

		file, err := os.Open(xmlFilePath)
		if err != nil {
			log.Fatalf("Cannot open wayland.xml: %s", err)
		}
		xmlFile = file
	}

	defer xmlFile.Close()

	var protocol Protocol
	if err := xml.NewDecoder(xmlFile).Decode(&protocol); err != nil {
		log.Fatalf("Cannot decode wayland.xml: %s", err)
	}

	wlNames = make(map[string]string)

	fmt.Fprint(&constBuffer, "//generated by wl-scanner https://github.com/sternix/wl-scanner\n")
	fmt.Fprint(&constBuffer, "package wl")

	for _, iface := range protocol.Interfaces {
		//required for arg type's determine
		caseAndRegister(iface.Name)
	}

	fmt.Fprint(&reqCodesBuffer, "\n//Interface Request Codes\n") // request codes
	fmt.Fprint(&reqCodesBuffer, "\nconst (\n")                   // request codes

	for _, iface := range protocol.Interfaces {
		eventBuffer, eventNames := interfaceEvents(iface)
		eventBuffer.WriteTo(&ifaceBuffer)

		interfaceTypes(iface, eventNames)
		interfaceConstructor(iface, eventNames)
		interfaceRequests(iface)
		interfaceEnums(iface)
	}

	fmt.Fprint(&reqCodesBuffer, ")") // request codes end

	// if file exists
	if _, err := os.Stat("client.go"); err == nil {
		if !*overwrite {
			log.Print("client.go exists if you want to overwrite try -o flag")
			return
		}
	}

	file, err := os.Create("client.go")
	if err != nil {
		log.Fatalf("Cannot create file: %s", err)
	}

	constBuffer.WriteTo(file)
	reqCodesBuffer.WriteTo(file)
	ifaceBuffer.WriteTo(file)

	file.Close()

	// go fmt file
	fmtFile()
}

// register names to map
func caseAndRegister(wlName string) string {
	var orj string = wlName
	wlName = CamelCase(wlName)
	wlNames[orj] = wlName
	return wlName
}

func enumArgName(ifaceName, enumName string) string {
	if strings.Index(enumName, ".") == -1 {
		return ifaceName + CamelCase(enumName)
	}

	parts := strings.Split(enumName, ".")
	if len(parts) != 2 {
		log.Fatal("enum args must be \"interface.enum\" format")
	}
	return CamelCase(parts[0]) + CamelCase(parts[1])
}

func CamelCase(wlName string) string {
	if strings.HasPrefix(wlName, "wl_") {
		wlName = strings.TrimPrefix(wlName, "wl_")
	}

	// replace all "_" chars to " " chars
	wlName = strings.Replace(wlName, "_", " ", -1)

	// Capitalize first chars
	wlName = strings.Title(wlName)

	// remove all spaces
	wlName = strings.Replace(wlName, " ", "", -1)

	return wlName
}

func interfaceConstructor(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]

	// interface constructor
	fmt.Fprintf(&ifaceBuffer, "\nfunc New%s(conn *Connection) *%s {\n", ifaceName, ifaceName)
	fmt.Fprintf(&ifaceBuffer, "ret := new(%s)\n", ifaceName)
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer, "ret.%sChan = make(chan %s%sEvent)\n", evName, ifaceName, evName)
	}

	fmt.Fprint(&ifaceBuffer, "conn.Register(ret)\n")
	fmt.Fprint(&ifaceBuffer, "return ret\n")
	fmt.Fprint(&ifaceBuffer, "}\n")
}

func interfaceTypes(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]
	// interface type definition
	fmt.Fprintf(&ifaceBuffer, "\ntype %s struct {\n", ifaceName)
	fmt.Fprint(&ifaceBuffer, "BaseProxy\n")
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer, "%sChan chan %s%sEvent\n", evName, ifaceName, evName)
	}
	fmt.Fprint(&ifaceBuffer, "}\n")
}

func interfaceRequests(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// interface method definitions (requests)
	// order used for request identification
	for order, req := range iface.Requests {
		reqName := CamelCase(req.Name)
		reqCodeName := strings.ToTitle(fmt.Sprintf("_%s_%s", ifaceName, reqName)) // first _ for not export constant
		fmt.Fprintf(&reqCodesBuffer, "%s = %d\n", reqCodeName, order)

		fmt.Fprintf(&ifaceBuffer, "\nfunc (p *%s) %s(", ifaceName, reqName)
		// get args buffer
		requestArgs(ifaceName, req).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer, ")") // close the args

		// get returns buffer
		requestRets(req).WriteTo(&ifaceBuffer)
		fmt.Fprint(&ifaceBuffer, "{\n")

		// get method body
		requestBody(req, reqCodeName).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer, "\n}\n")
	}
}

func interfaceEnums(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// Enums - Constants
	for _, enum := range iface.Enums {
		enumName := caseAndRegister(enum.Name)
		constTypeName := ifaceName + enumName
		fmt.Fprintf(&constBuffer, "\ntype %s uint32\n", constTypeName) // enums are uint
		fmt.Fprint(&constBuffer, "const (\n")
		for _, entry := range enum.Entries {
			entryName := caseAndRegister(entry.Name)
			constName := ifaceName + enumName + entryName
			fmt.Fprintf(&constBuffer, "%s %s = %s\n", constName, constTypeName, entry.Value)
		}
		fmt.Fprint(&constBuffer, ")\n")
	}
}

func interfaceEvents(iface Interface) (bytes.Buffer, []string) {
	var (
		eventBuffer bytes.Buffer
		eventNames  []string
		ifaceName   = wlNames[iface.Name]
	)

	// Event struct types
	for _, event := range iface.Events {
		eventName := caseAndRegister(event.Name)
		fmt.Fprintf(&eventBuffer, "\ntype %s%sEvent struct {\n", ifaceName, eventName)
		for _, arg := range event.Args {
			if t, ok := wlTypes[arg.Type]; ok { // if basic type
				if arg.Type == "uint" && arg.Enum != "" { // enum type
					enumTypeName := ifaceName + CamelCase(arg.Enum)
					fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), enumTypeName)
				} else {
					fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), t)
				}
			} else { // interface type
				if (arg.Type == "object" || arg.Type == "new_id") && arg.Interface != "" {
					t = "*" + wlNames[arg.Interface]
				} else {
					t = "Proxy"
				}
				fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), t)
			}
		}

		eventNames = append(eventNames, eventName)
		fmt.Fprint(&eventBuffer, "}\n")
	}

	return eventBuffer, eventNames
}

func requestArgs(ifaceName string, req Request) *bytes.Buffer {
	var (
		args       []string
		argsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		// special type, for example registry.bind
		if arg.Type == "new_id" {
			if arg.Interface == "" {
				args = append(args, "iface string")
				args = append(args, "version uint32")
				args = append(args, fmt.Sprintf("%s Proxy", arg.Name))
			} else {
				continue
			}
		} else if arg.Type == "object" && arg.Interface != "" {
			argTypeName := wlNames[arg.Interface]
			args = append(args, fmt.Sprintf("%s *%s", arg.Name, argTypeName))
		} else if arg.Type == "uint" && arg.Enum != "" {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, enumArgName(ifaceName, arg.Enum)))
		} else {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, wlTypes[arg.Type]))
		}
	}

	fmt.Fprint(&argsBuffer, strings.Join(args, ","))

	return &argsBuffer
}

func requestRets(req Request) *bytes.Buffer {
	var (
		rets       []string
		retsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" && arg.Interface != "" {
			retTypeName := wlNames[arg.Interface]
			rets = append(rets, fmt.Sprintf("*%s", retTypeName))
		}
	}

	// all request have an error return
	rets = append(rets, "error")

	retstr := strings.Join(rets, ",")

	if len(rets) > 1 {
		fmt.Fprintf(&retsBuffer, "( %s )", retstr)
	} else {
		fmt.Fprint(&retsBuffer, retstr)
	}

	return &retsBuffer
}

func requestBody(req Request, reqCodeName string) *bytes.Buffer {
	var (
		params     []string
		bodyBuffer bytes.Buffer
		hasRet     string
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" {
			if arg.Interface != "" {
				retTypeName := wlNames[arg.Interface]
				fmt.Fprintf(&bodyBuffer, "ret := New%s(p.Connection())\n", retTypeName)
				params = append(params, "Proxy(ret)")
				hasRet = "ret,"
			} else {
				params = append(params, "iface")
				params = append(params, "version")
				params = append(params, arg.Name)
			}
		} else {
			params = append(params, arg.Name)
		}
	}

	fmt.Fprintf(&bodyBuffer, "return %s p.Connection().SendRequest(p,%s,%s)", hasRet, reqCodeName, strings.Join(params, ","))

	return &bodyBuffer
}

func getDevelXml() (*os.File, error) {
	url := "https://cgit.freedesktop.org/wayland/wayland/plain/protocol/wayland.xml"
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("HTTP Get error: %s", err)
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Cannot get wayland.xml StatusCode != StatusOK")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body: %s", err)
	}

	file, err := ioutil.TempFile("", "devel_wayland_xml")
	if err != nil {
		return nil, fmt.Errorf("Cannot create temp file: %s", err)
	}

	file.Write(body)
	return file, nil
}

func fmtFile() {
	goex, err := exec.LookPath("go")
	if err != nil {
		log.Printf("go executable cannot found run \"go fmt client.go\" yourself: %s", err)
		return
	}

	cmd := exec.Command(goex, "fmt", "client.go")
	errr := cmd.Run()
	if errr != nil {
		log.Fatalf("Cannot run cmd: %s", errr)
	}
}
<commit_msg>make new functions private<commit_after>package main

import (
	"bytes"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type (
	Protocol struct {
		XMLName    xml.Name    `xml:"protocol"`
		Name       string      `xml:"name,attr"`
		Copyright  string      `xml:"copyright"`
		Interfaces []Interface `xml:"interface"`
	}

	Description struct {
		XMLName     xml.Name `xml:"description"`
		Summary     string   `xml:"summary,attr"`
		Description string   `xml:"description"`
	}

	Interface struct {
		XMLName     xml.Name    `xml:"interface"`
		Name        string      `xml:"name,attr"`
		Version     int         `xml:"version,attr"`
		Since       int         `xml:"since,attr"` // maybe in future versions
		Description Description `xml:"description"`
		Requests    []Request   `xml:"request"`
		Events      []Event     `xml:"event"`
		Enums       []Enum      `xml:"enum"`
	}

	Request struct {
		XMLName     xml.Name    `xml:"request"`
		Name        string      `xml:"name,attr"`
		Type        string      `xml:"type,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Arg struct {
		XMLName   xml.Name `xml:"arg"`
		Name      string   `xml:"name,attr"`
		Type      string   `xml:"type,attr"`
		Interface string   `xml:"interface,attr"`
		Enum      string   `xml:"enum,attr"`
		AllowNull bool     `xml:"allow-null,attr"`
		Summary   string   `xml:"summary,attr"`
	}

	Event struct {
		XMLName     xml.Name    `xml:"event"`
		Name        string      `xml:"name,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Enum struct {
		XMLName     xml.Name    `xml:"enum"`
		Name        string      `xml:"name,attr"`
		BitField    bool        `xml:"bitfield,attr"`
		Description Description `xml:"description"`
		Entries     []Entry     `xml:"entry"`
	}

	Entry struct {
		XMLName xml.Name `xml:"entry"`
		Name    string   `xml:"name,attr"`
		Value   string   `xml:"value,attr"`
		Summary string   `xml:"summary,attr"`
	}
)

var (
	wlTypes map[string]string = map[string]string{
		"int":    "int32",
		"uint":   "uint32",
		"string": "string",
		"fd":     "uintptr",
		"fixed":  "float32",
		"array":  "[]int32",
	}

	wlNames        map[string]string
	constBuffer    bytes.Buffer
	ifaceBuffer    bytes.Buffer
	reqCodesBuffer bytes.Buffer

	overwrite = flag.Bool("o", false, "Overwrite existing client.go file")
	develXml  = flag.Bool("dev", false, "Get development version of wayland.xml from repository")
)

func init() {
	flag.Parse()
	log.SetFlags(0)
}

func main() {
	var xmlFile *os.File

	if *develXml {
		file, err := getDevelXml()
		if err != nil {
			file.Close()
			log.Fatalf("Error while reading xml file: %s", err)
		}
		xmlFile = file
		xmlFile.Seek(0, 0)
	} else {
		xmlFilePath, err := filepath.Abs("wayland.xml")
		if err != nil {
			log.Fatalf("Cannot find wayland.xml: %s", err)
		}

		file, err := os.Open(xmlFilePath)
		if err != nil {
			log.Fatalf("Cannot open wayland.xml: %s", err)
		}
		xmlFile = file
	}

	defer xmlFile.Close()

	var protocol Protocol
	if err := xml.NewDecoder(xmlFile).Decode(&protocol); err != nil {
		log.Fatalf("Cannot decode wayland.xml: %s", err)
	}

	wlNames = make(map[string]string)

	fmt.Fprint(&constBuffer, "//generated by wl-scanner https://github.com/sternix/wl-scanner\n")
	fmt.Fprint(&constBuffer, "package wl")

	for _, iface := range protocol.Interfaces {
		//required for arg type's determine
		caseAndRegister(iface.Name)
	}

	fmt.Fprint(&reqCodesBuffer, "\n//Interface Request Codes\n") // request codes
	fmt.Fprint(&reqCodesBuffer, "\nconst (\n")                   // request codes

	for _, iface := range protocol.Interfaces {
		eventBuffer, eventNames := interfaceEvents(iface)
		eventBuffer.WriteTo(&ifaceBuffer)

		interfaceTypes(iface, eventNames)
		interfaceConstructor(iface, eventNames)
		interfaceRequests(iface)
		interfaceEnums(iface)
	}

	fmt.Fprint(&reqCodesBuffer, ")") // request codes end

	// if file exists
	if _, err := os.Stat("client.go"); err == nil {
		if !*overwrite {
			log.Print("client.go exists if you want to overwrite try -o flag")
			return
		}
	}

	file, err := os.Create("client.go")
	if err != nil {
		log.Fatalf("Cannot create file: %s", err)
	}

	constBuffer.WriteTo(file)
	reqCodesBuffer.WriteTo(file)
	ifaceBuffer.WriteTo(file)

	file.Close()

	// go fmt file
	fmtFile()
}

// register names to map
func caseAndRegister(wlName string) string {
	var orj string = wlName
	wlName = CamelCase(wlName)
	wlNames[orj] = wlName
	return wlName
}

func enumArgName(ifaceName, enumName string) string {
	if strings.Index(enumName, ".") == -1 {
		return ifaceName + CamelCase(enumName)
	}

	parts := strings.Split(enumName, ".")
	if len(parts) != 2 {
		log.Fatal("enum args must be \"interface.enum\" format")
	}
	return CamelCase(parts[0]) + CamelCase(parts[1])
}

func CamelCase(wlName string) string {
	if strings.HasPrefix(wlName, "wl_") {
		wlName = strings.TrimPrefix(wlName, "wl_")
	}

	// replace all "_" chars to " " chars
	wlName = strings.Replace(wlName, "_", " ", -1)

	// Capitalize first chars
	wlName = strings.Title(wlName)

	// remove all spaces
	wlName = strings.Replace(wlName, " ", "", -1)

	return wlName
}

func interfaceConstructor(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]

	// interface constructor
	fmt.Fprintf(&ifaceBuffer, "\nfunc new%s(conn *Connection) *%s {\n", ifaceName, ifaceName)
	fmt.Fprintf(&ifaceBuffer, "ret := new(%s)\n", ifaceName)
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer, "ret.%sChan = make(chan %s%sEvent)\n", evName, ifaceName, evName)
	}

	fmt.Fprint(&ifaceBuffer, "conn.Register(ret)\n")
	fmt.Fprint(&ifaceBuffer, "return ret\n")
	fmt.Fprint(&ifaceBuffer, "}\n")
}

func interfaceTypes(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]
	// interface type definition
	fmt.Fprintf(&ifaceBuffer, "\ntype %s struct {\n", ifaceName)
	fmt.Fprint(&ifaceBuffer, "BaseProxy\n")
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer, "%sChan chan %s%sEvent\n", evName, ifaceName, evName)
	}
	fmt.Fprint(&ifaceBuffer, "}\n")
}

func interfaceRequests(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// interface method definitions (requests)
	// order used for request identification
	for order, req := range iface.Requests {
		reqName := CamelCase(req.Name)
		reqCodeName := strings.ToTitle(fmt.Sprintf("_%s_%s", ifaceName, reqName)) // first _ for not export constant
		fmt.Fprintf(&reqCodesBuffer, "%s = %d\n", reqCodeName, order)

		fmt.Fprintf(&ifaceBuffer, "\nfunc (p *%s) %s(", ifaceName, reqName)
		// get args buffer
		requestArgs(ifaceName, req).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer, ")") // close the args

		// get returns buffer
		requestRets(req).WriteTo(&ifaceBuffer)
		fmt.Fprint(&ifaceBuffer, "{\n")

		// get method body
		requestBody(req, reqCodeName).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer, "\n}\n")
	}
}

func interfaceEnums(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// Enums - Constants
	for _, enum := range iface.Enums {
		enumName := caseAndRegister(enum.Name)
		constTypeName := ifaceName + enumName
		fmt.Fprintf(&constBuffer, "\ntype %s uint32\n", constTypeName) // enums are uint
		fmt.Fprint(&constBuffer, "const (\n")
		for _, entry := range enum.Entries {
			entryName := caseAndRegister(entry.Name)
			constName := ifaceName + enumName + entryName
			fmt.Fprintf(&constBuffer, "%s %s = %s\n", constName, constTypeName, entry.Value)
		}
		fmt.Fprint(&constBuffer, ")\n")
	}
}

func interfaceEvents(iface Interface) (bytes.Buffer, []string) {
	var (
		eventBuffer bytes.Buffer
		eventNames  []string
		ifaceName   = wlNames[iface.Name]
	)

	// Event struct types
	for _, event := range iface.Events {
		eventName := caseAndRegister(event.Name)
		fmt.Fprintf(&eventBuffer, "\ntype %s%sEvent struct {\n", ifaceName, eventName)
		for _, arg := range event.Args {
			if t, ok := wlTypes[arg.Type]; ok { // if basic type
				if arg.Type == "uint" && arg.Enum != "" { // enum type
					enumTypeName := ifaceName + CamelCase(arg.Enum)
					fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), enumTypeName)
				} else {
					fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), t)
				}
			} else { // interface type
				if (arg.Type == "object" || arg.Type == "new_id") && arg.Interface != "" {
					t = "*" + wlNames[arg.Interface]
				} else {
					t = "Proxy"
				}
				fmt.Fprintf(&eventBuffer, "%s %s\n", CamelCase(arg.Name), t)
			}
		}

		eventNames = append(eventNames, eventName)
		fmt.Fprint(&eventBuffer, "}\n")
	}

	return eventBuffer, eventNames
}

func requestArgs(ifaceName string, req Request) *bytes.Buffer {
	var (
		args       []string
		argsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		// special type, for example registry.bind
		if arg.Type == "new_id" {
			if arg.Interface == "" {
				args = append(args, "iface string")
				args = append(args, "version uint32")
				args = append(args, fmt.Sprintf("%s Proxy", arg.Name))
			} else {
				continue
			}
		} else if arg.Type == "object" && arg.Interface != "" {
			argTypeName := wlNames[arg.Interface]
			args = append(args, fmt.Sprintf("%s *%s", arg.Name, argTypeName))
		} else if arg.Type == "uint" && arg.Enum != "" {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, enumArgName(ifaceName, arg.Enum)))
		} else {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, wlTypes[arg.Type]))
		}
	}

	fmt.Fprint(&argsBuffer, strings.Join(args, ","))

	return &argsBuffer
}

func requestRets(req Request) *bytes.Buffer {
	var (
		rets       []string
		retsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" && arg.Interface != "" {
			retTypeName := wlNames[arg.Interface]
			rets = append(rets, fmt.Sprintf("*%s", retTypeName))
		}
	}

	// all request have an error return
	rets = append(rets, "error")

	retstr := strings.Join(rets, ",")

	if len(rets) > 1 {
		fmt.Fprintf(&retsBuffer, "( %s )", retstr)
	} else {
		fmt.Fprint(&retsBuffer, retstr)
	}

	return &retsBuffer
}

func requestBody(req Request, reqCodeName string) *bytes.Buffer {
	var (
		params     []string
		bodyBuffer bytes.Buffer
		hasRet     string
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" {
			if arg.Interface != "" {
				retTypeName := wlNames[arg.Interface]
				fmt.Fprintf(&bodyBuffer, "ret := new%s(p.Connection())\n", retTypeName)
				params = append(params, "Proxy(ret)")
				hasRet = "ret,"
			} else {
				params = append(params, "iface")
				params = append(params, "version")
				params = append(params, arg.Name)
			}
		} else {
			params = append(params, arg.Name)
		}
	}

	fmt.Fprintf(&bodyBuffer, "return %s p.Connection().SendRequest(p,%s,%s)", hasRet, reqCodeName, strings.Join(params, ","))

	return &bodyBuffer
}

func getDevelXml() (*os.File, error) {
	url := "https://cgit.freedesktop.org/wayland/wayland/plain/protocol/wayland.xml"
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("HTTP Get error: %s", err)
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Cannot get wayland.xml StatusCode != StatusOK")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body: %s", err)
	}

	file, err := ioutil.TempFile("", "devel_wayland_xml")
	if err != nil {
		return nil, fmt.Errorf("Cannot create temp file: %s", err)
	}

	file.Write(body)
	return file, nil
}

func fmtFile() {
	goex, err := exec.LookPath("go")
	if err != nil {
		log.Printf("go executable cannot found run \"go fmt client.go\" yourself: %s", err)
		return
	}

	cmd := exec.Command(goex, "fmt", "client.go")
	errr := cmd.Run()
	if errr != nil {
		log.Fatalf("Cannot run cmd: %s", errr)
	}
}
<|endoftext|>


<commit_before>package js

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/orktes/orlang/analyser"
	"github.com/orktes/orlang/ast"
	"github.com/orktes/orlang/types"
)

type JSCodeGen struct {
	analyserInfo *analyser.Info
	buffer       bytes.Buffer
	currentFile  *ast.File
	identNumbers map[*ast.Identifier]int
}

func New(info *analyser.Info) *JSCodeGen {
	return &JSCodeGen{analyserInfo: info, identNumbers: map[*ast.Identifier]int{}}
}

func (jscg *JSCodeGen) getTempVar() string {
	// TODO check if temp var is defined in scope
	return "_temp"
}

func (jscg *JSCodeGen) getIdentifier(ident *ast.Identifier) string {
	nodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[ident]
	scopeItemDetals := nodeInfo.Scope.GetDetails(ident.Text, true)

	identNumber := 0
	if number, ok := jscg.identNumbers[scopeItemDetals.DefineIdentifier]; ok {
		identNumber = number
	} else {
		identNumber = len(jscg.identNumbers)
		jscg.identNumbers[scopeItemDetals.DefineIdentifier] = identNumber
	}

	return fmt.Sprintf("$%d", identNumber)
}

func (jscg *JSCodeGen) Visit(node ast.Node) ast.Visitor {
	nodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[node]
	switch n := node.(type) {
	case *ast.Macro, *ast.CallArgument:
	case *ast.TupleDeclaration:

		var varName string

		if n.DefaultValue != nil {
			if ident, ok := n.DefaultValue.(*ast.Identifier); ok {
				varName = jscg.getIdentifier(ident)
			}
		}

		if varName == "" {
			varName = jscg.getTempVar()
			jscg.buffer.WriteString(fmt.Sprintf(
				`var %s`,
				varName,
			))

			if n.DefaultValue != nil {
				jscg.buffer.WriteString("=")
			}

			ast.Walk(jscg, n.DefaultValue)

			jscg.buffer.WriteString(";")
		}

		var ptrnPrint func(pattern *ast.TuplePattern, prefix string)
		ptrnPrint = func(pattern *ast.TuplePattern, prefix string) {
			for i, ptrrn := range pattern.Patterns {
				switch pt := ptrrn.(type) {
				case *ast.TuplePattern:
					ptrnPrint(pt, fmt.Sprintf("%s[%d]", prefix, i))
				case *ast.Identifier:
					jscg.buffer.WriteString(
						fmt.Sprintf(
							"var %s = %s[%d]",
							jscg.getIdentifier(pt),
							prefix,
							i,
						))
					if i != len(pattern.Patterns)-1 {
						jscg.buffer.WriteString(";")
					}
				}

			}
		}

		ptrnPrint(n.Pattern, varName)

		return nil
	case *ast.VariableDeclaration:
		jscg.buffer.WriteString(fmt.Sprintf(
			`var %s`,
			jscg.getIdentifier(n.Name),
		))
		if n.DefaultValue != nil {
			jscg.buffer.WriteString("=")
		}

		ast.Walk(jscg, n.DefaultValue)
		return nil
	case *ast.IfStatement:
		jscg.buffer.WriteString(" if (")
		ast.Walk(jscg, n.Condition)
		jscg.buffer.WriteString(")")

		ast.Walk(jscg, n.Block)

		if n.Else != nil {
			jscg.buffer.WriteString(" else ")
			ast.Walk(jscg, n.Else)
		}

		return nil
	case *ast.TupleExpression:
		jscg.buffer.WriteString(`[`)

		for i, expr := range n.Expressions {
			ast.Walk(jscg, expr)
			if i < len(n.Expressions)-1 {
				jscg.buffer.WriteString(`,`)
			}
		}

		jscg.buffer.WriteString(`]`)
		return nil
	case *ast.UnaryExpression:
		if n.Postfix {
			ast.Walk(jscg, n.Expression)

		}

		jscg.buffer.WriteString(n.Operator.Text)

		if n.Postfix {
			return nil
		}
	case *ast.ComparisonExpression:
		ast.Walk(jscg, n.Left)
		jscg.buffer.WriteString(n.Operator.Text)
		ast.Walk(jscg, n.Right)
		return nil
	case *ast.BinaryExpression:
		ast.Walk(jscg, n.Left)
		jscg.buffer.WriteString(n.Operator.Text)
		ast.Walk(jscg, n.Right)
		return nil
	case *ast.Identifier:
		if n == nil {
			break
		}
		if sigType, ok := nodeInfo.Type.(*types.SignatureType); ok {
			if sigType.Extern {
				jscg.buffer.WriteString(n.Text)
				break
			}
		}

		jscg.buffer.WriteString(jscg.getIdentifier(n))
	case *ast.ValueExpression:
		jscg.buffer.WriteString(fmt.Sprintf(
			`%s`,
			n.Text,
		))
	case *ast.ReturnStatement:
		jscg.buffer.WriteString(`return `)
	case *ast.FunctionCall:
		if nodeInfo.TypeCast {
			if nodeInfo.Type == types.Int32Type || nodeInfo.Type == types.Int64Type {
				jscg.buffer.WriteString(`Math.floor`)
			} else {
				ast.Walk(jscg, n.Arguments[0])
				return nil
			}
		} else {
			ast.Walk(jscg, n.Callee)
		}
		jscg.buffer.WriteString(`(`)

		// TODO set named args into the right order
		var argNames []string

		calleeNodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[n.Callee]
		if calleeNodeInfo != nil && calleeNodeInfo.Type != nil {
			argNames = calleeNodeInfo.Type.(*types.SignatureType).ArgumentNames
		}

		namedArgs := len(n.Arguments) > 0 && n.Arguments[0].Name != nil
		if len(argNames) == 0 || !namedArgs {
			for i, expr := range n.Arguments {
				ast.Walk(jscg, expr)
				if i < len(n.Arguments)-1 {
					jscg.buffer.WriteString(`,`)
				}
			}
		} else {
			for i, argName := range argNames {
				found := false
				for _, expr := range n.Arguments {
					if expr.Name.Text == argName {
						ast.Walk(jscg, expr.Expression)
						found = true
						break
					}
				}

				if !found {
					jscg.buffer.WriteString("undefined")
				}

				if i < len(argNames)-1 {
					jscg.buffer.WriteString(`,`)
				}
			}
		}

		jscg.buffer.WriteString(`)`)

		return nil
	case *ast.Block:
		jscg.buffer.WriteString(`{`)

		for _, node := range n.Body {
			ast.Walk(jscg, node)
			jscg.buffer.WriteString(";")
		}

		return nil
	case *ast.File:
		for _, node := range n.Body {
			ast.Walk(jscg, node)
			jscg.buffer.WriteString(";")
		}
		return nil
	case *ast.ForLoop:
		jscg.buffer.WriteString(" for (")

		if n.Init != nil {
			ast.Walk(jscg, n.Init)
		}
		jscg.buffer.WriteString(";")

		if n.Condition != nil {
			ast.Walk(jscg, n.Condition)
		}
		jscg.buffer.WriteString(";")

		if n.After != nil {
			ast.Walk(jscg, n.After)
		}
		jscg.buffer.WriteString(")")

		ast.Walk(jscg, n.Block)
		return nil
	case *ast.FunctionDeclaration:
		var name string
		var args []string
		if n.Signature.Identifier != nil {
			name = jscg.getIdentifier(n.Signature.Identifier)
		}

		for _, arg := range n.Signature.Arguments {
			args = append(args, jscg.getIdentifier(arg.Name))
		}

		jscg.buffer.WriteString(fmt.Sprintf(
			`function %s (%s)`,
			name,
			strings.Join(args, ","),
		))

		ast.Walk(jscg, n.Block)

		return nil
	case *ast.ParenExpression:
		jscg.buffer.WriteString("(")
	default:
		panic(fmt.Sprintf("TODO: %T", n))
	}
	return jscg
}

func (jscg *JSCodeGen) Leave(node ast.Node) {
	switch n := node.(type) {
	case *ast.TupleDeclaration:
		// DO nothing
	case *ast.File:
		for _, n := range n.Body {
			if funDecl, ok := n.(*ast.FunctionDeclaration); ok {
				if funDecl.Signature != nil && funDecl.Signature.Identifier != nil && funDecl.Signature.Identifier.Text == "main" {
					name := jscg.getIdentifier(funDecl.Signature.Identifier)
					jscg.buffer.WriteString(fmt.Sprintf("%s && %s();", name, name))
					break
				}
			}
		}

	case *ast.Block:
		jscg.buffer.WriteString(`}`)
	case *ast.ParenExpression:
		jscg.buffer.WriteString(")")
	}
}

func (jscg *JSCodeGen) Generate(file *ast.File) []byte {
	jscg.currentFile = file
	ast.Walk(jscg, file)
	return jscg.buffer.Bytes()
}
<commit_msg>Wrap in self invoking function<commit_after>package js

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/orktes/orlang/analyser"
	"github.com/orktes/orlang/ast"
	"github.com/orktes/orlang/types"
)

type JSCodeGen struct {
	analyserInfo *analyser.Info
	buffer       bytes.Buffer
	currentFile  *ast.File
	identNumbers map[*ast.Identifier]int
}

func New(info *analyser.Info) *JSCodeGen {
	return &JSCodeGen{analyserInfo: info, identNumbers: map[*ast.Identifier]int{}}
}

func (jscg *JSCodeGen) getTempVar() string {
	// TODO check if temp var is defined in scope
	return "_temp"
}

func (jscg *JSCodeGen) getIdentifier(ident *ast.Identifier) string {
	nodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[ident]
	scopeItemDetals := nodeInfo.Scope.GetDetails(ident.Text, true)

	identNumber := 0
	if number, ok := jscg.identNumbers[scopeItemDetals.DefineIdentifier]; ok {
		identNumber = number
	} else {
		identNumber = len(jscg.identNumbers)
		jscg.identNumbers[scopeItemDetals.DefineIdentifier] = identNumber
	}

	return fmt.Sprintf("$%d", identNumber)
}

func (jscg *JSCodeGen) Visit(node ast.Node) ast.Visitor {
	nodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[node]
	switch n := node.(type) {
	case *ast.Macro, *ast.CallArgument:
	case *ast.TupleDeclaration:

		var varName string

		if n.DefaultValue != nil {
			if ident, ok := n.DefaultValue.(*ast.Identifier); ok {
				varName = jscg.getIdentifier(ident)
			}
		}

		if varName == "" {
			varName = jscg.getTempVar()
			jscg.buffer.WriteString(fmt.Sprintf(
				`var %s`,
				varName,
			))

			if n.DefaultValue != nil {
				jscg.buffer.WriteString("=")
			}

			ast.Walk(jscg, n.DefaultValue)

			jscg.buffer.WriteString(";")
		}

		var ptrnPrint func(pattern *ast.TuplePattern, prefix string)
		ptrnPrint = func(pattern *ast.TuplePattern, prefix string) {
			for i, ptrrn := range pattern.Patterns {
				switch pt := ptrrn.(type) {
				case *ast.TuplePattern:
					ptrnPrint(pt, fmt.Sprintf("%s[%d]", prefix, i))
				case *ast.Identifier:
					jscg.buffer.WriteString(
						fmt.Sprintf(
							"var %s = %s[%d]",
							jscg.getIdentifier(pt),
							prefix,
							i,
						))
					if i != len(pattern.Patterns)-1 {
						jscg.buffer.WriteString(";")
					}
				}

			}
		}

		ptrnPrint(n.Pattern, varName)

		return nil
	case *ast.VariableDeclaration:
		jscg.buffer.WriteString(fmt.Sprintf(
			`var %s`,
			jscg.getIdentifier(n.Name),
		))
		if n.DefaultValue != nil {
			jscg.buffer.WriteString("=")
		}

		ast.Walk(jscg, n.DefaultValue)
		return nil
	case *ast.IfStatement:
		jscg.buffer.WriteString(" if (")
		ast.Walk(jscg, n.Condition)
		jscg.buffer.WriteString(")")

		ast.Walk(jscg, n.Block)

		if n.Else != nil {
			jscg.buffer.WriteString(" else ")
			ast.Walk(jscg, n.Else)
		}

		return nil
	case *ast.TupleExpression:
		jscg.buffer.WriteString(`[`)

		for i, expr := range n.Expressions {
			ast.Walk(jscg, expr)
			if i < len(n.Expressions)-1 {
				jscg.buffer.WriteString(`,`)
			}
		}

		jscg.buffer.WriteString(`]`)
		return nil
	case *ast.UnaryExpression:
		if n.Postfix {
			ast.Walk(jscg, n.Expression)

		}

		jscg.buffer.WriteString(n.Operator.Text)

		if n.Postfix {
			return nil
		}
	case *ast.ComparisonExpression:
		ast.Walk(jscg, n.Left)
		jscg.buffer.WriteString(n.Operator.Text)
		ast.Walk(jscg, n.Right)
		return nil
	case *ast.BinaryExpression:
		ast.Walk(jscg, n.Left)
		jscg.buffer.WriteString(n.Operator.Text)
		ast.Walk(jscg, n.Right)
		return nil
	case *ast.Identifier:
		if n == nil {
			break
		}
		if sigType, ok := nodeInfo.Type.(*types.SignatureType); ok {
			if sigType.Extern {
				jscg.buffer.WriteString(n.Text)
				break
			}
		}

		jscg.buffer.WriteString(jscg.getIdentifier(n))
	case *ast.ValueExpression:
		jscg.buffer.WriteString(fmt.Sprintf(
			`%s`,
			n.Text,
		))
	case *ast.ReturnStatement:
		jscg.buffer.WriteString(`return `)
	case *ast.FunctionCall:
		if nodeInfo.TypeCast {
			if nodeInfo.Type == types.Int32Type || nodeInfo.Type == types.Int64Type {
				jscg.buffer.WriteString(`Math.floor`)
			} else {
				ast.Walk(jscg, n.Arguments[0])
				return nil
			}
		} else {
			ast.Walk(jscg, n.Callee)
		}
		jscg.buffer.WriteString(`(`)

		// TODO set named args into the right order
		var argNames []string

		calleeNodeInfo := jscg.analyserInfo.FileInfo[jscg.currentFile].NodeInfo[n.Callee]
		if calleeNodeInfo != nil && calleeNodeInfo.Type != nil {
			argNames = calleeNodeInfo.Type.(*types.SignatureType).ArgumentNames
		}

		namedArgs := len(n.Arguments) > 0 && n.Arguments[0].Name != nil
		if len(argNames) == 0 || !namedArgs {
			for i, expr := range n.Arguments {
				ast.Walk(jscg, expr)
				if i < len(n.Arguments)-1 {
					jscg.buffer.WriteString(`,`)
				}
			}
		} else {
			for i, argName := range argNames {
				found := false
				for _, expr := range n.Arguments {
					if expr.Name.Text == argName {
						ast.Walk(jscg, expr.Expression)
						found = true
						break
					}
				}

				if !found {
					jscg.buffer.WriteString("undefined")
				}

				if i < len(argNames)-1 {
					jscg.buffer.WriteString(`,`)
				}
			}
		}

		jscg.buffer.WriteString(`)`)

		return nil
	case *ast.Block:
		jscg.buffer.WriteString(`{`)

		for _, node := range n.Body {
			ast.Walk(jscg, node)
			jscg.buffer.WriteString(";")
		}

		return nil
	case *ast.File:
		jscg.buffer.WriteString("(function () {")
		for _, node := range n.Body {
			ast.Walk(jscg, node)
			jscg.buffer.WriteString(";")
		}
		return nil
	case *ast.ForLoop:
		jscg.buffer.WriteString(" for (")

		if n.Init != nil {
			ast.Walk(jscg, n.Init)
		}
		jscg.buffer.WriteString(";")

		if n.Condition != nil {
			ast.Walk(jscg, n.Condition)
		}
		jscg.buffer.WriteString(";")

		if n.After != nil {
			ast.Walk(jscg, n.After)
		}
		jscg.buffer.WriteString(")")

		ast.Walk(jscg, n.Block)
		return nil
	case *ast.FunctionDeclaration:
		var name string
		var args []string
		if n.Signature.Identifier != nil {
			name = jscg.getIdentifier(n.Signature.Identifier)
		}

		for _, arg := range n.Signature.Arguments {
			args = append(args, jscg.getIdentifier(arg.Name))
		}

		jscg.buffer.WriteString(fmt.Sprintf(
			`function %s (%s)`,
			name,
			strings.Join(args, ","),
		))

		ast.Walk(jscg, n.Block)

		return nil
	case *ast.ParenExpression:
		jscg.buffer.WriteString("(")
	default:
		panic(fmt.Sprintf("TODO: %T", n))
	}
	return jscg
}

func (jscg *JSCodeGen) Leave(node ast.Node) {
	switch n := node.(type) {
	case *ast.TupleDeclaration:
		// DO nothing
	case *ast.File:
		for _, n := range n.Body {
			if funDecl, ok := n.(*ast.FunctionDeclaration); ok {
				if funDecl.Signature != nil && funDecl.Signature.Identifier != nil && funDecl.Signature.Identifier.Text == "main" {
					name := jscg.getIdentifier(funDecl.Signature.Identifier)
					jscg.buffer.WriteString(fmt.Sprintf("%s && %s();", name, name))
					break
				}
			}
		}

		jscg.buffer.WriteString("})();")
	case *ast.Block:
		jscg.buffer.WriteString(`}`)
	case *ast.ParenExpression:
		jscg.buffer.WriteString(")")
	}
}

func (jscg *JSCodeGen) Generate(file *ast.File) []byte {
	jscg.currentFile = file
	ast.Walk(jscg, file)
	return jscg.buffer.Bytes()
}
<|endoftext|>