<commit_before>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam    = "auth"
	formatParam  = "format"
	shallowParam = "shallow"
	formatVal    = "export"
)

// Firebase represents a location in the cloud
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect
// See: https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference
func New(url string) *Firebase {

	var tr *http.Transport
	tr = &http.Transport{
		DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
		Dial: func(network, address string) (net.Conn, error) {
			start := time.Now()
			c, err := net.DialTimeout(network, address, TimeoutDuration)
			tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
			return c, err
		},
	}

	var client *http.Client
	client = &http.Client{
		Transport:     tr,
		CheckRedirect: redirectPreserveHeaders,
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent
func (fb *Firebase) Child(child string) *Firebase {
	c := &Firebase{
		url:          fb.url + "/" + child,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

// StartAt creates a new Firebase reference with the
// requested StartAt configuration
func (fb *Firebase) StartAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("startAt", value)
	} else {
		c.params.Del("startAt")
	}
	return c
}

// EndAt creates a new Firebase reference with the
// requested EndAt configuration
func (fb *Firebase) EndAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("endAt", value)
	} else {
		c.params.Del("endAt")
	}
	return c
}

// OrderBy creates a new Firebase reference with the
// requested OrderBy configuration
func (fb *Firebase) OrderBy(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("orderBy", value)
	} else {
		c.params.Del("orderBy")
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	fmt.Printf("Firebase Path: %v ", path)
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<commit_msg>Removes log<commit_after>/*
Package firego is a REST client for Firebase (https://firebase.com).
*/
package firego

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	_url "net/url"
	"strings"
	"sync"
	"time"
)

// TimeoutDuration is the length of time any request will have to establish
// a connection and receive headers from Firebase before returning
// an ErrTimeout error
var TimeoutDuration = 30 * time.Second

var defaultRedirectLimit = 30

// ErrTimeout is an error type is that is returned if a request
// exceeds the TimeoutDuration configured
type ErrTimeout struct {
	error
}

// query parameter constants
const (
	authParam    = "auth"
	formatParam  = "format"
	shallowParam = "shallow"
	formatVal    = "export"
)

// Firebase represents a location in the cloud
type Firebase struct {
	url    string
	params _url.Values
	client *http.Client

	watchMtx     sync.Mutex
	watching     bool
	stopWatching chan struct{}
}

func sanitizeURL(url string) string {
	if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
		url = "https://" + url
	}

	if strings.HasSuffix(url, "/") {
		url = url[:len(url)-1]
	}

	return url
}

// Preserve headers on redirect
// See: https://github.com/golang/go/issues/4800
func redirectPreserveHeaders(req *http.Request, via []*http.Request) error {
	if len(via) == 0 {
		// No redirects
		return nil
	}

	if len(via) > defaultRedirectLimit {
		return fmt.Errorf("%d consecutive requests(redirects)", len(via))
	}

	// mutate the subsequent redirect requests with the first Header
	for key, val := range via[0].Header {
		req.Header[key] = val
	}
	return nil
}

// New creates a new Firebase reference
func New(url string) *Firebase {

	var tr *http.Transport
	tr = &http.Transport{
		DisableKeepAlives: true, // https://code.google.com/p/go/issues/detail?id=3514
		Dial: func(network, address string) (net.Conn, error) {
			start := time.Now()
			c, err := net.DialTimeout(network, address, TimeoutDuration)
			tr.ResponseHeaderTimeout = TimeoutDuration - time.Since(start)
			return c, err
		},
	}

	var client *http.Client
	client = &http.Client{
		Transport:     tr,
		CheckRedirect: redirectPreserveHeaders,
	}

	return &Firebase{
		url:          sanitizeURL(url),
		params:       _url.Values{},
		client:       client,
		stopWatching: make(chan struct{}),
	}
}

// String returns the string representation of the
// Firebase reference
func (fb *Firebase) String() string {
	return fb.url
}

// Child creates a new Firebase reference for the requested
// child with the same configuration as the parent
func (fb *Firebase) Child(child string) *Firebase {
	c := &Firebase{
		url:          fb.url + "/" + child,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	return c
}

// StartAt creates a new Firebase reference with the
// requested StartAt configuration
func (fb *Firebase) StartAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("startAt", value)
	} else {
		c.params.Del("startAt")
	}
	return c
}

// EndAt creates a new Firebase reference with the
// requested EndAt configuration
func (fb *Firebase) EndAt(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("endAt", value)
	} else {
		c.params.Del("endAt")
	}
	return c
}

// OrderBy creates a new Firebase reference with the
// requested OrderBy configuration
func (fb *Firebase) OrderBy(value string) *Firebase {
	c := &Firebase{
		url:          fb.url,
		params:       _url.Values{},
		client:       fb.client,
		stopWatching: make(chan struct{}),
	}

	// making sure to manually copy the map items into a new
	// map to avoid modifying the map reference.
	for k, v := range fb.params {
		c.params[k] = v
	}
	if value != "" {
		c.params.Set("orderBy", value)
	} else {
		c.params.Del("orderBy")
	}
	return c
}

// Shallow limits the depth of the data returned when calling Value.
// If the data at the location is a JSON primitive (string, number or boolean),
// its value will be returned. If the data is a JSON object, the values
// for each key will be truncated to true.
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-shallow
func (fb *Firebase) Shallow(v bool) {
	if v {
		fb.params.Set(shallowParam, "true")
	} else {
		fb.params.Del(shallowParam)
	}
}

// IncludePriority determines whether or not to ask Firebase
// for the values priority. By default, the priority is not returned
//
// Reference https://www.firebase.com/docs/rest/api/#section-param-format
func (fb *Firebase) IncludePriority(v bool) {
	if v {
		fb.params.Set(formatParam, formatVal)
	} else {
		fb.params.Del(formatParam)
	}
}

func (fb *Firebase) makeRequest(method string, body []byte) (*http.Request, error) {
	path := fb.url + "/.json"

	if len(fb.params) > 0 {
		path += "?" + fb.params.Encode()
	}
	return http.NewRequest(method, path, bytes.NewReader(body))
}

func (fb *Firebase) doRequest(method string, body []byte) ([]byte, error) {
	req, err := fb.makeRequest(method, body)
	if err != nil {
		return nil, err
	}

	resp, err := fb.client.Do(req)
	switch err := err.(type) {
	default:
		return nil, err
	case nil:
		// carry on

	case *_url.Error:
		// `http.Client.Do` will return a `url.Error` that wraps a `net.Error`
		// when exceeding it's `Transport`'s `ResponseHeadersTimeout`
		e1, ok := err.Err.(net.Error)
		if ok && e1.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err

	case net.Error:
		// `http.Client.Do` will return a `net.Error` directly when Dial times
		// out, or when the Client's RoundTripper otherwise returns an err
		if err.Timeout() {
			return nil, ErrTimeout{err}
		}

		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode/200 != 1 {
		return nil, errors.New(string(respBody))
	}
	return respBody, nil
}
<|endoftext|>


<commit_before>package socket

import (
	"time"
	"github.com/neliseev/logger"
)

// Defaults
const maxTCPQueries  int           = 256
const tcpIdleTimeout time.Duration = 60 * time.Second
const rtimeout       time.Duration = 2 * time.Second // Socket read timeout
const msgSep         []byte          = []byte(":")
const udpMsgSize     int           = 508             // RFC 791 (Min IP Size - Max IP Header Size - UDP Header Size)
const maxMsgSize     int           = 128             // ToDo Set configurable?

// Init logger subsystem
var log logger.Log

func init() {
	log.New()
}<commit_msg>Fix errors with types in conditions<commit_after>package socket

import (
	"time"
	"github.com/neliseev/logger"
)

// Defaults vars
var msgSep = byte(":")

// Constants
const maxTCPQueries  int           = 256
const tcpIdleTimeout time.Duration = 60 * time.Second
const rtimeout       time.Duration = 2 * time.Second // Socket read timeout
const udpMsgSize     int           = 508             // RFC 791 (Min IP Size - Max IP Header Size - UDP Header Size)
const maxMsgSize     int           = 128             // ToDo Set configurable?

// Init logger subsystem
var log logger.Log

func init() {
	log.New()
}<|endoftext|>


<commit_before>package compiler

import (
	"fmt"
	"path/filepath"
	"strings"

	"bitbucket.org/moovie/util/template"

	"github.com/crackcomm/renderer/storage"
)

// parseTemplate - Parse template from string.
// String may be in URL format (eq. `http://...` or `file://...`).
// Or it may contain template data in format `data:template {{ here }}`.
// Or it may contain pure text data in format `text:plain data here`.
func parseTemplate(s *storage.Storage, text, baseDir string) (t template.Template, err error) {
	scheme, rest, ok := parseScheme(text)
	if !ok {
		return nil, fmt.Errorf("invalid template url %q", text)
	}

	switch scheme {
	case "template":
		return template.FromString(rest)
	case "file":
		if baseDir != "" {
			rest = filepath.Join(baseDir, rest)
		}
		return s.Template(rest)
	case "http", "https":
		return template.Text(text), nil
	case "text":
		return template.Text(rest), nil
	}

	return
}

// parseTemplates - Parses list of templates.
func parseTemplates(s *storage.Storage, texts []string, baseDir string, start []template.Template) (res []template.Template, err error) {
	res = start
	for _, text := range texts {
		t, err := parseTemplate(s, text, baseDir)
		if err != nil {
			return nil, err
		}
		res = append(res, t)
	}
	return
}

func parseScheme(text string) (scheme, rest string, ok bool) {
	i := strings.Index(text, "://")
	if i == -1 {
		return
	}
	scheme = text[:i]
	rest = text[i+3:]
	ok = true
	return
}
<commit_msg>compiler: file+text for files without templates, allow file paths in styles and scripts<commit_after>package compiler

import (
	"fmt"
	"path/filepath"
	"strings"

	"bitbucket.org/moovie/util/template"

	"github.com/crackcomm/renderer/storage"
)

// parseTemplate - Parse template from string.
// String may be in URL format (eq. `http://...` or `file://...`).
// Or it may contain template data in format `data:template {{ here }}`.
// Or it may contain pure text data in format `text:plain data here`.
func parseTemplate(s *storage.Storage, text, baseDir string) (t template.Template, err error) {
	scheme, rest, ok := parseScheme(text)
	if !ok {
		return nil, fmt.Errorf("missing scheme from template URL: %q", text)
	}

	switch scheme {
	case "template":
		return template.FromString(rest)
	case "file":
		if baseDir != "" {
			rest = filepath.Join(baseDir, rest)
		}
		t, err = s.Template(rest)
		if err != nil {
			return nil, fmt.Errorf("%s: %v", text, err)
		}
		return
	case "file+text":
		if baseDir != "" {
			rest = filepath.Join(baseDir, rest)
		}
		t, err = s.Text(rest)
		if err != nil {
			return nil, fmt.Errorf("%s: %v", text, err)
		}
		return
	case "http", "https":
		return template.Text(text), nil
	case "text":
		return template.Text(rest), nil
	}

	return
}

// parseTemplates - Parses list of templates.
func parseTemplates(s *storage.Storage, texts []string, baseDir string, start []template.Template) (res []template.Template, err error) {
	res = start
	for _, text := range texts {
		t, err := parseTemplate(s, text, baseDir)
		if err != nil {
			return nil, err
		}
		res = append(res, t)
	}
	return
}

func parseScheme(text string) (scheme, rest string, ok bool) {
	if strings.HasPrefix(text, "/") {
		return "http", text, true
	}
	i := strings.Index(text, "://")
	if i == -1 {
		return
	}
	scheme = text[:i]
	rest = text[i+3:]
	ok = true
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"os"
	"runtime"

	"github.com/davecheney/profile"
	"github.com/thinkofdeath/steven/platform"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/protocol/mojang"
	"github.com/thinkofdeath/steven/render"
)

func main() {
	defer profile.Start(&profile.Config{
		CPUProfile:  true,
		ProfilePath: "./",
	}).Stop()
	runtime.GOMAXPROCS(runtime.NumCPU() * 2)

	// Can't use flags as we need to support a weird flag
	// format
	var username, uuid, accessToken, server string

	for i, arg := range os.Args {
		switch arg {
		case "--username":
			username = os.Args[i+1]
		case "--uuid":
			uuid = os.Args[i+1]
		case "--accessToken":
			accessToken = os.Args[i+1]
		case "--server":
			server = os.Args[i+1]
		}
	}

	// Start connecting whilst starting the renderer
	go startConnection(mojang.Profile{
		Username:    username,
		ID:          uuid,
		AccessToken: accessToken,
	}, server)

	platform.Init(platform.Handler{
		Start:  start,
		Draw:   draw,
		Move:   move,
		Rotate: rotate,
		Action: action,
	})
}

func start() {
	render.Start()
}

func rotate(x, y float64) {
	render.Camera.Yaw -= x
	render.Camera.Pitch -= y
}

var mf, ms float64

func move(f, s float64) {
	mf, ms = f, s
}

func action(action platform.Action) {
	fmt.Println("action: ", action)
	switch action {
	case platform.DebugRefresh:
		fmt.Println(len(chunkMap))
		for _, c := range chunkMap {
			for _, s := range c.Sections {
				if s != nil {
					s.dirty = true
				}
			}
		}
	}
}

var maxBuilders = runtime.NumCPU() * 2

var (
	ready            bool
	tick             int
	freeBuilders     = maxBuilders
	completeBuilders = make(chan buildPos, maxBuilders)
	syncChan         = make(chan func(), 200)
)

func draw() {
handle:
	for {
		select {
		case err := <-errorChan:
			panic(err)
		case packet := <-readChan:
			defaultHandler.Handle(packet)
		case pos := <-completeBuilders:
			c := chunkMap[chunkPosition{pos.X, pos.Z}]
			freeBuilders++
			if c != nil {
				s := c.Sections[pos.Y]
				if s != nil {
					s.building = false
				}
			}
		case f := <-syncChan:
			f()
		default:
			break handle
		}
	}

	// TODO(Think) Tidy up
	render.Camera.X += mf * math.Cos(render.Camera.Yaw-math.Pi/2) * -math.Cos(render.Camera.Pitch) * (1.0 / 7.0)
	render.Camera.Z -= mf * math.Sin(render.Camera.Yaw-math.Pi/2) * -math.Cos(render.Camera.Pitch) * (1.0 / 7.0)
	render.Camera.Y -= mf * math.Sin(render.Camera.Pitch) * (1.0 / 7.0)
	tick++
	if ready && tick%3 == 0 {
		writeChan <- &protocol.PlayerPositionLook{
			X:     render.Camera.X,
			Y:     render.Camera.Y,
			Z:     render.Camera.Z,
			Yaw:   float32(-render.Camera.Yaw * (180 / math.Pi)),
			Pitch: float32((-render.Camera.Pitch - math.Pi) * (180 / math.Pi)),
		}
	}

dirtyClean:
	for _, c := range sortedChunks() {
		for _, s := range c.Sections {
			if s == nil {
				continue
			}
			if freeBuilders <= 0 {
				break dirtyClean
			}
			if s.dirty && !s.building {
				freeBuilders--
				s.dirty = false
				s.building = true
				s.build(completeBuilders)
			}
		}
	}

	render.Draw()
}
<commit_msg>/: remove profiling<commit_after>package main

import (
	"fmt"
	"math"
	"os"
	"runtime"

	"github.com/thinkofdeath/steven/platform"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/protocol/mojang"
	"github.com/thinkofdeath/steven/render"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU() * 2)

	// Can't use flags as we need to support a weird flag
	// format
	var username, uuid, accessToken, server string

	for i, arg := range os.Args {
		switch arg {
		case "--username":
			username = os.Args[i+1]
		case "--uuid":
			uuid = os.Args[i+1]
		case "--accessToken":
			accessToken = os.Args[i+1]
		case "--server":
			server = os.Args[i+1]
		}
	}

	// Start connecting whilst starting the renderer
	go startConnection(mojang.Profile{
		Username:    username,
		ID:          uuid,
		AccessToken: accessToken,
	}, server)

	platform.Init(platform.Handler{
		Start:  start,
		Draw:   draw,
		Move:   move,
		Rotate: rotate,
		Action: action,
	})
}

func start() {
	render.Start()
}

func rotate(x, y float64) {
	render.Camera.Yaw -= x
	render.Camera.Pitch -= y
}

var mf, ms float64

func move(f, s float64) {
	mf, ms = f, s
}

func action(action platform.Action) {
	fmt.Println("action: ", action)
	switch action {
	case platform.DebugRefresh:
		fmt.Println(len(chunkMap))
		for _, c := range chunkMap {
			for _, s := range c.Sections {
				if s != nil {
					s.dirty = true
				}
			}
		}
	}
}

var maxBuilders = runtime.NumCPU() * 2

var (
	ready            bool
	tick             int
	freeBuilders     = maxBuilders
	completeBuilders = make(chan buildPos, maxBuilders)
	syncChan         = make(chan func(), 200)
)

func draw() {
handle:
	for {
		select {
		case err := <-errorChan:
			panic(err)
		case packet := <-readChan:
			defaultHandler.Handle(packet)
		case pos := <-completeBuilders:
			c := chunkMap[chunkPosition{pos.X, pos.Z}]
			freeBuilders++
			if c != nil {
				s := c.Sections[pos.Y]
				if s != nil {
					s.building = false
				}
			}
		case f := <-syncChan:
			f()
		default:
			break handle
		}
	}

	// TODO(Think) Tidy up
	render.Camera.X += mf * math.Cos(render.Camera.Yaw-math.Pi/2) * -math.Cos(render.Camera.Pitch) * (1.0 / 7.0)
	render.Camera.Z -= mf * math.Sin(render.Camera.Yaw-math.Pi/2) * -math.Cos(render.Camera.Pitch) * (1.0 / 7.0)
	render.Camera.Y -= mf * math.Sin(render.Camera.Pitch) * (1.0 / 7.0)
	tick++
	if ready && tick%3 == 0 {
		writeChan <- &protocol.PlayerPositionLook{
			X:     render.Camera.X,
			Y:     render.Camera.Y,
			Z:     render.Camera.Z,
			Yaw:   float32(-render.Camera.Yaw * (180 / math.Pi)),
			Pitch: float32((-render.Camera.Pitch - math.Pi) * (180 / math.Pi)),
		}
	}

dirtyClean:
	for _, c := range sortedChunks() {
		for _, s := range c.Sections {
			if s == nil {
				continue
			}
			if freeBuilders <= 0 {
				break dirtyClean
			}
			if s.dirty && !s.building {
				freeBuilders--
				s.dirty = false
				s.building = true
				s.build(completeBuilders)
			}
		}
	}

	render.Draw()
}
<|endoftext|>


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

package slogger

import (
	"errors"
	"fmt"
	"github.com/tolsen/slogger/v2/queued_set"
	"runtime"
	"strings"
	"time"
)

type Log struct {
	Prefix     string
	Level      Level
	Filename   string
	FuncName   string
	Line       int
	Timestamp  time.Time
	MessageFmt string
	Args       []interface{}
	Context    *Context
}

func SimpleLog(prefix string, level Level, callerSkip int, messageFmt string, args ...interface{}) *Log {
	return SimpleLogStrippingDirs(prefix, level, callerSkip, -1, messageFmt, args...)
}

func SimpleLogStrippingDirs(prefix string, level Level, callerSkip int, numDirsToKeep int, messageFmt string, args ...interface{}) *Log {
	pc, file, line, ok := runtime.Caller(callerSkip)
	funcName := ""

	if ok {
		funcName = runtime.FuncForPC(pc).Name()
	} else {
		file = "UNKNOWN_FILE"
		line = -1
	}

	if numDirsToKeep >= 0 {
		file = stripDirectories(file, numDirsToKeep)
	}

	return &Log{
		Prefix:     prefix,
		Level:      level,
		Filename:   file,
		FuncName:   funcName,
		Line:       line,
		Timestamp:  time.Now(),
		MessageFmt: messageFmt,
		Args:       args,
	}
}

func (self *Log) Message() string {
	messageFmt := self.MessageFmt
	if self.Context != nil {
		messageFmt = self.Context.interpolateString(self.MessageFmt)
	}

	return fmt.Sprintf(messageFmt, self.Args...)
}

// for use as a cache key
func (self *Log) stringWithoutTime() string {
	return fmt.Sprintf(
		"%s %v %s %s %d %s",
		self.Prefix,
		self.Level.Type(),
		self.Filename,
		self.FuncName,
		self.Line,
		self.Message(),
	)
}

type Logger struct {
	Prefix             string
	Appenders          []Appender
	StripDirs          int
	cache              *queued_set.QueuedSet
	suppressionEnabled bool
}

// Log a message and a level to a logger instance. This returns a
// pointer to a Log and a slice of errors that were gathered from every
// Appender (nil errors included).
func (self *Logger) Logf(level Level, messageFmt string, args ...interface{}) (*Log, []error) {
	return self.logf(level, messageFmt, nil, args...)
}

func (self *Logger) LogfWithContext(level Level, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	return self.logf(level, messageFmt, context, args...)
}

func (self *Logger) DisableLogSuppression() {
	self.suppressionEnabled = false
	self.cache = nil
	return
}

func (self *Logger) EnableLogSuppression(historyCapacity int) {
	self.cache = queued_set.New(historyCapacity)
	self.suppressionEnabled = true
	return
}

// Log and return a formatted error string.
// Example:
//
// if whatIsExpected != whatIsReturned {
//     return slogger.Errorf(slogger.WARN, "Unexpected return value. Expected: %v Received: %v",
//         whatIsExpected, whatIsReturned)
// }5
//
func (self *Logger) Errorf(level Level, messageFmt string, args ...interface{}) error {
	return self.ErrorfWithContext(level, messageFmt, nil, args...)
}

func (self *Logger) ErrorfWithContext(level Level, messageFmt string, context *Context, args ...interface{}) error {
	log, _ := self.logf(level, messageFmt, context, args...)
	return errors.New(log.Message())
}

func (self *Logger) Flush() (errors []error) {
	for _, appender := range self.Appenders {
		if err := appender.Flush(); err != nil {
			errors = append(errors, err)
		}
	}
	return
}

func (self *Logger) IsSuppressionEnabled() bool {
	return self.suppressionEnabled
}

// Stackf is designed to work in tandem with `NewStackError`. This
// function is similar to `Logf`, but takes a `stackErr`
// parameter. `stackErr` is expected to be of type StackError, but does
// not have to be.
func (self *Logger) Stackf(level Level, stackErr error, messageFmt string, args ...interface{}) (*Log, []error) {
	return self.StackfWithContext(level, stackErr, messageFmt, nil, args...)
}

func (self *Logger) StackfWithContext(level Level, stackErr error, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	messageFmt = fmt.Sprintf("%v\n%v", messageFmt, stackErr.Error())
	return self.logf(level, messageFmt, context, args...)
}

var ignoredFileNames = []string{"logger.go"}

// Add a file to the list of file names that slogger will skip when it identifies the source
// of a message.  This is useful if you have a logging library built on top of slogger.
// If you IgnoreThisFilenameToo(...) on the files of that library, logging messages
// will be marked as coming from your code that calls your library, rather than from your library.
func IgnoreThisFilenameToo(fn string) {
	ignoredFileNames = append(ignoredFileNames, fn)
}

func containsAnyIgnoredFilename(s string) bool {
	for _, ign := range ignoredFileNames {
		if strings.Contains(s, ign) {
			return true
		}
	}
	return false
}

func nonSloggerCaller() (pc uintptr, file string, line int, ok bool) {
	for skip := 0; skip < 100; skip++ {
		pc, file, line, ok := runtime.Caller(skip)
		if !ok || !containsAnyIgnoredFilename(file) {
			return pc, file, line, ok
		}
	}
	return 0, "", 0, false
}

// accepts a Context or *Context as the first element of args
func (self *Logger) logf(level Level, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	var errors []error

	pc, file, line, ok := nonSloggerCaller()
	//	_, file, line, ok := runtime.Caller(2+offset)
	if ok == false {
		return nil, []error{fmt.Errorf("Failed to find the calling method.")}
	}

	file = stripDirectories(file, self.StripDirs)
	log := &Log{
		Prefix:     self.Prefix,
		Level:      level,
		Filename:   file,
		FuncName:   runtime.FuncForPC(pc).Name(),
		Line:       line,
		Timestamp:  time.Now(),
		MessageFmt: messageFmt,
		Args:       args,
		Context:    context,
	}

	if !self.suppressionEnabled || self.cache.Add(log.stringWithoutTime()) {
		for _, appender := range self.Appenders {
			if err := appender.Append(log); err != nil {
				error := fmt.Errorf("Error appending. Appender: %T Error: %v", appender, err)
				errors = append(errors, error)
			}
		}
	}

	return log, errors
}

type Level uint8

// The level is in an order such that the expressions
// `level < WARN`, `level >= INFO` have intuitive meaning.
const (
	OFF Level = iota
	DEBUG
	ROUTINE
	INFO
	WARN
	ERROR
	DOOM
	topLevel
)

var strToLevel map[string]Level

var levelToStr []string

func init() {
	strToLevel = map[string]Level{
		"off":     OFF,
		"debug":   DEBUG,
		"routine": ROUTINE,
		"info":    INFO,
		"warn":    WARN,
		"error":   ERROR,
		"doom":    DOOM,
	}

	levelToStr = make([]string, len(strToLevel))
	for str, level := range strToLevel {
		levelToStr[uint8(level)] = str
	}
}

func NewLevel(levelStr string) (Level, error) {
	level, ok := strToLevel[strings.ToLower(levelStr)]

	if !ok {
		err := UnknownLevelError{levelStr}
		return OFF, err
	}

	return level, nil
}

func (self Level) String() string {
	return self.Type()
}

func (self Level) Type() string {
	if self >= topLevel {
		return "off?"
	}

	return levelToStr[uint8(self)]
}

func stacktrace() []string {
	ret := make([]string, 0, 2)
	for skip := 2; true; skip++ {
		_, file, line, ok := runtime.Caller(skip)
		if ok == false {
			break
		}

		ret = append(ret, fmt.Sprintf("at %s:%d", stripDirectories(file, 2), line))
	}

	return ret
}

type StackError struct {
	Message    string
	Stacktrace []string
}

func NewStackError(messageFmt string, args ...interface{}) *StackError {
	return &StackError{
		Message:    fmt.Sprintf(messageFmt, args...),
		Stacktrace: stacktrace(),
	}
}

func (self *StackError) Error() string {
	return fmt.Sprintf("%s\n\t%s", self.Message, strings.Join(self.Stacktrace, "\n\t"))
}

func stripDirectories(filepath string, toKeep int) string {
	var idxCutoff int
	if idxCutoff = strings.LastIndex(filepath, "/"); idxCutoff == -1 {
		return filepath
	}

	for dirToKeep := 0; dirToKeep < toKeep; dirToKeep++ {
		switch idx := strings.LastIndex(filepath[:idxCutoff], "/"); idx {
		case -1:
			break
		default:
			idxCutoff = idx
		}
	}

	return filepath[idxCutoff+1:]
}

type UnknownLevelError struct {
	levelStr string
}

func (self UnknownLevelError) Error() string {
	return fmt.Sprintf("Unknown level: %s", self.levelStr)
}
<commit_msg>Strip off namespace from function name in log<commit_after>// Copyright 2013, 2014 MongoDB, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package slogger

import (
	"errors"
	"fmt"
	"github.com/tolsen/slogger/v2/queued_set"
	"runtime"
	"strings"
	"time"
)

type Log struct {
	Prefix     string
	Level      Level
	Filename   string
	FuncName   string
	Line       int
	Timestamp  time.Time
	MessageFmt string
	Args       []interface{}
	Context    *Context
}

func SimpleLog(prefix string, level Level, callerSkip int, messageFmt string, args ...interface{}) *Log {
	return SimpleLogStrippingDirs(prefix, level, callerSkip, -1, messageFmt, args...)
}

func SimpleLogStrippingDirs(prefix string, level Level, callerSkip int, numDirsToKeep int, messageFmt string, args ...interface{}) *Log {
	pc, file, line, ok := runtime.Caller(callerSkip)
	funcName := ""

	if ok {
		funcName = baseFuncNameForPC(pc)
	} else {
		file = "UNKNOWN_FILE"
		line = -1
	}

	if numDirsToKeep >= 0 {
		file = stripDirectories(file, numDirsToKeep)
	}

	return &Log{
		Prefix:     prefix,
		Level:      level,
		Filename:   file,
		FuncName:   funcName,
		Line:       line,
		Timestamp:  time.Now(),
		MessageFmt: messageFmt,
		Args:       args,
	}
}

func (self *Log) Message() string {
	messageFmt := self.MessageFmt
	if self.Context != nil {
		messageFmt = self.Context.interpolateString(self.MessageFmt)
	}

	return fmt.Sprintf(messageFmt, self.Args...)
}

// for use as a cache key
func (self *Log) stringWithoutTime() string {
	return fmt.Sprintf(
		"%s %v %s %s %d %s",
		self.Prefix,
		self.Level.Type(),
		self.Filename,
		self.FuncName,
		self.Line,
		self.Message(),
	)
}

type Logger struct {
	Prefix             string
	Appenders          []Appender
	StripDirs          int
	cache              *queued_set.QueuedSet
	suppressionEnabled bool
}

// Log a message and a level to a logger instance. This returns a
// pointer to a Log and a slice of errors that were gathered from every
// Appender (nil errors included).
func (self *Logger) Logf(level Level, messageFmt string, args ...interface{}) (*Log, []error) {
	return self.logf(level, messageFmt, nil, args...)
}

func (self *Logger) LogfWithContext(level Level, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	return self.logf(level, messageFmt, context, args...)
}

func (self *Logger) DisableLogSuppression() {
	self.suppressionEnabled = false
	self.cache = nil
	return
}

func (self *Logger) EnableLogSuppression(historyCapacity int) {
	self.cache = queued_set.New(historyCapacity)
	self.suppressionEnabled = true
	return
}

// Log and return a formatted error string.
// Example:
//
// if whatIsExpected != whatIsReturned {
//     return slogger.Errorf(slogger.WARN, "Unexpected return value. Expected: %v Received: %v",
//         whatIsExpected, whatIsReturned)
// }5
//
func (self *Logger) Errorf(level Level, messageFmt string, args ...interface{}) error {
	return self.ErrorfWithContext(level, messageFmt, nil, args...)
}

func (self *Logger) ErrorfWithContext(level Level, messageFmt string, context *Context, args ...interface{}) error {
	log, _ := self.logf(level, messageFmt, context, args...)
	return errors.New(log.Message())
}

func (self *Logger) Flush() (errors []error) {
	for _, appender := range self.Appenders {
		if err := appender.Flush(); err != nil {
			errors = append(errors, err)
		}
	}
	return
}

func (self *Logger) IsSuppressionEnabled() bool {
	return self.suppressionEnabled
}

// Stackf is designed to work in tandem with `NewStackError`. This
// function is similar to `Logf`, but takes a `stackErr`
// parameter. `stackErr` is expected to be of type StackError, but does
// not have to be.
func (self *Logger) Stackf(level Level, stackErr error, messageFmt string, args ...interface{}) (*Log, []error) {
	return self.StackfWithContext(level, stackErr, messageFmt, nil, args...)
}

func (self *Logger) StackfWithContext(level Level, stackErr error, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	messageFmt = fmt.Sprintf("%v\n%v", messageFmt, stackErr.Error())
	return self.logf(level, messageFmt, context, args...)
}

var ignoredFileNames = []string{"logger.go"}

// Add a file to the list of file names that slogger will skip when it identifies the source
// of a message.  This is useful if you have a logging library built on top of slogger.
// If you IgnoreThisFilenameToo(...) on the files of that library, logging messages
// will be marked as coming from your code that calls your library, rather than from your library.
func IgnoreThisFilenameToo(fn string) {
	ignoredFileNames = append(ignoredFileNames, fn)
}

func baseFuncNameForPC(pc uintptr) string {
	fullFuncName := runtime.FuncForPC(pc).Name()

	// strip github.com/tolsen/slogger/v2slogger.BaseFuncNameForPC down to BaseFuncNameForPC
	periodIndex := strings.LastIndex(fullFuncName, ".")
	if periodIndex >= 0 {
		return fullFuncName[(periodIndex + 1):]
	}

	// no period present.  Just return the full function name
	return fullFuncName
}

func containsAnyIgnoredFilename(s string) bool {
	for _, ign := range ignoredFileNames {
		if strings.Contains(s, ign) {
			return true
		}
	}
	return false
}

func nonSloggerCaller() (pc uintptr, file string, line int, ok bool) {
	for skip := 0; skip < 100; skip++ {
		pc, file, line, ok := runtime.Caller(skip)
		if !ok || !containsAnyIgnoredFilename(file) {
			return pc, file, line, ok
		}
	}
	return 0, "", 0, false
}

// accepts a Context or *Context as the first element of args
func (self *Logger) logf(level Level, messageFmt string, context *Context, args ...interface{}) (*Log, []error) {
	var errors []error

	pc, file, line, ok := nonSloggerCaller()
	//	_, file, line, ok := runtime.Caller(2+offset)
	if ok == false {
		return nil, []error{fmt.Errorf("Failed to find the calling method.")}
	}

	file = stripDirectories(file, self.StripDirs)
	log := &Log{
		Prefix:     self.Prefix,
		Level:      level,
		Filename:   file,
		FuncName:   baseFuncNameForPC(pc),
		Line:       line,
		Timestamp:  time.Now(),
		MessageFmt: messageFmt,
		Args:       args,
		Context:    context,
	}

	if !self.suppressionEnabled || self.cache.Add(log.stringWithoutTime()) {
		for _, appender := range self.Appenders {
			if err := appender.Append(log); err != nil {
				error := fmt.Errorf("Error appending. Appender: %T Error: %v", appender, err)
				errors = append(errors, error)
			}
		}
	}

	return log, errors
}

type Level uint8

// The level is in an order such that the expressions
// `level < WARN`, `level >= INFO` have intuitive meaning.
const (
	OFF Level = iota
	DEBUG
	ROUTINE
	INFO
	WARN
	ERROR
	DOOM
	topLevel
)

var strToLevel map[string]Level

var levelToStr []string

func init() {
	strToLevel = map[string]Level{
		"off":     OFF,
		"debug":   DEBUG,
		"routine": ROUTINE,
		"info":    INFO,
		"warn":    WARN,
		"error":   ERROR,
		"doom":    DOOM,
	}

	levelToStr = make([]string, len(strToLevel))
	for str, level := range strToLevel {
		levelToStr[uint8(level)] = str
	}
}

func NewLevel(levelStr string) (Level, error) {
	level, ok := strToLevel[strings.ToLower(levelStr)]

	if !ok {
		err := UnknownLevelError{levelStr}
		return OFF, err
	}

	return level, nil
}

func (self Level) String() string {
	return self.Type()
}

func (self Level) Type() string {
	if self >= topLevel {
		return "off?"
	}

	return levelToStr[uint8(self)]
}

func stacktrace() []string {
	ret := make([]string, 0, 2)
	for skip := 2; true; skip++ {
		_, file, line, ok := runtime.Caller(skip)
		if ok == false {
			break
		}

		ret = append(ret, fmt.Sprintf("at %s:%d", stripDirectories(file, 2), line))
	}

	return ret
}

type StackError struct {
	Message    string
	Stacktrace []string
}

func NewStackError(messageFmt string, args ...interface{}) *StackError {
	return &StackError{
		Message:    fmt.Sprintf(messageFmt, args...),
		Stacktrace: stacktrace(),
	}
}

func (self *StackError) Error() string {
	return fmt.Sprintf("%s\n\t%s", self.Message, strings.Join(self.Stacktrace, "\n\t"))
}

func stripDirectories(filepath string, toKeep int) string {
	var idxCutoff int
	if idxCutoff = strings.LastIndex(filepath, "/"); idxCutoff == -1 {
		return filepath
	}

	for dirToKeep := 0; dirToKeep < toKeep; dirToKeep++ {
		switch idx := strings.LastIndex(filepath[:idxCutoff], "/"); idx {
		case -1:
			break
		default:
			idxCutoff = idx
		}
	}

	return filepath[idxCutoff+1:]
}

type UnknownLevelError struct {
	levelStr string
}

func (self UnknownLevelError) Error() string {
	return fmt.Sprintf("Unknown level: %s", self.levelStr)
}
<|endoftext|>


<commit_before>package validate

import (
	"github.com/mbict/go-errors"
	"github.com/mbict/go-tags"
	"reflect"
	"sync"
	"unicode"
)

// Validator interface
type Validator interface {
	SetTag(tag string)
	WithTag(tag string) Validator
	SetValidationFunc(name string, vf ValidatorFunc) error
	SetNameResolver(resolver NameResolverFunc)
	ValidateAll(v interface{}) error
	Validate(v interface{}) error
	ValidAll(val interface{}, tags string) error
	Valid(val interface{}, tags string) error
}

// validatorTag represents one of the validatorTag items
type validatorTag struct {
	tags.Param               // name of the validator and the arguments to send to the validator func
	Fn         ValidatorFunc // validation function to call
}

// ValidateInterface describes the interface a structure can embed to enable custom validation of the structure
type ValidateInterface interface {
	Validate() error
}

// ValidatorFunc is a function that receives the value of a
// field and the parameters used for the respective validation validatorTag.
type ValidatorFunc func(v interface{}, params []string) error

// validator implements the Validator interface
type validator struct {
	tagName         string                   // structure validatorTag name being used (`validate`)
	validationFuncs map[string]ValidatorFunc // validator functions map indexed by name
	structRules     structRules              // structure rules cache
	mu              sync.RWMutex             // rw mutex for structure rules cache
	nameResolver    NameResolverFunc         // func to extract the name to use for field error
}

// Helper validator so users can use the
// functions directly from the package
var defaultValidator = NewValidator()

type Option func(Validator)

func NameResolverOption(resolver NameResolverFunc) Option {
	return func(v Validator) {
		v.SetNameResolver(resolver)
	}
}

func TagOption(tag string) Option {
	return func(v Validator) {
		v.SetTag(tag)
	}
}

func ValidatorOption(name string, validatorFunc ValidatorFunc) Option {
	return func(v Validator) {
		v.SetValidationFunc(name, validatorFunc)
	}
}

// NewValidator creates a new Validator
func NewValidator(options ...Option) Validator {
	v := &validator{
		tagName: "validate",
		validationFuncs: map[string]ValidatorFunc{
			"omitempty":      omitempty,
			"required":       required,
			"not_empty":      notEmpty,
			"len":            length,
			"min":            min,
			"max":            max,
			"between":        between,
			"around":         around,
			"in":             include,
			"exclude":        exclude,
			"regexp":         regex,
			"url":            url,
			"email":          email,
			"numeric":        numeric,
			"number":         number,
			"identifier":     identifier,
			"alpha_dash":     alphaDash,
			"alpha_dash_dot": alphaDashDot,
			"alpha":          alpha,
			"alphanumeric":   alphaNumeric,
			"uuid":           uuid,
			"uuid3":          uuid3,
			"uuid4":          uuid4,
			"uuid5":          uuid5,
			"base64":         base64,
			"enum":           enum,
		},
		structRules:  make(structRules),
		nameResolver: DefaultNameResolver,
	}

	for _, option := range options {
		option(v)
	}

	return v
}

// SetTag allows you to change the validatorTag name used in structs for the default validator
func SetTag(tag string) {
	defaultValidator.SetTag(tag)
}

// WithTag creates a new Validator with the new validatorTag name. It will leave
// the defaultValidator untouched
func WithTag(tag string) Validator {
	return defaultValidator.WithTag(tag)
}

// SetValidationFunc sets the function to be used for a given validation constraint.
// Calling this function with nil validatorFunction (vf) is the same as removing
// the constraint function from the list. The function will be added to the default
// validator
func SetValidationFunc(name string, vf ValidatorFunc) error {
	return defaultValidator.SetValidationFunc(name, vf)
}

// Validate validates the fields of a struct based  on 'validator' tags and returns
// the first validation error found per field name.
func Validate(v interface{}) error {
	return defaultValidator.Validate(v)
}

// ValidateAll validates the fields of a struct based  on 'validator' tags and returns
// errors found indexed by the field name.
func ValidateAll(v interface{}) error {
	return defaultValidator.ValidateAll(v)
}

// Valid validates a value based on the provided tags and returns the first validation error found or nil.
func Valid(val interface{}, tags string) error {
	return defaultValidator.Valid(val, tags)
}

// ValidAll validates a value based on the provided tags and returns errors found or nil.
func ValidAll(val interface{}, tags string) error {
	return defaultValidator.ValidAll(val, tags)
}

// SetNameResolver allows you to change the way field names are resolved
func (mv *validator) SetNameResolver(resolver NameResolverFunc) {
	mv.nameResolver = resolver
	mv.resetCache()
}

// SetTag allows you to change the validatorTag name used in structs
func (mv *validator) SetTag(tag string) {
	mv.tagName = tag
	mv.resetCache()
}

// WithTag creates a new Validator based on the current validator with the new validatorTag name.
func (mv *validator) WithTag(tag string) Validator {
	v := mv.copy()
	v.SetTag(tag)
	return v
}

// copy creates a duplicate of the current validator and returns the new instance
func (mv *validator) copy() Validator {
	return &validator{
		tagName:         mv.tagName,
		validationFuncs: mv.validationFuncs,
		structRules:     mv.structRules,
		nameResolver:    mv.nameResolver,
	}
}

// SetValidationFunc sets the function to be used for a given validation constraint.
// Calling this function with nil validatorFunction (vf) is the same as removing
// the constraint function from the list.
func (mv *validator) SetValidationFunc(name string, vf ValidatorFunc) error {
	if name == "" {
		return errors.New("name cannot be empty")
	}
	if vf == nil {
		delete(mv.validationFuncs, name)
		return nil
	}
	mv.validationFuncs[name] = vf
	return nil
}

// Validate validates the fields of a struct based on 'validator' tags and returns
// the first valiadtion errors found indexed per field name.
func (mv *validator) Validate(v interface{}) error {
	return mv.validate(v, true)
}

// ValidateAll validates the fields of a struct based on 'validator' tags and returns
// errors found indexed by the field name.
func (mv *validator) ValidateAll(v interface{}) error {
	return mv.validate(v, false)
}

func (mv *validator) validate(v interface{}, stopOnError bool) error {
	sv := reflect.ValueOf(v)

	//nil pointer not type found
	if sv.Kind() == reflect.Invalid {
		return ErrUnsupported
	}

	if sv.Kind() == reflect.Ptr && !sv.IsNil() {
		return mv.validate(sv.Elem().Interface(), stopOnError)
	}

	if sv.Kind() != reflect.Struct {
		return ErrUnsupported
	}

	mv.mu.RLock()
	rules, ok := mv.structRules[sv.Type()]
	mv.mu.RUnlock()
	if !ok {
		mv.mu.Lock()
		defer mv.mu.Unlock()
		r, err := mv.parseStruct(sv.Type())
		if err != nil {
			return err
		}
		mv.structRules[sv.Type()] = r
		rules = r
	}

	if errs := rules.Validate(sv, stopOnError); len(errs) > 0 {
		return errs
	}
	return nil
}

// Valid validates a value based on the provided tags and returns the first validation error found or nil.
func (mv *validator) Valid(val interface{}, tags string) error {
	if tags == "-" {
		return nil
	}
	v := reflect.ValueOf(val)
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		return mv.Valid(v.Elem().Interface(), tags)
	}

	if v.Kind() == reflect.Invalid {
		return mv.validateVar(nil, tags, true)
	}
	return mv.validateVar(val, tags, true)
}

// ValidAll validates a value based on the provided tags and returns errors found or nil.
func (mv *validator) ValidAll(val interface{}, tags string) error {
	if tags == "-" {
		return nil
	}
	v := reflect.ValueOf(val)
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		return mv.ValidAll(v.Elem().Interface(), tags)
	}

	if v.Kind() == reflect.Invalid {
		return mv.validateVar(nil, tags, false)
	}
	return mv.validateVar(val, tags, false)
}

func (mv *validator) resetCache() {
	mv.mu.Lock()
	defer mv.mu.Unlock()
	mv.structRules = make(structRules, 0)
}

// validateVar validates a single variable
func (mv *validator) validateVar(v interface{}, tag string, stopOnError bool) error {
	tags, err := mv.parseTags(tag)
	if err != nil {
		// unknown validatorTag found.
		return err
	}
	var errs ErrorList
	for _, t := range tags {
		if err := t.Fn(v, t.Args); err != nil {
			if err == errOmitEmpty {
				return nil
			}
			errs = append(errs, err)

			if stopOnError == true {
				return errs
			}
		}
	}
	return errs
}

// parseTags parses all individual tags found within a struct validatorTag and
// resolve the validator function
func (mv *validator) parseTags(t string) ([]validatorTag, error) {
	params, err := tags.Parse(t)
	if err != nil {
		return nil, ErrSyntax
	}

	tags := make([]validatorTag, 0, len(params))
	for _, param := range params {
		validatorFunc, found := mv.validationFuncs[param.Name]
		if !found {
			return nil, ErrUnknownTag
		}

		tags = append(tags, validatorTag{
			Param: param,
			Fn:    validatorFunc,
		})
	}
	return tags, nil
}

// parseStruct will extract all the validation rules from the given structure
func (mv *validator) parseStruct(t reflect.Type) (rules, error) {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	if t.Kind() != reflect.Struct {
		return nil, ErrUnsupported
	}

	rules := rules{}
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		tag := sf.Tag.Get(mv.tagName)

		if tag == "-" {
			continue
		}

		fieldName := mv.nameResolver(sf)
		if !unicode.IsUpper(rune(fieldName[0])) {
			continue
		}

		rule := rule{
			Name:       fieldName,
			FieldIndex: i,
			IsSlice:    false,
			IsStruct:   false,
		}

		if tag != "" {
			//extract the validator properties
			validatorTags, err := mv.parseTags(tag)
			if err != nil {
				// unknown validatorTag found.
				return nil, err
			}

			//Add validatorTags to rules
			rule.Validators = validatorTags

		}

		st := sf.Type
		if st.Kind() == reflect.Slice {
			rule.IsSlice = true
			st = st.Elem()
		}

		if st.Kind() == reflect.Ptr {
			st = st.Elem()
		}

		if st.Kind() == reflect.Struct {
			subset, ok := mv.structRules[st]
			if !ok {
				var err error
				subset, err = mv.parseStruct(st)
				if err != nil {
					return nil, err
				}
				mv.structRules[st] = subset
			}
			rule.IsStruct = true
			rule.Subset = subset
		}

		rules = append(rules, rule)
	}

	return rules, nil
}
<commit_msg>fix detection of exported fields (#3)<commit_after>package validate

import (
	"github.com/mbict/go-errors"
	"github.com/mbict/go-tags"
	"reflect"
	"sync"
	"unicode"
)

// Validator interface
type Validator interface {
	SetTag(tag string)
	WithTag(tag string) Validator
	SetValidationFunc(name string, vf ValidatorFunc) error
	SetNameResolver(resolver NameResolverFunc)
	ValidateAll(v interface{}) error
	Validate(v interface{}) error
	ValidAll(val interface{}, tags string) error
	Valid(val interface{}, tags string) error
}

// validatorTag represents one of the validatorTag items
type validatorTag struct {
	tags.Param               // name of the validator and the arguments to send to the validator func
	Fn         ValidatorFunc // validation function to call
}

// ValidateInterface describes the interface a structure can embed to enable custom validation of the structure
type ValidateInterface interface {
	Validate() error
}

// ValidatorFunc is a function that receives the value of a
// field and the parameters used for the respective validation validatorTag.
type ValidatorFunc func(v interface{}, params []string) error

// validator implements the Validator interface
type validator struct {
	tagName         string                   // structure validatorTag name being used (`validate`)
	validationFuncs map[string]ValidatorFunc // validator functions map indexed by name
	structRules     structRules              // structure rules cache
	mu              sync.RWMutex             // rw mutex for structure rules cache
	nameResolver    NameResolverFunc         // func to extract the name to use for field error
}

// Helper validator so users can use the
// functions directly from the package
var defaultValidator = NewValidator()

type Option func(Validator)

func NameResolverOption(resolver NameResolverFunc) Option {
	return func(v Validator) {
		v.SetNameResolver(resolver)
	}
}

func TagOption(tag string) Option {
	return func(v Validator) {
		v.SetTag(tag)
	}
}

func ValidatorOption(name string, validatorFunc ValidatorFunc) Option {
	return func(v Validator) {
		v.SetValidationFunc(name, validatorFunc)
	}
}

// NewValidator creates a new Validator
func NewValidator(options ...Option) Validator {
	v := &validator{
		tagName: "validate",
		validationFuncs: map[string]ValidatorFunc{
			"omitempty":      omitempty,
			"required":       required,
			"not_empty":      notEmpty,
			"len":            length,
			"min":            min,
			"max":            max,
			"between":        between,
			"around":         around,
			"in":             include,
			"exclude":        exclude,
			"regexp":         regex,
			"url":            url,
			"email":          email,
			"numeric":        numeric,
			"number":         number,
			"identifier":     identifier,
			"alpha_dash":     alphaDash,
			"alpha_dash_dot": alphaDashDot,
			"alpha":          alpha,
			"alphanumeric":   alphaNumeric,
			"uuid":           uuid,
			"uuid3":          uuid3,
			"uuid4":          uuid4,
			"uuid5":          uuid5,
			"base64":         base64,
			"enum":           enum,
		},
		structRules:  make(structRules),
		nameResolver: DefaultNameResolver,
	}

	for _, option := range options {
		option(v)
	}

	return v
}

// SetTag allows you to change the validatorTag name used in structs for the default validator
func SetTag(tag string) {
	defaultValidator.SetTag(tag)
}

// WithTag creates a new Validator with the new validatorTag name. It will leave
// the defaultValidator untouched
func WithTag(tag string) Validator {
	return defaultValidator.WithTag(tag)
}

// SetValidationFunc sets the function to be used for a given validation constraint.
// Calling this function with nil validatorFunction (vf) is the same as removing
// the constraint function from the list. The function will be added to the default
// validator
func SetValidationFunc(name string, vf ValidatorFunc) error {
	return defaultValidator.SetValidationFunc(name, vf)
}

// Validate validates the fields of a struct based  on 'validator' tags and returns
// the first validation error found per field name.
func Validate(v interface{}) error {
	return defaultValidator.Validate(v)
}

// ValidateAll validates the fields of a struct based  on 'validator' tags and returns
// errors found indexed by the field name.
func ValidateAll(v interface{}) error {
	return defaultValidator.ValidateAll(v)
}

// Valid validates a value based on the provided tags and returns the first validation error found or nil.
func Valid(val interface{}, tags string) error {
	return defaultValidator.Valid(val, tags)
}

// ValidAll validates a value based on the provided tags and returns errors found or nil.
func ValidAll(val interface{}, tags string) error {
	return defaultValidator.ValidAll(val, tags)
}

// SetNameResolver allows you to change the way field names are resolved
func (mv *validator) SetNameResolver(resolver NameResolverFunc) {
	mv.nameResolver = resolver
	mv.resetCache()
}

// SetTag allows you to change the validatorTag name used in structs
func (mv *validator) SetTag(tag string) {
	mv.tagName = tag
	mv.resetCache()
}

// WithTag creates a new Validator based on the current validator with the new validatorTag name.
func (mv *validator) WithTag(tag string) Validator {
	v := mv.copy()
	v.SetTag(tag)
	return v
}

// copy creates a duplicate of the current validator and returns the new instance
func (mv *validator) copy() Validator {
	return &validator{
		tagName:         mv.tagName,
		validationFuncs: mv.validationFuncs,
		structRules:     mv.structRules,
		nameResolver:    mv.nameResolver,
	}
}

// SetValidationFunc sets the function to be used for a given validation constraint.
// Calling this function with nil validatorFunction (vf) is the same as removing
// the constraint function from the list.
func (mv *validator) SetValidationFunc(name string, vf ValidatorFunc) error {
	if name == "" {
		return errors.New("name cannot be empty")
	}
	if vf == nil {
		delete(mv.validationFuncs, name)
		return nil
	}
	mv.validationFuncs[name] = vf
	return nil
}

// Validate validates the fields of a struct based on 'validator' tags and returns
// the first valiadtion errors found indexed per field name.
func (mv *validator) Validate(v interface{}) error {
	return mv.validate(v, true)
}

// ValidateAll validates the fields of a struct based on 'validator' tags and returns
// errors found indexed by the field name.
func (mv *validator) ValidateAll(v interface{}) error {
	return mv.validate(v, false)
}

func (mv *validator) validate(v interface{}, stopOnError bool) error {
	sv := reflect.ValueOf(v)

	//nil pointer not type found
	if sv.Kind() == reflect.Invalid {
		return ErrUnsupported
	}

	if sv.Kind() == reflect.Ptr && !sv.IsNil() {
		return mv.validate(sv.Elem().Interface(), stopOnError)
	}

	if sv.Kind() != reflect.Struct {
		return ErrUnsupported
	}

	mv.mu.RLock()
	rules, ok := mv.structRules[sv.Type()]
	mv.mu.RUnlock()
	if !ok {
		mv.mu.Lock()
		defer mv.mu.Unlock()
		r, err := mv.parseStruct(sv.Type())
		if err != nil {
			return err
		}
		mv.structRules[sv.Type()] = r
		rules = r
	}

	if errs := rules.Validate(sv, stopOnError); len(errs) > 0 {
		return errs
	}
	return nil
}

// Valid validates a value based on the provided tags and returns the first validation error found or nil.
func (mv *validator) Valid(val interface{}, tags string) error {
	if tags == "-" {
		return nil
	}
	v := reflect.ValueOf(val)
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		return mv.Valid(v.Elem().Interface(), tags)
	}

	if v.Kind() == reflect.Invalid {
		return mv.validateVar(nil, tags, true)
	}
	return mv.validateVar(val, tags, true)
}

// ValidAll validates a value based on the provided tags and returns errors found or nil.
func (mv *validator) ValidAll(val interface{}, tags string) error {
	if tags == "-" {
		return nil
	}
	v := reflect.ValueOf(val)
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		return mv.ValidAll(v.Elem().Interface(), tags)
	}

	if v.Kind() == reflect.Invalid {
		return mv.validateVar(nil, tags, false)
	}
	return mv.validateVar(val, tags, false)
}

func (mv *validator) resetCache() {
	mv.mu.Lock()
	defer mv.mu.Unlock()
	mv.structRules = make(structRules, 0)
}

// validateVar validates a single variable
func (mv *validator) validateVar(v interface{}, tag string, stopOnError bool) error {
	tags, err := mv.parseTags(tag)
	if err != nil {
		// unknown validatorTag found.
		return err
	}
	var errs ErrorList
	for _, t := range tags {
		if err := t.Fn(v, t.Args); err != nil {
			if err == errOmitEmpty {
				return nil
			}
			errs = append(errs, err)

			if stopOnError == true {
				return errs
			}
		}
	}
	return errs
}

// parseTags parses all individual tags found within a struct validatorTag and
// resolve the validator function
func (mv *validator) parseTags(t string) ([]validatorTag, error) {
	params, err := tags.Parse(t)
	if err != nil {
		return nil, ErrSyntax
	}

	tags := make([]validatorTag, 0, len(params))
	for _, param := range params {
		validatorFunc, found := mv.validationFuncs[param.Name]
		if !found {
			return nil, ErrUnknownTag
		}

		tags = append(tags, validatorTag{
			Param: param,
			Fn:    validatorFunc,
		})
	}
	return tags, nil
}

// parseStruct will extract all the validation rules from the given structure
func (mv *validator) parseStruct(t reflect.Type) (rules, error) {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	if t.Kind() != reflect.Struct {
		return nil, ErrUnsupported
	}

	rules := rules{}
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		tag := sf.Tag.Get(mv.tagName)

		if tag == "-" {
			continue
		}

		if !unicode.IsUpper(rune(sf.Name[0])) {
			continue
		}

		fieldName := mv.nameResolver(sf)
		rule := rule{
			Name:       fieldName,
			FieldIndex: i,
			IsSlice:    false,
			IsStruct:   false,
		}

		if tag != "" {
			//extract the validator properties
			validatorTags, err := mv.parseTags(tag)
			if err != nil {
				// unknown validatorTag found.
				return nil, err
			}

			//Add validatorTags to rules
			rule.Validators = validatorTags

		}

		st := sf.Type
		if st.Kind() == reflect.Slice {
			rule.IsSlice = true
			st = st.Elem()
		}

		if st.Kind() == reflect.Ptr {
			st = st.Elem()
		}

		if st.Kind() == reflect.Struct {
			subset, ok := mv.structRules[st]
			if !ok {
				var err error
				subset, err = mv.parseStruct(st)
				if err != nil {
					return nil, err
				}
				mv.structRules[st] = subset
			}
			rule.IsStruct = true
			rule.Subset = subset
		}

		rules = append(rules, rule)
	}

	return rules, nil
}
<|endoftext|>


<commit_before>package dht

import (
	"bytes"
	"testing"

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

	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	inet "github.com/jbenet/go-ipfs/net"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"

	"fmt"
	"time"
)

func setupDHT(t *testing.T, p *peer.Peer) *IpfsDHT {
	ctx := context.Background()

	peerstore := peer.NewPeerstore()

	dhts := netservice.NewService(nil) // nil handler for now, need to patch it
	if err := dhts.Start(ctx); err != nil {
		t.Fatal(err)
	}

	net, err := inet.NewIpfsNetwork(ctx, p, &mux.ProtocolMap{
		mux.ProtocolID_Routing: dhts,
	})
	if err != nil {
		t.Fatal(err)
	}

	d := NewDHT(p, peerstore, net, dhts, ds.NewMapDatastore())
	dhts.Handler = d
	return d
}

func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) {
	var addrs []*ma.Multiaddr
	for i := 0; i < n; i++ {
		a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
		if err != nil {
			t.Fatal(err)
		}
		addrs = append(addrs, a)
	}

	var peers []*peer.Peer
	for i := 0; i < n; i++ {
		p := makePeer(addrs[i])
		peers = append(peers, p)
	}

	dhts := make([]*IpfsDHT, n)
	for i := 0; i < n; i++ {
		dhts[i] = setupDHT(t, peers[i])
	}

	return addrs, peers, dhts
}

func makePeer(addr *ma.Multiaddr) *peer.Peer {
	p := new(peer.Peer)
	p.AddAddress(addr)
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		panic(err)
	}
	p.PrivKey = sk
	p.PubKey = pk
	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		panic(err)
	}

	p.ID = id
	return p
}

func TestPing(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5678")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	//Test that we can ping the node
	ctx, _ := context.WithTimeout(context.Background(), 5*time.Millisecond)
	err = dhtA.Ping(ctx, peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctx, _ = context.WithTimeout(context.Background(), 5*time.Millisecond)
	err = dhtB.Ping(ctx, peerA)
	if err != nil {
		t.Fatal(err)
	}
}

func TestValueGetSet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1235")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5679")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	dhtA.PutValue(ctxT, "hello", []byte("world"))

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err := dhtA.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err = dhtB.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}
}

func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	provs, err := dhts[0].FindProviders(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if len(provs) != 1 {
		t.Fatal("Didnt get back providers")
	}
}

func TestProvidesAsync(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctx, u.Key("hello"), 5)
	select {
	case p := <-provs:
		if !p.ID.Equal(dhts[3].self.ID) {
			t.Fatalf("got a provider, but not the right one. %v", p.ID.Pretty())
		}
	case <-ctx.Done():
		t.Fatal("Didnt get back providers")
	}
}

func TestLayeredGet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatalf("Failed to connect: %s", err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	val, err := dhts[0].GetValue(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	p, err := dhts[0].FindPeer(ctxT, peers[2].ID)
	if err != nil {
		t.Fatal(err)
	}

	if p == nil {
		t.Fatal("Failed to find peer.")
	}

	if !p.ID.Equal(peers[2].ID) {
		t.Fatal("Didnt find expected peer.")
	}
}
<commit_msg>update net with peerstore<commit_after>package dht

import (
	"bytes"
	"testing"

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

	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	inet "github.com/jbenet/go-ipfs/net"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"

	"fmt"
	"time"
)

func setupDHT(t *testing.T, p *peer.Peer) *IpfsDHT {
	ctx := context.Background()

	peerstore := peer.NewPeerstore()

	dhts := netservice.NewService(nil) // nil handler for now, need to patch it
	if err := dhts.Start(ctx); err != nil {
		t.Fatal(err)
	}

	net, err := inet.NewIpfsNetwork(ctx, p, peerstore, &mux.ProtocolMap{
		mux.ProtocolID_Routing: dhts,
	})
	if err != nil {
		t.Fatal(err)
	}

	d := NewDHT(p, peerstore, net, dhts, ds.NewMapDatastore())
	dhts.Handler = d
	return d
}

func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) {
	var addrs []*ma.Multiaddr
	for i := 0; i < n; i++ {
		a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
		if err != nil {
			t.Fatal(err)
		}
		addrs = append(addrs, a)
	}

	var peers []*peer.Peer
	for i := 0; i < n; i++ {
		p := makePeer(addrs[i])
		peers = append(peers, p)
	}

	dhts := make([]*IpfsDHT, n)
	for i := 0; i < n; i++ {
		dhts[i] = setupDHT(t, peers[i])
	}

	return addrs, peers, dhts
}

func makePeer(addr *ma.Multiaddr) *peer.Peer {
	p := new(peer.Peer)
	p.AddAddress(addr)
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		panic(err)
	}
	p.PrivKey = sk
	p.PubKey = pk
	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		panic(err)
	}

	p.ID = id
	return p
}

func TestPing(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5678")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	//Test that we can ping the node
	ctx, _ := context.WithTimeout(context.Background(), 5*time.Millisecond)
	err = dhtA.Ping(ctx, peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctx, _ = context.WithTimeout(context.Background(), 5*time.Millisecond)
	err = dhtB.Ping(ctx, peerA)
	if err != nil {
		t.Fatal(err)
	}
}

func TestValueGetSet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1235")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5679")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	dhtA.PutValue(ctxT, "hello", []byte("world"))

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err := dhtA.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err = dhtB.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}
}

func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	provs, err := dhts[0].FindProviders(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if len(provs) != 1 {
		t.Fatal("Didnt get back providers")
	}
}

func TestProvidesAsync(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctx, u.Key("hello"), 5)
	select {
	case p := <-provs:
		if !p.ID.Equal(dhts[3].self.ID) {
			t.Fatalf("got a provider, but not the right one. %v", p.ID.Pretty())
		}
	case <-ctx.Done():
		t.Fatal("Didnt get back providers")
	}
}

func TestLayeredGet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatalf("Failed to connect: %s", err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	val, err := dhts[0].GetValue(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	p, err := dhts[0].FindPeer(ctxT, peers[2].ID)
	if err != nil {
		t.Fatal(err)
	}

	if p == nil {
		t.Fatal("Failed to find peer.")
	}

	if !p.ID.Equal(peers[2].ID) {
		t.Fatal("Didnt find expected peer.")
	}
}
<|endoftext|>


<commit_before>package dht

import (
	"bytes"
	"testing"

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

	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	inet "github.com/jbenet/go-ipfs/net"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"

	"fmt"
	"time"
)

func setupDHT(t *testing.T, p *peer.Peer) *IpfsDHT {
	ctx := context.Background()

	peerstore := peer.NewPeerstore()

	dhts := netservice.NewService(nil) // nil handler for now, need to patch it
	if err := dhts.Start(ctx); err != nil {
		t.Fatal(err)
	}

	net, err := inet.NewIpfsNetwork(ctx, p, &mux.ProtocolMap{
		mux.ProtocolID_Routing: dhts,
	})
	if err != nil {
		t.Fatal(err)
	}

	d := NewDHT(p, peerstore, net, dhts, ds.NewMapDatastore())
	dhts.Handler = d
	return d
}

func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) {
	var addrs []*ma.Multiaddr
	for i := 0; i < n; i++ {
		a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
		if err != nil {
			t.Fatal(err)
		}
		addrs = append(addrs, a)
	}

	var peers []*peer.Peer
	for i := 0; i < n; i++ {
		p := makePeer(addrs[i])
		peers = append(peers, p)
	}

	dhts := make([]*IpfsDHT, n)
	for i := 0; i < n; i++ {
		dhts[i] = setupDHT(t, peers[i])
	}

	return addrs, peers, dhts
}

func makePeer(addr *ma.Multiaddr) *peer.Peer {
	p := new(peer.Peer)
	p.AddAddress(addr)
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		panic(err)
	}
	p.PrivKey = sk
	p.PubKey = pk
	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		panic(err)
	}

	p.ID = id
	return p
}

func TestPing(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5678")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(peerB)
	if err != nil {
		t.Fatal(err)
	}

	//Test that we can ping the node
	err = dhtA.Ping(peerB, time.Second*2)
	if err != nil {
		t.Fatal(err)
	}
}

func TestValueGetSet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1235")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5679")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	dhtA.PutValue(ctxT, "hello", []byte("world"))

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err := dhtA.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

}

func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	provs, err := dhts[0].FindProviders(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if len(provs) != 1 {
		t.Fatal("Didnt get back providers")
	}
}

func TestProvidesAsync(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctx, u.Key("hello"), 5)
	select {
	case p := <-provs:
		if !p.ID.Equal(dhts[3].self.ID) {
			t.Fatalf("got a provider, but not the right one. %v", p.ID.Pretty())
		}
	case <-ctx.Done():
		t.Fatal("Didnt get back providers")
	}
}

func TestLayeredGet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(peers[1])
	if err != nil {
		t.Fatalf("Failed to connect: %s", err)
	}

	_, err = dhts[1].Connect(peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].Provide(u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	val, err := dhts[0].GetValue(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(peers[3])
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	p, err := dhts[0].FindPeer(ctxT, peers[2].ID)
	if err != nil {
		t.Fatal(err)
	}

	if p == nil {
		t.Fatal("Failed to find peer.")
	}

	if !p.ID.Equal(peers[2].ID) {
		t.Fatal("Didnt find expected peer.")
	}
}
<commit_msg>fix(routing:dht) add ctx args<commit_after>package dht

import (
	"bytes"
	"testing"

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

	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

	ci "github.com/jbenet/go-ipfs/crypto"
	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	inet "github.com/jbenet/go-ipfs/net"
	mux "github.com/jbenet/go-ipfs/net/mux"
	netservice "github.com/jbenet/go-ipfs/net/service"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"

	"fmt"
	"time"
)

func setupDHT(t *testing.T, p *peer.Peer) *IpfsDHT {
	ctx := context.Background()

	peerstore := peer.NewPeerstore()

	dhts := netservice.NewService(nil) // nil handler for now, need to patch it
	if err := dhts.Start(ctx); err != nil {
		t.Fatal(err)
	}

	net, err := inet.NewIpfsNetwork(ctx, p, &mux.ProtocolMap{
		mux.ProtocolID_Routing: dhts,
	})
	if err != nil {
		t.Fatal(err)
	}

	d := NewDHT(p, peerstore, net, dhts, ds.NewMapDatastore())
	dhts.Handler = d
	return d
}

func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) {
	var addrs []*ma.Multiaddr
	for i := 0; i < n; i++ {
		a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5000+i))
		if err != nil {
			t.Fatal(err)
		}
		addrs = append(addrs, a)
	}

	var peers []*peer.Peer
	for i := 0; i < n; i++ {
		p := makePeer(addrs[i])
		peers = append(peers, p)
	}

	dhts := make([]*IpfsDHT, n)
	for i := 0; i < n; i++ {
		dhts[i] = setupDHT(t, peers[i])
	}

	return addrs, peers, dhts
}

func makePeer(addr *ma.Multiaddr) *peer.Peer {
	p := new(peer.Peer)
	p.AddAddress(addr)
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		panic(err)
	}
	p.PrivKey = sk
	p.PubKey = pk
	id, err := spipe.IDFromPubKey(pk)
	if err != nil {
		panic(err)
	}

	p.ID = id
	return p
}

func TestPing(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/2222")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5678")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	//Test that we can ping the node
	ctx, _ := context.WithTimeout(context.Background(), 2*time.Millisecond)
	err = dhtA.Ping(ctx, peerB)
	if err != nil {
		t.Fatal(err)
	}
}

func TestValueGetSet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	addrA, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1235")
	if err != nil {
		t.Fatal(err)
	}
	addrB, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/5679")
	if err != nil {
		t.Fatal(err)
	}

	peerA := makePeer(addrA)
	peerB := makePeer(addrB)

	dhtA := setupDHT(t, peerA)
	dhtB := setupDHT(t, peerB)

	defer dhtA.Halt()
	defer dhtB.Halt()
	defer dhtA.network.Close()
	defer dhtB.network.Close()

	_, err = dhtA.Connect(context.Background(), peerB)
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	dhtA.PutValue(ctxT, "hello", []byte("world"))

	ctxT, _ = context.WithTimeout(context.Background(), time.Second*2)
	val, err := dhtA.GetValue(ctxT, "hello")
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

}

func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	provs, err := dhts[0].FindProviders(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if len(provs) != 1 {
		t.Fatal("Didnt get back providers")
	}
}

func TestProvidesAsync(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctx, u.Key("hello"), 5)
	select {
	case p := <-provs:
		if !p.ID.Equal(dhts[3].self.ID) {
			t.Fatalf("got a provider, but not the right one. %v", p.ID.Pretty())
		}
	case <-ctx.Done():
		t.Fatal("Didnt get back providers")
	}
}

func TestLayeredGet(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false
	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			defer dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatalf("Failed to connect: %s", err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(u.Key("hello"), []byte("world"))
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].Provide(context.Background(), u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	val, err := dhts[0].GetValue(ctxT, u.Key("hello"))
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
	// t.Skip("skipping test to debug another")

	u.Debug = false

	_, peers, dhts := setupDHTS(4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Halt()
			dhts[i].network.Close()
		}
	}()

	_, err := dhts[0].Connect(context.Background(), peers[1])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[2])
	if err != nil {
		t.Fatal(err)
	}

	_, err = dhts[1].Connect(context.Background(), peers[3])
	if err != nil {
		t.Fatal(err)
	}

	ctxT, _ := context.WithTimeout(context.Background(), time.Second)
	p, err := dhts[0].FindPeer(ctxT, peers[2].ID)
	if err != nil {
		t.Fatal(err)
	}

	if p == nil {
		t.Fatal("Failed to find peer.")
	}

	if !p.ID.Equal(peers[2].ID) {
		t.Fatal("Didnt find expected peer.")
	}
}
<|endoftext|>