<commit_before>package admin

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path"
	"reflect"
	"strings"
	"text/template"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

type Context struct {
	*qor.Context
	*Searcher
	Resource    *Resource
	Admin       *Admin
	CurrentUser qor.CurrentUser
	Result      interface{}
	Content     string
}

// Resource
func (context *Context) ResourcePath() string {
	if context.Resource == nil {
		return ""
	}
	return context.Resource.ToParam()
}

func (context *Context) SetResource(res *Resource) *Context {
	context.Resource = res
	context.Searcher = &Searcher{Context: context}
	return context
}

func (context *Context) NewResource(name ...string) *Context {
	clone := &Context{Context: context.Context, Admin: context.Admin, Result: context.Result}
	if len(name) > 0 {
		clone.SetResource(context.Admin.GetResource(name[0]))
	} else {
		clone.SetResource(context.Resource)
	}
	return clone
}

// Template
func (context *Context) getViewPaths() (paths []string) {
	dirs := []string{context.ResourcePath(), path.Join("themes", "default"), "."}
	if context.Resource != nil && context.Resource.Config != nil && context.Resource.Config.Theme != "" {
		themePath := path.Join("themes", context.Resource.Config.Theme)
		dirs = append([]string{path.Join(themePath, context.ResourcePath()), themePath}, dirs...)
	}

	for _, p := range dirs {
		for _, d := range viewPaths {
			if isExistingDir(path.Join(d, p)) {
				paths = append(paths, path.Join(d, p))
			}
		}
	}
	return paths
}

func (context *Context) findFile(layout string) (string, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			return path.Join(p, layout), nil
		}
	}
	return "", errors.New("file not found")
}

func (context *Context) findTemplate(tmpl *template.Template, layout string) (*template.Template, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			if tmpl, err = tmpl.ParseFiles(path.Join(p, layout)); err != nil {
				fmt.Println(err)
			} else {
				return tmpl, nil
			}
		}
	}
	return tmpl, errors.New("template not found")
}

func (context *Context) Render(name string, results ...interface{}) string {
	var err error
	names := strings.Split(name, "/")
	tmpl := template.New(names[len(names)-1] + ".tmpl").Funcs(context.funcMap())
	if len(results) > 0 {
		context.Result = results[0]
	}

	if tmpl, err = context.findTemplate(tmpl, name+".tmpl"); err == nil {
		var result = bytes.NewBufferString("")
		if err := tmpl.Execute(result, context); err != nil {
			fmt.Println(err)
		}
		return result.String()
	}

	return ""
}

func (context *Context) Execute(name string, result interface{}) {
	var tmpl *template.Template
	var cacheKey string

	if context.Resource != nil {
		cacheKey = path.Join(context.ResourcePath(), name)
	} else {
		cacheKey = name
	}

	if t, ok := templates[cacheKey]; !ok || true {
		var err error
		tmpl = template.New("layout.tmpl").Funcs(context.funcMap())
		if tmpl, err = context.findTemplate(tmpl, "layout.tmpl"); err == nil {
			for _, name := range []string{"header", "footer"} {
				if tmpl.Lookup(name) == nil {
					tmpl, _ = context.findTemplate(tmpl, name+".tmpl")
				}
			}
		}
	} else {
		tmpl = t
	}

	context.Content = context.Render(name, result)
	if err := tmpl.Execute(context.Writer, context); err != nil {
		fmt.Println(err)
	}
}

// Function Maps
func (context *Context) PrimaryKeyOf(value interface{}) interface{} {
	return context.GetDB().NewScope(value).PrimaryKeyValue()
}

func (context *Context) NewRecord(value interface{}) interface{} {
	return context.GetDB().NewRecord(value)
}

func (context *Context) ValueOf(value interface{}, meta *Meta) interface{} {
	return meta.Valuer(value, context.Context)
}

func (context *Context) NewResourcePath(value interface{}) string {
	if res, ok := value.(*Resource); ok {
		return path.Join(context.Admin.router.Prefix, res.ToParam(), "new")
	} else {
		return path.Join(context.Admin.router.Prefix, context.Resource.ToParam(), "new")
	}
}

func (context *Context) UrlFor(value interface{}, resources ...*Resource) string {
	var url string
	if admin, ok := value.(*Admin); ok {
		url = admin.router.Prefix
	} else if res, ok := value.(*Resource); ok {
		url = path.Join(context.Admin.router.Prefix, res.ToParam())
	} else {
		structType := reflect.Indirect(reflect.ValueOf(value)).Type().String()
		res := context.Admin.GetResource(structType)
		primaryKey := context.GetDB().NewScope(value).PrimaryKeyValue()
		url = path.Join(context.Admin.router.Prefix, res.ToParam(), fmt.Sprintf("%v", primaryKey))
	}
	return url
}

func (context *Context) LinkTo(text interface{}, link interface{}) string {
	text = reflect.Indirect(reflect.ValueOf(text)).Interface()
	if linkStr, ok := link.(string); ok {
		return fmt.Sprintf(`<a href="%v">%v</a>`, linkStr, text)
	}
	return fmt.Sprintf(`<a href="%v">%v</a>`, context.UrlFor(link), text)
}

func (context *Context) RenderForm(value interface{}, metas []*Meta) string {
	var result = bytes.NewBufferString("")
	context.renderForm(result, value, metas, []string{"QorResource"})
	return result.String()
}

func (context *Context) renderForm(result *bytes.Buffer, value interface{}, metas []*Meta, prefix []string) {
	for _, meta := range metas {
		context.RenderMeta(result, meta, value, prefix)
	}
}

func (context *Context) RenderMeta(writer *bytes.Buffer, meta *Meta, value interface{}, prefix []string) {
	prefix = append(prefix, meta.Name)

	funcsMap := context.funcMap()
	funcsMap["render_form"] = func(value interface{}, metas []*Meta, index ...int) string {
		var result = bytes.NewBufferString("")
		newPrefix := append([]string{}, prefix...)

		if len(index) > 0 {
			last := newPrefix[len(newPrefix)-1]
			newPrefix = append(newPrefix[:len(newPrefix)-1], fmt.Sprintf("%v[%v]", last, index[0]))
		}

		context.renderForm(result, value, metas, newPrefix)
		return result.String()
	}

	var tmpl = template.New(meta.Type + ".tmpl").Funcs(funcsMap)

	if tmpl, err := context.findTemplate(tmpl, fmt.Sprintf("forms/%v.tmpl", meta.Type)); err == nil {
		data := map[string]interface{}{}
		data["InputId"] = strings.Join(prefix, "")
		data["Label"] = meta.Label
		data["InputName"] = strings.Join(prefix, ".")
		data["Value"] = meta.Valuer(value, context.Context)
		if meta.GetCollection != nil {
			data["CollectionValue"] = meta.GetCollection(value, context.Context)
		}
		data["Meta"] = meta

		if err := tmpl.Execute(writer, data); err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Printf("%v: form type %v not supported\n", meta.Name, meta.Type)
	}
}

func (context *Context) HasPrimaryKey(value interface{}, primaryKey interface{}) bool {
	primaryKeys := []interface{}{}
	reflectValue := reflect.ValueOf(value)
	if reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	if reflectValue.Kind() == reflect.Slice {
		for i := 0; i < reflectValue.Len(); i++ {
			scope := &gorm.Scope{Value: reflectValue.Index(i).Interface()}
			primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
		}
	} else if reflectValue.Kind() == reflect.Struct {
		scope := &gorm.Scope{Value: value}
		primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
	}

	for _, key := range primaryKeys {
		if fmt.Sprintf("%v", primaryKey) == fmt.Sprintf("%v", key) {
			return true
		}
	}
	return false
}

func (context *Context) getResource(resources ...*Resource) *Resource {
	for _, res := range resources {
		return res
	}
	return context.Resource
}

func (context *Context) AllMetas(resources ...*Resource) []*Meta {
	return context.getResource(resources...).AllMetas()
}

func (context *Context) IndexMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.IndexMetas(), context, roles.Read)
}

func (context *Context) EditMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.EditMetas(), context, roles.Update)
}

func (context *Context) ShowMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.ShowMetas(), context, roles.Read)
}

func (context *Context) NewMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.NewMetas(), context, roles.Create)
}

func (context *Context) JavaScriptTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "javascripts", name+".js")
	return fmt.Sprintf(`<script src="%s"></script>`, name)
}

func (context *Context) StyleSheetTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "stylesheets", name+".css")
	return fmt.Sprintf(`<link type="text/css" rel="stylesheet" href="%s">`, name)
}

type Page struct {
	Page       int
	Current    bool
	IsPrevious bool
	IsNext     bool
}

func (context *Context) Pagination() []Page {
	pagination := context.Searcher.Pagination
	start := pagination.CurrentPage
	if start-5 < 1 {
		start = 1
	}

	end := start + 9
	if end > pagination.Pages {
		end = pagination.Pages
	}

	var pages []Page
	if start > 1 {
		pages = append(pages, Page{Page: start - 1, IsPrevious: true})
	}

	for i := start; i <= end; i++ {
		pages = append(pages, Page{Page: i, Current: pagination.CurrentPage == i})
	}

	if end < pagination.Pages {
		pages = append(pages, Page{Page: end + 1, IsNext: true})
	}

	return pages
}

func Equal(a, b interface{}) bool {
	return reflect.DeepEqual(a, b)
}

func (context *Context) funcMap() template.FuncMap {
	funcMap := template.FuncMap{
		"menus":             context.Admin.GetMenus,
		"current_user":      func() qor.CurrentUser { return context.CurrentUser },
		"render":            context.Render,
		"render_form":       context.RenderForm,
		"url_for":           context.UrlFor,
		"link_to":           context.LinkTo,
		"new_resource_path": context.NewResourcePath,
		"new_resource":      context.NewResource,
		"is_new_record":     context.NewRecord,
		"value_of":          context.ValueOf,
		"primary_key_of":    context.PrimaryKeyOf,
		"has_primary_key":   context.HasPrimaryKey,
		"all_metas":         context.AllMetas,
		"index_metas":       context.IndexMetas,
		"edit_metas":        context.EditMetas,
		"show_metas":        context.ShowMetas,
		"new_metas":         context.NewMetas,
		"pagination":        context.Pagination,
		"javascript_tag":    context.JavaScriptTag,
		"stylesheet_tag":    context.StyleSheetTag,
		"equal":             Equal,
	}

	for key, value := range context.Admin.funcMaps {
		funcMap[key] = value
	}
	return funcMap
}
<commit_msg>fix render meta value bug<commit_after>package admin

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path"
	"reflect"
	"strings"
	"text/template"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

type Context struct {
	*qor.Context
	*Searcher
	Resource    *Resource
	Admin       *Admin
	CurrentUser qor.CurrentUser
	Result      interface{}
	Content     string
}

// Resource
func (context *Context) ResourcePath() string {
	if context.Resource == nil {
		return ""
	}
	return context.Resource.ToParam()
}

func (context *Context) SetResource(res *Resource) *Context {
	context.Resource = res
	context.Searcher = &Searcher{Context: context}
	return context
}

func (context *Context) NewResource(name ...string) *Context {
	clone := &Context{Context: context.Context, Admin: context.Admin, Result: context.Result}
	if len(name) > 0 {
		clone.SetResource(context.Admin.GetResource(name[0]))
	} else {
		clone.SetResource(context.Resource)
	}
	return clone
}

// Template
func (context *Context) getViewPaths() (paths []string) {
	dirs := []string{context.ResourcePath(), path.Join("themes", "default"), "."}
	if context.Resource != nil && context.Resource.Config != nil && context.Resource.Config.Theme != "" {
		themePath := path.Join("themes", context.Resource.Config.Theme)
		dirs = append([]string{path.Join(themePath, context.ResourcePath()), themePath}, dirs...)
	}

	for _, p := range dirs {
		for _, d := range viewPaths {
			if isExistingDir(path.Join(d, p)) {
				paths = append(paths, path.Join(d, p))
			}
		}
	}
	return paths
}

func (context *Context) findFile(layout string) (string, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			return path.Join(p, layout), nil
		}
	}
	return "", errors.New("file not found")
}

func (context *Context) findTemplate(tmpl *template.Template, layout string) (*template.Template, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			if tmpl, err = tmpl.ParseFiles(path.Join(p, layout)); err != nil {
				fmt.Println(err)
			} else {
				return tmpl, nil
			}
		}
	}
	return tmpl, errors.New("template not found")
}

func (context *Context) Render(name string, results ...interface{}) string {
	var err error
	names := strings.Split(name, "/")
	tmpl := template.New(names[len(names)-1] + ".tmpl").Funcs(context.funcMap())
	if len(results) > 0 {
		context.Result = results[0]
	}

	if tmpl, err = context.findTemplate(tmpl, name+".tmpl"); err == nil {
		var result = bytes.NewBufferString("")
		if err := tmpl.Execute(result, context); err != nil {
			fmt.Println(err)
		}
		return result.String()
	}

	return ""
}

func (context *Context) Execute(name string, result interface{}) {
	var tmpl *template.Template
	var cacheKey string

	if context.Resource != nil {
		cacheKey = path.Join(context.ResourcePath(), name)
	} else {
		cacheKey = name
	}

	if t, ok := templates[cacheKey]; !ok || true {
		var err error
		tmpl = template.New("layout.tmpl").Funcs(context.funcMap())
		if tmpl, err = context.findTemplate(tmpl, "layout.tmpl"); err == nil {
			for _, name := range []string{"header", "footer"} {
				if tmpl.Lookup(name) == nil {
					tmpl, _ = context.findTemplate(tmpl, name+".tmpl")
				}
			}
		}
	} else {
		tmpl = t
	}

	context.Content = context.Render(name, result)
	if err := tmpl.Execute(context.Writer, context); err != nil {
		fmt.Println(err)
	}
}

// Function Maps
func (context *Context) PrimaryKeyOf(value interface{}) interface{} {
	return context.GetDB().NewScope(value).PrimaryKeyValue()
}

func (context *Context) NewRecord(value interface{}) interface{} {
	return context.GetDB().NewRecord(value)
}

func (context *Context) ValueOf(value interface{}, meta *Meta) interface{} {
	return meta.Valuer(value, context.Context)
}

func (context *Context) NewResourcePath(value interface{}) string {
	if res, ok := value.(*Resource); ok {
		return path.Join(context.Admin.router.Prefix, res.ToParam(), "new")
	} else {
		return path.Join(context.Admin.router.Prefix, context.Resource.ToParam(), "new")
	}
}

func (context *Context) UrlFor(value interface{}, resources ...*Resource) string {
	var url string
	if admin, ok := value.(*Admin); ok {
		url = admin.router.Prefix
	} else if res, ok := value.(*Resource); ok {
		url = path.Join(context.Admin.router.Prefix, res.ToParam())
	} else {
		structType := reflect.Indirect(reflect.ValueOf(value)).Type().String()
		res := context.Admin.GetResource(structType)
		primaryKey := context.GetDB().NewScope(value).PrimaryKeyValue()
		url = path.Join(context.Admin.router.Prefix, res.ToParam(), fmt.Sprintf("%v", primaryKey))
	}
	return url
}

func (context *Context) LinkTo(text interface{}, link interface{}) string {
	text = reflect.Indirect(reflect.ValueOf(text)).Interface()
	if linkStr, ok := link.(string); ok {
		return fmt.Sprintf(`<a href="%v">%v</a>`, linkStr, text)
	}
	return fmt.Sprintf(`<a href="%v">%v</a>`, context.UrlFor(link), text)
}

func (context *Context) RenderForm(value interface{}, metas []*Meta) string {
	var result = bytes.NewBufferString("")
	context.renderForm(result, value, metas, []string{"QorResource"})
	return result.String()
}

func (context *Context) renderForm(result *bytes.Buffer, value interface{}, metas []*Meta, prefix []string) {
	for _, meta := range metas {
		context.RenderMeta(result, meta, value, prefix)
	}
}

func (context *Context) RenderMeta(writer *bytes.Buffer, meta *Meta, value interface{}, prefix []string) {
	prefix = append(prefix, meta.Name)

	funcsMap := context.funcMap()
	funcsMap["render_form"] = func(value interface{}, metas []*Meta, index ...int) string {
		var result = bytes.NewBufferString("")
		newPrefix := append([]string{}, prefix...)

		if len(index) > 0 {
			last := newPrefix[len(newPrefix)-1]
			newPrefix = append(newPrefix[:len(newPrefix)-1], fmt.Sprintf("%v[%v]", last, index[0]))
		}

		context.renderForm(result, value, metas, newPrefix)
		return result.String()
	}

	var tmpl = template.New(meta.Type + ".tmpl").Funcs(funcsMap)

	if tmpl, err := context.findTemplate(tmpl, fmt.Sprintf("forms/%v.tmpl", meta.Type)); err == nil {
		data := map[string]interface{}{}
		data["InputId"] = strings.Join(prefix, "")
		data["Label"] = meta.Label
		data["InputName"] = strings.Join(prefix, ".")
		value := meta.Valuer(value, context.Context)
		if rv := reflect.ValueOf(value); rv.Kind() == reflect.Ptr && !rv.IsNil() {
			value = rv.Elem().Interface()
		}
		data["Value"] = value
		if meta.GetCollection != nil {
			data["CollectionValue"] = meta.GetCollection(value, context.Context)
		}
		data["Meta"] = meta

		if err := tmpl.Execute(writer, data); err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Printf("%v: form type %v not supported\n", meta.Name, meta.Type)
	}
}

func (context *Context) HasPrimaryKey(value interface{}, primaryKey interface{}) bool {
	primaryKeys := []interface{}{}
	reflectValue := reflect.ValueOf(value)
	if reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	if reflectValue.Kind() == reflect.Slice {
		for i := 0; i < reflectValue.Len(); i++ {
			scope := &gorm.Scope{Value: reflectValue.Index(i).Interface()}
			primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
		}
	} else if reflectValue.Kind() == reflect.Struct {
		scope := &gorm.Scope{Value: value}
		primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
	}

	for _, key := range primaryKeys {
		if fmt.Sprintf("%v", primaryKey) == fmt.Sprintf("%v", key) {
			return true
		}
	}
	return false
}

func (context *Context) getResource(resources ...*Resource) *Resource {
	for _, res := range resources {
		return res
	}
	return context.Resource
}

func (context *Context) AllMetas(resources ...*Resource) []*Meta {
	return context.getResource(resources...).AllMetas()
}

func (context *Context) IndexMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.IndexMetas(), context, roles.Read)
}

func (context *Context) EditMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.EditMetas(), context, roles.Update)
}

func (context *Context) ShowMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.ShowMetas(), context, roles.Read)
}

func (context *Context) NewMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.NewMetas(), context, roles.Create)
}

func (context *Context) JavaScriptTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "javascripts", name+".js")
	return fmt.Sprintf(`<script src="%s"></script>`, name)
}

func (context *Context) StyleSheetTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "stylesheets", name+".css")
	return fmt.Sprintf(`<link type="text/css" rel="stylesheet" href="%s">`, name)
}

type Page struct {
	Page       int
	Current    bool
	IsPrevious bool
	IsNext     bool
}

func (context *Context) Pagination() []Page {
	pagination := context.Searcher.Pagination
	start := pagination.CurrentPage
	if start-5 < 1 {
		start = 1
	}

	end := start + 9
	if end > pagination.Pages {
		end = pagination.Pages
	}

	var pages []Page
	if start > 1 {
		pages = append(pages, Page{Page: start - 1, IsPrevious: true})
	}

	for i := start; i <= end; i++ {
		pages = append(pages, Page{Page: i, Current: pagination.CurrentPage == i})
	}

	if end < pagination.Pages {
		pages = append(pages, Page{Page: end + 1, IsNext: true})
	}

	return pages
}

func Equal(a, b interface{}) bool {
	return reflect.DeepEqual(a, b)
}

func (context *Context) funcMap() template.FuncMap {
	funcMap := template.FuncMap{
		"menus":             context.Admin.GetMenus,
		"current_user":      func() qor.CurrentUser { return context.CurrentUser },
		"render":            context.Render,
		"render_form":       context.RenderForm,
		"url_for":           context.UrlFor,
		"link_to":           context.LinkTo,
		"new_resource_path": context.NewResourcePath,
		"new_resource":      context.NewResource,
		"is_new_record":     context.NewRecord,
		"value_of":          context.ValueOf,
		"primary_key_of":    context.PrimaryKeyOf,
		"has_primary_key":   context.HasPrimaryKey,
		"all_metas":         context.AllMetas,
		"index_metas":       context.IndexMetas,
		"edit_metas":        context.EditMetas,
		"show_metas":        context.ShowMetas,
		"new_metas":         context.NewMetas,
		"pagination":        context.Pagination,
		"javascript_tag":    context.JavaScriptTag,
		"stylesheet_tag":    context.StyleSheetTag,
		"equal":             Equal,
	}

	for key, value := range context.Admin.funcMaps {
		funcMap[key] = value
	}
	return funcMap
}
<|endoftext|>


<commit_before>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"sync"
	"time"
)

type Adminz struct {
	// keep track of killfile state
	running bool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	onresume func()

	// pause is called when the server is killed
	onpause func()

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool

	sync.Mutex

	// the various handlers are attached to serveMux or DefaultServeMux
	mux *http.ServeMux
}

// Creates a new Adminz "builder". Not safe to use until Start() is called.
func New() *Adminz {
	return &Adminz{}
}

func (a *Adminz) Resume() {
	a.Lock()
	defer a.Unlock()
	a.doResume()
}

// Internal helper to resume if stopped. MUST be called while holding a.Lock. Use a.Resume if not.
func (a *Adminz) doResume() {
	if !a.running {
		if a.onresume != nil {
			a.onresume()
		}
		a.running = true
	}
}

func (a *Adminz) ServeMux(mux *http.ServeMux) *Adminz {
	a.mux = mux
	return a
}

// Resume is called when the server is unkilled
func (a *Adminz) OnResume(resume func()) *Adminz {
	a.onresume = resume
	return a
}

// Pause the server if it is running and return true, otherwise no-op and return false.
func (a *Adminz) Pause() bool {
	a.Lock()
	defer a.Unlock()
	return a.doPause()
}

// Internal helper to pause if running. MUST be called while holding a.Lock. Use a.Pause if not.
func (a *Adminz) doPause() bool {
	was := a.running
	if a.running {
		if a.onpause != nil {
			a.onpause()
		}
		a.running = false
	}
	return was
}

// pause is called when the server is killed
func (a *Adminz) OnPause(pause func()) *Adminz {
	a.onpause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Start initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Start() *Adminz {
	if a.mux != nil {
		a.mux.HandleFunc("/healthz", a.healthzHandler)
		a.mux.HandleFunc("/servicez", a.ServicezHandler)
		a.mux.HandleFunc("/quitquitquit", a.quitHandler)
		a.mux.HandleFunc("/abortabortabort", a.abortHandler)
		a.mux.HandleFunc("/gc", a.gcHandler)
	} else {
		http.HandleFunc("/healthz", a.healthzHandler)
		http.HandleFunc("/servicez", a.ServicezHandler)
		http.HandleFunc("/quitquitquit", a.quitHandler)
		http.HandleFunc("/abortabortabort", a.abortHandler)
		http.HandleFunc("/gc", a.gcHandler)
	}

	log.Print("adminz registered")

	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		log.Print("Watching paths for killfile: ", a.killfilePaths)
		a.checkKillfiles()
		go a.killfileLoop()
	} else {
		log.Print("No killfiles being watched.")
	}

	return a
}

// Stops killfile checking
func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...int) []string {
	// the number of ports + the "all" killfile
	log.Print(ports)
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%d", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			if a.Pause() {
				log.Println("paused due to ", killfile)
			}
			return true
		}
	}
	a.Resume()
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		a.checkKillfiles()
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string

	if a.running && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
		log.Println("Unhealthy, returning ", ret)
	}

	w.Write(([]byte)(ret))
}

type EmptyStruct struct {
}

func (a *Adminz) ServicezHandler(w http.ResponseWriter, r *http.Request) {
	var data interface{}

	if a.servicez != nil {
		data = a.servicez()
	} else {
		data = &EmptyStruct{}
	}

	bytes, err := json.Marshal(data)
	if err == nil {
		w.Header().Add("Content-Type", "application/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}

func (a *Adminz) quitHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("quitquitquit called! Pausing and shutting down service")
	a.Stop()
	a.Pause()
	os.Exit(0)
}

func (a *Adminz) abortHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("abortabortabort called! Shutting down service")
	os.Exit(0)
}

func (a *Adminz) gcHandler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats

	mb := uint64(1024 * 1024)
	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "Before")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	a.Lock()
	was := a.doPause()
	runtime.GC()
	if was {
		a.doResume()
	}
	a.Unlock()

	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "After")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	w.Write([]byte("OK"))
}
<commit_msg>Add "/health" as a clone of "/healthz"<commit_after>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"sync"
	"time"
)

type Adminz struct {
	// keep track of killfile state
	running bool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	onresume func()

	// pause is called when the server is killed
	onpause func()

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool

	sync.Mutex

	// the various handlers are attached to serveMux or DefaultServeMux
	mux *http.ServeMux
}

// Creates a new Adminz "builder". Not safe to use until Start() is called.
func New() *Adminz {
	return &Adminz{}
}

func (a *Adminz) Resume() {
	a.Lock()
	defer a.Unlock()
	a.doResume()
}

// Internal helper to resume if stopped. MUST be called while holding a.Lock. Use a.Resume if not.
func (a *Adminz) doResume() {
	if !a.running {
		if a.onresume != nil {
			a.onresume()
		}
		a.running = true
	}
}

func (a *Adminz) ServeMux(mux *http.ServeMux) *Adminz {
	a.mux = mux
	return a
}

// Resume is called when the server is unkilled
func (a *Adminz) OnResume(resume func()) *Adminz {
	a.onresume = resume
	return a
}

// Pause the server if it is running and return true, otherwise no-op and return false.
func (a *Adminz) Pause() bool {
	a.Lock()
	defer a.Unlock()
	return a.doPause()
}

// Internal helper to pause if running. MUST be called while holding a.Lock. Use a.Pause if not.
func (a *Adminz) doPause() bool {
	was := a.running
	if a.running {
		if a.onpause != nil {
			a.onpause()
		}
		a.running = false
	}
	return was
}

// pause is called when the server is killed
func (a *Adminz) OnPause(pause func()) *Adminz {
	a.onpause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Start initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Start() *Adminz {
	if a.mux != nil {
		a.mux.HandleFunc("/healthz", a.healthzHandler)
		a.mux.HandleFunc("/health", a.healthzHandler)
		a.mux.HandleFunc("/servicez", a.ServicezHandler)
		a.mux.HandleFunc("/quitquitquit", a.quitHandler)
		a.mux.HandleFunc("/abortabortabort", a.abortHandler)
		a.mux.HandleFunc("/gc", a.gcHandler)
	} else {
		http.HandleFunc("/healthz", a.healthzHandler)
		http.HandleFunc("/health", a.healthzHandler)
		http.HandleFunc("/servicez", a.ServicezHandler)
		http.HandleFunc("/quitquitquit", a.quitHandler)
		http.HandleFunc("/abortabortabort", a.abortHandler)
		http.HandleFunc("/gc", a.gcHandler)
	}

	log.Print("adminz registered")

	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		log.Print("Watching paths for killfile: ", a.killfilePaths)
		a.checkKillfiles()
		go a.killfileLoop()
	} else {
		log.Print("No killfiles being watched.")
	}

	return a
}

// Stops killfile checking
func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...int) []string {
	// the number of ports + the "all" killfile
	log.Print(ports)
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%d", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			if a.Pause() {
				log.Println("paused due to ", killfile)
			}
			return true
		}
	}
	a.Resume()
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		a.checkKillfiles()
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string

	if a.running && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
		log.Println("Unhealthy, returning ", ret)
	}

	w.Write(([]byte)(ret))
}

type EmptyStruct struct {
}

func (a *Adminz) ServicezHandler(w http.ResponseWriter, r *http.Request) {
	var data interface{}

	if a.servicez != nil {
		data = a.servicez()
	} else {
		data = &EmptyStruct{}
	}

	bytes, err := json.Marshal(data)
	if err == nil {
		w.Header().Add("Content-Type", "application/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}

func (a *Adminz) quitHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("quitquitquit called! Pausing and shutting down service")
	a.Stop()
	a.Pause()
	os.Exit(0)
}

func (a *Adminz) abortHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("abortabortabort called! Shutting down service")
	os.Exit(0)
}

func (a *Adminz) gcHandler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats

	mb := uint64(1024 * 1024)
	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "Before")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	a.Lock()
	was := a.doPause()
	runtime.GC()
	if was {
		a.doResume()
	}
	a.Unlock()

	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "After")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	w.Write([]byte("OK"))
}
<|endoftext|>


<commit_before>package sdbot

import (
	"testing"
)

// TestRename performs two independent tests on the Rename function.
//
// First it tries to rename to a name considered to be a different user.
// Second, it tries to rename to a name that is considered to be canonically
// the same by the server (same alphanumeric characters).
func TestRename(t *testing.T) {
	testBot := NewBot("examples/config/config_example.toml")
	FindUserEnsured("tympy", testBot)
	testRoom := FindRoomEnsured("test", testBot)
	testRoom.AddUser("tympy")
	Rename("tympy", "tympani", testRoom, testBot)

	if testBot.UserList["tympani"] == nil {
		t.Fatal(`user "tympani" was not created or stored`)
	}
	if len(testRoom.Users) != 1 {
		t.Fatalf(`number of users in room (%d) should == 1`, len(testRoom.Users))
	}
	if testRoom.Users[0] != "tympani" {
		t.Fatalf(`user in room (%s) should == tympani`, testRoom.Users[0])
	}

	FindUserEnsured("randomuser1", testBot)
	FindUserEnsured("randomuser2", testBot)
	testRoom.AddUser("randomuser1")
	testRoom.AddUser("randomuser2")
	Rename("tympani", "tympy", testRoom, testBot)

	if len(testRoom.Users) != 3 {
		t.Fatalf(`number of users in room (%d) should == 3`, len(testRoom.Users))
	}
	var oldFound bool
	var newFound bool
	for _, u := range testRoom.Users {
		if u == "tympy" {
			newFound = true
		} else if u == "tympani" {
			oldFound = true
		}
	}
	if oldFound {
		t.Fatalf(`bool "oldFound" (%t) should == false`, oldFound)
	}
	if !newFound {
		t.Fatalf(`bool "newFound" (%t) should == true`, newFound)
	}

	FindUserEnsured("tympy", testBot).AddAuth("test", "+")
	testName := "T\\%\\%\\%\\%\\%ympy"
	Rename("tympy", testName, testRoom, testBot)
	testUser := FindUserEnsured("tympy", testBot)

	if len(testRoom.Users) != 3 {
		t.Fatalf(`number of users in room (%d) should == 3`, len(testRoom.Users))
	}
	if testUser.Name != testName {
		t.Fatalf(`username (%s) should == (%s)`, testUser.Name, testName)
	}
}
<commit_msg>Add extra tests to Rename to ensure the correct auths are maintained.<commit_after>package sdbot

import (
	"testing"
)

// TestRename performs two independent tests on the Rename function.
//
// First it tries to rename to a name considered to be a different user.
// Second, it tries to rename to a name that is considered to be canonically
// the same by the server (same alphanumeric characters).
func TestRename(t *testing.T) {
	testBot := NewBot("examples/config/config_example.toml")
	testUser := FindUserEnsured("tympy", testBot)
	testBot.UserList[testUser.Name].AddAuth("test", Voiced)
	testRoom := FindRoomEnsured("test", testBot)
	testRoom.AddUser("tympy")
	Rename("tympy", "tympani", testRoom, testBot, Voiced)

	if testBot.UserList["tympani"] == nil {
		t.Fatal(`user "tympani" was not created or stored`)
	}
	if len(testRoom.Users) != 1 {
		t.Fatalf(`number of users in room (%d) should == 1`, len(testRoom.Users))
	}
	if testRoom.Users[0] != "tympani" {
		t.Fatalf(`user in room (%s) should == tympani`, testRoom.Users[0])
	}
	if FindUserEnsured(testRoom.Users[0], testBot).Auths["test"] != Voiced {
		t.Fatalf(`user "tympani" has auth (%s) should == %s`,
			FindUserEnsured(testRoom.Users[0], testBot).Auths["test"], Voiced)
	}

	FindUserEnsured("randomuser1", testBot)
	FindUserEnsured("randomuser2", testBot)
	testRoom.AddUser("randomuser1")
	testRoom.AddUser("randomuser2")
	Rename("tympani", "tympy", testRoom, testBot, Driver)
	var testRenamedReauthedUser *User

	if len(testRoom.Users) != 3 {
		t.Fatalf(`number of users in room (%d) should == 3`, len(testRoom.Users))
	}
	var oldFound bool
	var newFound bool
	for _, u := range testRoom.Users {
		if u == "tympy" {
			newFound = true
			testRenamedReauthedUser = FindUserEnsured(u, testBot)
		} else if u == "tympani" {
			oldFound = true
		}
	}
	if oldFound {
		t.Fatalf(`bool "oldFound" (%t) should == false`, oldFound)
	}
	if !newFound {
		t.Fatalf(`bool "newFound" (%t) should == true`, newFound)
	}
	if testRenamedReauthedUser.Auths["test"] != Driver {
		t.Fatalf(`renamed user "%s" has auth (%s) should == %s`,
			testRenamedReauthedUser.Name, testRenamedReauthedUser.Auths["test"], Driver)
	}

	FindUserEnsured("tympy", testBot)
	testName := "T\\%\\%\\%\\%\\%ympy"
	Rename("tympy", testName, testRoom, testBot)
	testUser = FindUserEnsured("tympy", testBot)

	if len(testRoom.Users) != 3 {
		t.Fatalf(`number of users in room (%d) should == 3`, len(testRoom.Users))
	}
	if testUser.Name != testName {
		t.Fatalf(`username (%s) should == (%s)`, testUser.Name, testName)
	}
}
<|endoftext|>


<commit_before>package idletiming

import (
	"io"
	"io/ioutil"
	"net"
	"sync/atomic"
	"testing"
	"time"

	"github.com/getlantern/fdcount"
)

var (
	msg = []byte("HelloThere")

	dataLoops = 10

	clientTimeout                 = 25 * time.Millisecond
	serverTimeout                 = 10 * clientTimeout
	slightlyLessThanClientTimeout = time.Duration(int64(float64(clientTimeout.Nanoseconds()) * 0.9))
	slightlyMoreThanClientTimeout = time.Duration(int64(float64(clientTimeout.Nanoseconds()) * 1.1))
)

func TestWrite(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	listenerIdled := int32(0)
	connIdled := int32(0)

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}

	addr := l.Addr().String()
	il := Listener(l, serverTimeout, func(conn net.Conn) {
		atomic.StoreInt32(&listenerIdled, 1)
		if err := conn.Close(); err != nil {
			t.Errorf("Unable to close connection: %v", err)
		}
	})
	defer func() {
		if err := il.Close(); err != nil {
			t.Errorf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	go func() {
		conn, err := il.Accept()
		if err != nil {
			t.Fatalf("Unable to accept: %s", err)
		}
		go func() {
			// Discard data
			if _, err := io.Copy(ioutil.Discard, conn); err != nil {
				t.Fatalf("Unable to discard data: %v", err)
			}
		}()
	}()

	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	conn = &slowConn{orig: conn, targetDuration: slightlyLessThanClientTimeout}

	c := Conn(conn, clientTimeout, func() {
		atomic.StoreInt32(&connIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})

	// Write messages
	for i := 0; i < dataLoops; i++ {
		n, err := c.Write(msg)
		if err != nil || n != len(msg) {
			t.Fatalf("Problem writing.  n: %d  err: %s", n, err)
		}
	}

	// Now write msg with a really short deadline
	if err := c.SetWriteDeadline(time.Now().Add(1 * time.Nanosecond)); err != nil {
		t.Fatalf("Unable to set write deadline: %v", err)
	}
	_, err = c.Write(msg)
	if netErr, ok := err.(net.Error); ok {
		if !netErr.Timeout() {
			t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
		}
	} else {
		t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
	}

	time.Sleep(slightlyMoreThanClientTimeout)
	if connIdled == 0 {
		t.Errorf("Conn failed to idle!")
	}

	connTimesOutIn := c.TimesOutIn()
	if connTimesOutIn > 0 {
		t.Errorf("TimesOutIn returned bad value, should have been negative, but was: %s", connTimesOutIn)
	}

	time.Sleep(9 * slightlyMoreThanClientTimeout)
	if listenerIdled == 0 {
		t.Errorf("Listener failed to idle!")
	}
}

func TestRead(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	listenerIdled := int32(0)
	connIdled := int32(0)

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}

	il := Listener(l, serverTimeout, func(conn net.Conn) {
		atomic.StoreInt32(&listenerIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})
	defer func() {
		if err := il.Close(); err != nil {
			t.Fatalf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	addr := l.Addr().String()

	go func() {
		conn, err := il.Accept()
		if err != nil {
			t.Fatalf("Unable to accept: %s", err)
		}
		go func() {
			// Feed data
			for i := 0; i < dataLoops; i++ {
				_, err := conn.Write(msg)
				if err != nil {
					return
				}
			}
		}()
	}()

	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	conn = &slowConn{orig: conn, targetDuration: slightlyLessThanClientTimeout}

	c := Conn(conn, clientTimeout, func() {
		atomic.StoreInt32(&connIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})

	// Read messages (we use a buffer matching the message size to make sure
	// that each iterator of the below loop actually has something to read).
	b := make([]byte, len(msg))
	totalN := 0
	for i := 0; i < dataLoops; i++ {
		n, err := c.Read(b)
		if err != nil {
			t.Fatalf("Problem reading. Read %d bytes, err: %s", n, err)
		}
		totalN += n
	}

	if totalN == 0 {
		t.Fatal("Didn't read any data!")
	}

	// Now read with a really short deadline
	if err := c.SetReadDeadline(time.Now().Add(1 * time.Nanosecond)); err != nil {
		t.Fatalf("Unable to set read deadline: %v", err)
	}
	_, err = c.Read(msg)
	if netErr, ok := err.(net.Error); ok {
		if !netErr.Timeout() {
			t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
		}
	} else {
		t.Fatalf("Short deadline should have resulted in net.Error, but didn't: %s", err)
	}

	time.Sleep(slightlyMoreThanClientTimeout)
	if connIdled == 0 {
		t.Errorf("Conn failed to idle!")
	}

	time.Sleep(9 * slightlyMoreThanClientTimeout)
	if listenerIdled == 0 {
		t.Errorf("Listener failed to idle!")
	}
}

func TestClose(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}
	defer func() {
		if err := l.Close(); err != nil {
			t.Fatalf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	addr := l.Addr().String()
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	c := Conn(conn, clientTimeout, func() {})
	for i := 0; i < 100; i++ {
		_ = c.Close()
	}
}

// slowConn wraps a net.Conn and ensures that Writes and Reads take
// TargetDuration.
type slowConn struct {
	orig           net.Conn
	targetDuration time.Duration
	readDeadline   time.Time
	writeDeadline  time.Time
}

func (c *slowConn) Read(b []byte) (int, error) {
	targetEnd := time.Now().Add(c.targetDuration)
	if targetEnd.After(c.readDeadline) {
		// Never wait longer than the configured readDeadline
		targetEnd = c.readDeadline
	}
	n, err := c.orig.Read(b)
	sleepTime := targetEnd.Sub(time.Now())
	if sleepTime <= 0 && err == nil {
		err = timeoutError("slowConn timeout")
	}
	if n > 0 {
		time.Sleep(sleepTime)
	}
	return n, err
}

func (c *slowConn) Write(b []byte) (int, error) {
	targetEnd := time.Now().Add(c.targetDuration)
	if targetEnd.After(c.writeDeadline) {
		// Never wait longer than the configured writeDeadline
		targetEnd = c.writeDeadline
	}
	n, err := c.orig.Write(b)
	sleepTime := targetEnd.Sub(time.Now())
	if sleepTime <= 0 && err == nil {
		err = timeoutError("slowConn timeout")
	}
	if n > 0 {
		time.Sleep(sleepTime)
	}
	return n, err
}

func (c *slowConn) Close() error {
	return c.orig.Close()
}

func (c *slowConn) LocalAddr() net.Addr {
	return c.orig.LocalAddr()
}

func (c *slowConn) RemoteAddr() net.Addr {
	return c.orig.RemoteAddr()
}

func (c *slowConn) SetDeadline(t time.Time) error {
	err := c.SetReadDeadline(t)
	if err != nil {
		return err
	}
	return c.SetWriteDeadline(t)
}

func (c *slowConn) SetReadDeadline(t time.Time) error {
	c.readDeadline = t
	return c.orig.SetReadDeadline(t)
}

func (c *slowConn) SetWriteDeadline(t time.Time) error {
	c.writeDeadline = t
	return c.orig.SetWriteDeadline(t)
}

type timeoutError string

func (e timeoutError) Error() string {
	return string(e)
}

func (e timeoutError) Timeout() bool {
	return true
}

func (e timeoutError) Temporary() bool {
	return true
}
<commit_msg>Fixed occasional failure in idletiming_test<commit_after>package idletiming

import (
	"io"
	"io/ioutil"
	"net"
	"sync/atomic"
	"testing"
	"time"

	"github.com/getlantern/fdcount"
)

var (
	msg = []byte("HelloThere")

	dataLoops = 10

	clientTimeout                 = 25 * time.Millisecond
	serverTimeout                 = 10 * clientTimeout
	slightlyLessThanClientTimeout = time.Duration(int64(float64(clientTimeout.Nanoseconds()) * 0.5))
	slightlyMoreThanClientTimeout = time.Duration(int64(float64(clientTimeout.Nanoseconds()) * 1.5))
)

func TestWrite(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	listenerIdled := int32(0)
	connIdled := int32(0)

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}

	addr := l.Addr().String()
	il := Listener(l, serverTimeout, func(conn net.Conn) {
		atomic.StoreInt32(&listenerIdled, 1)
		if err := conn.Close(); err != nil {
			t.Errorf("Unable to close connection: %v", err)
		}
	})
	defer func() {
		if err := il.Close(); err != nil {
			t.Errorf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	go func() {
		conn, err := il.Accept()
		if err != nil {
			t.Fatalf("Unable to accept: %s", err)
		}
		go func() {
			// Discard data
			if _, err := io.Copy(ioutil.Discard, conn); err != nil {
				t.Fatalf("Unable to discard data: %v", err)
			}
		}()
	}()

	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	conn = &slowConn{orig: conn, targetDuration: slightlyLessThanClientTimeout}

	c := Conn(conn, clientTimeout, func() {
		atomic.StoreInt32(&connIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})

	// Write messages
	for i := 0; i < dataLoops; i++ {
		n, err := c.Write(msg)
		if err != nil || n != len(msg) {
			t.Fatalf("Problem writing.  n: %d  err: %s", n, err)
		}
	}

	// Now write msg with a really short deadline
	if err := c.SetWriteDeadline(time.Now().Add(1 * time.Nanosecond)); err != nil {
		t.Fatalf("Unable to set write deadline: %v", err)
	}
	_, err = c.Write(msg)
	if netErr, ok := err.(net.Error); ok {
		if !netErr.Timeout() {
			t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
		}
	} else {
		t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
	}

	time.Sleep(slightlyMoreThanClientTimeout)
	if connIdled == 0 {
		t.Errorf("Conn failed to idle!")
	}

	connTimesOutIn := c.TimesOutIn()
	if connTimesOutIn > 0 {
		t.Errorf("TimesOutIn returned bad value, should have been negative, but was: %s", connTimesOutIn)
	}

	time.Sleep(9 * slightlyMoreThanClientTimeout)
	if listenerIdled == 0 {
		t.Errorf("Listener failed to idle!")
	}
}

func TestRead(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	listenerIdled := int32(0)
	connIdled := int32(0)

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}

	il := Listener(l, serverTimeout, func(conn net.Conn) {
		atomic.StoreInt32(&listenerIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})
	defer func() {
		if err := il.Close(); err != nil {
			t.Fatalf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	addr := l.Addr().String()

	go func() {
		conn, err := il.Accept()
		if err != nil {
			t.Fatalf("Unable to accept: %s", err)
		}
		go func() {
			// Feed data
			for i := 0; i < dataLoops; i++ {
				_, err := conn.Write(msg)
				if err != nil {
					return
				}
			}
		}()
	}()

	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	conn = &slowConn{orig: conn, targetDuration: slightlyLessThanClientTimeout}

	c := Conn(conn, clientTimeout, func() {
		atomic.StoreInt32(&connIdled, 1)
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	})

	// Read messages (we use a buffer matching the message size to make sure
	// that each iterator of the below loop actually has something to read).
	b := make([]byte, len(msg))
	totalN := 0
	for i := 0; i < dataLoops; i++ {
		n, err := c.Read(b)
		if err != nil {
			t.Fatalf("Problem reading. Read %d bytes, err: %s", n, err)
		}
		totalN += n
	}

	if totalN == 0 {
		t.Fatal("Didn't read any data!")
	}

	// Now read with a really short deadline
	if err := c.SetReadDeadline(time.Now().Add(1 * time.Nanosecond)); err != nil {
		t.Fatalf("Unable to set read deadline: %v", err)
	}
	_, err = c.Read(msg)
	if netErr, ok := err.(net.Error); ok {
		if !netErr.Timeout() {
			t.Fatalf("Short deadline should have resulted in Timeout, but didn't: %s", err)
		}
	} else {
		t.Fatalf("Short deadline should have resulted in net.Error, but didn't: %s", err)
	}

	time.Sleep(slightlyMoreThanClientTimeout)
	if connIdled == 0 {
		t.Errorf("Conn failed to idle!")
	}

	time.Sleep(9 * slightlyMoreThanClientTimeout)
	if listenerIdled == 0 {
		t.Errorf("Listener failed to idle!")
	}
}

func TestClose(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("Unable to listen: %s", err)
	}
	defer func() {
		if err := l.Close(); err != nil {
			t.Fatalf("Unable to close listener: %v", err)
		}
		time.Sleep(1 * time.Second)
		err = fdc.AssertDelta(0)
		if err != nil {
			t.Errorf("File descriptors didn't return to original: %s", err)
		}
	}()

	addr := l.Addr().String()
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		t.Fatalf("Unable to dial %s: %s", addr, err)
	}

	c := Conn(conn, clientTimeout, func() {})
	for i := 0; i < 100; i++ {
		_ = c.Close()
	}
}

// slowConn wraps a net.Conn and ensures that Writes and Reads take
// TargetDuration.
type slowConn struct {
	orig           net.Conn
	targetDuration time.Duration
	readDeadline   time.Time
	writeDeadline  time.Time
}

func (c *slowConn) Read(b []byte) (int, error) {
	targetEnd := time.Now().Add(c.targetDuration)
	if targetEnd.After(c.readDeadline) {
		// Never wait longer than the configured readDeadline
		targetEnd = c.readDeadline
	}
	n, err := c.orig.Read(b)
	sleepTime := targetEnd.Sub(time.Now())
	if sleepTime <= 0 && err == nil {
		err = timeoutError("slowConn timeout")
	}
	if n > 0 {
		time.Sleep(sleepTime)
	}
	return n, err
}

func (c *slowConn) Write(b []byte) (int, error) {
	targetEnd := time.Now().Add(c.targetDuration)
	if targetEnd.After(c.writeDeadline) {
		// Never wait longer than the configured writeDeadline
		targetEnd = c.writeDeadline
	}
	n, err := c.orig.Write(b)
	sleepTime := targetEnd.Sub(time.Now())
	if sleepTime <= 0 && err == nil {
		err = timeoutError("slowConn timeout")
	}
	if n > 0 {
		time.Sleep(sleepTime)
	}
	return n, err
}

func (c *slowConn) Close() error {
	return c.orig.Close()
}

func (c *slowConn) LocalAddr() net.Addr {
	return c.orig.LocalAddr()
}

func (c *slowConn) RemoteAddr() net.Addr {
	return c.orig.RemoteAddr()
}

func (c *slowConn) SetDeadline(t time.Time) error {
	err := c.SetReadDeadline(t)
	if err != nil {
		return err
	}
	return c.SetWriteDeadline(t)
}

func (c *slowConn) SetReadDeadline(t time.Time) error {
	c.readDeadline = t
	return c.orig.SetReadDeadline(t)
}

func (c *slowConn) SetWriteDeadline(t time.Time) error {
	c.writeDeadline = t
	return c.orig.SetWriteDeadline(t)
}

type timeoutError string

func (e timeoutError) Error() string {
	return string(e)
}

func (e timeoutError) Timeout() bool {
	return true
}

func (e timeoutError) Temporary() bool {
	return true
}
<|endoftext|>


<commit_before>package build

import (
	"bytes"
	"encoding/hex"
	"fmt"

	"github.com/stellar/go-stellar-base"
	"github.com/stellar/go-stellar-base/xdr"
)

// Transaction groups the creation of a new TransactionBuilder with a call
// to Mutate.
func Transaction(muts ...TransactionMutator) (result TransactionBuilder) {
	result.Mutate(Defaults{})
	for _, m := range muts {
		m.MutateTransaction(&result)
	}
	return
}

// TransactionMutator is a interface that wraps the
// MutateTransaction operation.  types may implement this interface to
// specify how they modify an xdr.Transaction object
type TransactionMutator interface {
	MutateTransaction(*TransactionBuilder) error
}

// TransactionBuilder represents a Transaction that is being constructed.
type TransactionBuilder struct {
	TX        xdr.Transaction
	NetworkID [32]byte
	Err       error
}

// Mutate applies the provided TransactionMutators to this builder's transaction
func (b *TransactionBuilder) Mutate(muts ...TransactionMutator) {
	for _, m := range muts {
		err := m.MutateTransaction(b)
		if err != nil {
			b.Err = err
			return
		}
	}
}

// Hash returns the hash of this builder's transaction.
func (b *TransactionBuilder) Hash() ([32]byte, error) {
	var txBytes bytes.Buffer

	_, err := fmt.Fprintf(&txBytes, "%s", b.NetworkID)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, xdr.EnvelopeTypeEnvelopeTypeTx)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, b.TX)
	if err != nil {
		return [32]byte{}, err
	}

	return stellarbase.Hash(txBytes.Bytes()), nil
}

// HashHex returns the hex-encoded hash of this builder's transaction
func (b *TransactionBuilder) HashHex() (string, error) {
	hash, err := b.Hash()
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(hash[:]), nil
}

// Sign returns an new TransactionEnvelopeBuilder using this builder's
// transaction as the basis and with signatures of that transaction from the
// provided Signers.
func (b *TransactionBuilder) Sign(signers ...stellarbase.Signer) (result TransactionEnvelopeBuilder) {
	result.Mutate(*b)

	for _, s := range signers {
		result.Mutate(Sign{s})
	}

	return
}

// ------------------------------------------------------------
//
//   Mutator implementations
//
// ------------------------------------------------------------

// MutateTransaction for SourceAccount sets the transaction's SourceAccount
// to the pubilic key for the address provided
func (m Defaults) MutateTransaction(o *TransactionBuilder) error {
	o.TX.Fee = 10
	memo, err := xdr.NewMemo(xdr.MemoTypeMemoNone, nil)
	o.TX.Memo = memo
	o.NetworkID = DefaultNetwork.ID()
	return err
}

// MutateTransaction for SourceAccount sets the transaction's SourceAccount
// to the pubilic key for the address provided
func (m SourceAccount) MutateTransaction(o *TransactionBuilder) error {
	aid, err := stellarbase.AddressToAccountId(m.Address)
	o.TX.SourceAccount = aid
	return err
}

// MutateTransaction for PaymentBuilder causes the underylying PaymentOp
// to be added to the operation list for the provided transaction
func (m PaymentBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePayment, m.P)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for CreateAccountBuilder causes the underylying
// CreateAccountOp to be added to the operation list for the provided
// transaction
func (m CreateAccountBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreateAccount, m.CA)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Sequence sets the SeqNum on the transaction.
func (m Sequence) MutateTransaction(o *TransactionBuilder) error {
	o.TX.SeqNum = xdr.SequenceNumber(m.Sequence)
	return nil
}

// MutateTransaction for Network sets the Network ID to use when signing this transaction
func (m Network) MutateTransaction(o *TransactionBuilder) error {
	o.NetworkID = m.ID()
	return nil
}
<commit_msg>Update fee to 100 stroops<commit_after>package build

import (
	"bytes"
	"encoding/hex"
	"fmt"

	"github.com/stellar/go-stellar-base"
	"github.com/stellar/go-stellar-base/xdr"
)

// Transaction groups the creation of a new TransactionBuilder with a call
// to Mutate.
func Transaction(muts ...TransactionMutator) (result TransactionBuilder) {
	result.Mutate(Defaults{})
	for _, m := range muts {
		m.MutateTransaction(&result)
	}
	return
}

// TransactionMutator is a interface that wraps the
// MutateTransaction operation.  types may implement this interface to
// specify how they modify an xdr.Transaction object
type TransactionMutator interface {
	MutateTransaction(*TransactionBuilder) error
}

// TransactionBuilder represents a Transaction that is being constructed.
type TransactionBuilder struct {
	TX        xdr.Transaction
	NetworkID [32]byte
	Err       error
}

// Mutate applies the provided TransactionMutators to this builder's transaction
func (b *TransactionBuilder) Mutate(muts ...TransactionMutator) {
	for _, m := range muts {
		err := m.MutateTransaction(b)
		if err != nil {
			b.Err = err
			return
		}
	}
}

// Hash returns the hash of this builder's transaction.
func (b *TransactionBuilder) Hash() ([32]byte, error) {
	var txBytes bytes.Buffer

	_, err := fmt.Fprintf(&txBytes, "%s", b.NetworkID)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, xdr.EnvelopeTypeEnvelopeTypeTx)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, b.TX)
	if err != nil {
		return [32]byte{}, err
	}

	return stellarbase.Hash(txBytes.Bytes()), nil
}

// HashHex returns the hex-encoded hash of this builder's transaction
func (b *TransactionBuilder) HashHex() (string, error) {
	hash, err := b.Hash()
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(hash[:]), nil
}

// Sign returns an new TransactionEnvelopeBuilder using this builder's
// transaction as the basis and with signatures of that transaction from the
// provided Signers.
func (b *TransactionBuilder) Sign(signers ...stellarbase.Signer) (result TransactionEnvelopeBuilder) {
	result.Mutate(*b)

	for _, s := range signers {
		result.Mutate(Sign{s})
	}

	return
}

// ------------------------------------------------------------
//
//   Mutator implementations
//
// ------------------------------------------------------------

// MutateTransaction for Defaults sets reasonable defaults on the transaction being built
func (m Defaults) MutateTransaction(o *TransactionBuilder) error {
	o.TX.Fee = 100
	memo, err := xdr.NewMemo(xdr.MemoTypeMemoNone, nil)
	o.TX.Memo = memo
	o.NetworkID = DefaultNetwork.ID()
	return err
}

// MutateTransaction for SourceAccount sets the transaction's SourceAccount
// to the pubilic key for the address provided
func (m SourceAccount) MutateTransaction(o *TransactionBuilder) error {
	aid, err := stellarbase.AddressToAccountId(m.Address)
	o.TX.SourceAccount = aid
	return err
}

// MutateTransaction for PaymentBuilder causes the underylying PaymentOp
// to be added to the operation list for the provided transaction
func (m PaymentBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePayment, m.P)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for CreateAccountBuilder causes the underylying
// CreateAccountOp to be added to the operation list for the provided
// transaction
func (m CreateAccountBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreateAccount, m.CA)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Sequence sets the SeqNum on the transaction.
func (m Sequence) MutateTransaction(o *TransactionBuilder) error {
	o.TX.SeqNum = xdr.SequenceNumber(m.Sequence)
	return nil
}

// MutateTransaction for Network sets the Network ID to use when signing this transaction
func (m Network) MutateTransaction(o *TransactionBuilder) error {
	o.NetworkID = m.ID()
	return nil
}
<|endoftext|>


<commit_before>package geonames

import (
	"archive/zip"
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

const allCountriesURI = `allCountries.zip`

// AllCountries returns a big pack of all features of all countries
func AllCountries() (map[int]*Feature, error) {
	var err error
	result := make(map[int]*Feature)
	url := fmt.Sprintf("%s%s", geonamesURL, allCountriesURI)

	dat, err := httpGetNew(url)
	if err != nil {
		return nil, err
	}

	tempPath := getTempPath(allCountriesURI)

	f, err := writeToFile(tempPath, dat)
	if err != nil {
		return nil, err
	}
	dat.Close()
	defer f.Close()
	defer os.Remove(tempPath)

	r, err := zip.OpenReader(f.Name())
	if err != nil {
		return nil, err
	}
	defer r.Close()
	txtName := strings.Replace(allCountriesURI, "zip", "txt", -1)
	var s *bufio.Scanner
	for i := range r.File {
		if r.File[i].Name == txtName {
			rc, e := r.File[i].Open()
			if e != nil {
				return nil, e
			}
			defer rc.Close()

			s = bufio.NewScanner(rc)
			break
		}
	}

	if s == nil {
		return nil, errors.New("unknown error")
	}

	sParse(s, 0, func(raw []string) bool {
		if len(raw) != 19 {
			return true
		}

		geonameID, err := strconv.Atoi(raw[0])
		if err != nil {
			log.Printf("while parsing feature geoname id %s: %s", raw[0], err.Error())
			return true
		}

		alternateNames := strings.Split(raw[3], ",")
		for i := range alternateNames {
			alternateNames[i] = strings.TrimSpace(alternateNames[i])
			if alternateNames[i] == "" {
				alternateNames = append(alternateNames[:i], alternateNames[i+1:]...)
			}
		}

		latitude, err := strconv.ParseFloat(raw[4], 64)
		if err != nil {
			log.Printf("while parsing feature latitude %s: %s", raw[4], err.Error())
			return true
		}
		longitude, err := strconv.ParseFloat(raw[5], 64)
		if err != nil {
			log.Printf("while parsing feature longitude %s: %s", raw[5], err.Error())
			return true
		}

		var population *int
		if (raw[14]) != "" {
			populationInt, e := strconv.Atoi(raw[14])
			if e == nil {
				population = &populationInt
			}
		}

		var elevation *int
		if (raw[15]) != "" {
			elevationInt, e := strconv.Atoi(raw[15])
			if e == nil {
				elevation = &elevationInt
			}
		}

		dem, err := strconv.Atoi(raw[16])
		if err != nil {
			log.Printf("while parsing feature dem %s: %s", raw[16], err.Error())
			return true
		}
		modificationDate, err := time.Parse("2006-01-02", raw[18])
		if err != nil {
			log.Printf("while parsing feature modification date %s: %s", raw[18], err.Error())
			return true
		}

		result[geonameID] = &Feature{
			GeonameID:        geonameID,
			Name:             raw[1],
			ASCIIName:        raw[2],
			AlternateNames:   alternateNames,
			Latitude:         latitude,
			Longitude:        longitude,
			Class:            raw[6],
			Code:             raw[7],
			CountryCode:      raw[8],
			Cc2:              raw[9],
			Admin1Code:       raw[10],
			Admin2Code:       raw[11],
			Admin3Code:       raw[12],
			Admin4Code:       raw[13],
			Population:       population,
			Elevation:        elevation,
			Dem:              dem,
			TimeZone:         raw[17],
			ModificationDate: modificationDate,
		}

		return true
	})

	return result, nil
}
<commit_msg>saving RAM: added CallAllCountries method calling the passed handler on each extracted feature<commit_after>package geonames

import (
	"archive/zip"
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

const allCountriesURI = `allCountries.zip`

// AllCountries returns a big pack of all features of all countries
func AllCountries() (map[int]*Feature, error) {
	result := make(map[int]*Feature)

	err := CallAllCountries(func(f *Feature) {
		result[f.GeonameID] = f
	})

	return result, err
}

// CallAllCountries calls the passed handler on each extracted feature.
func CallAllCountries(handler func(*Feature)) error {
	url := fmt.Sprintf("%s%s", geonamesURL, allCountriesURI)

	dat, err := httpGetNew(url)
	if err != nil {
		return err
	}

	tempPath := getTempPath(allCountriesURI)

	f, err := writeToFile(tempPath, dat)
	if err != nil {
		return err
	}
	dat.Close()
	defer f.Close()
	defer os.Remove(tempPath)

	r, err := zip.OpenReader(f.Name())
	if err != nil {
		return err
	}
	defer r.Close()
	txtName := strings.Replace(allCountriesURI, "zip", "txt", -1)
	var s *bufio.Scanner
	for i := range r.File {
		if r.File[i].Name == txtName {
			rc, e := r.File[i].Open()
			if e != nil {
				return e
			}
			defer rc.Close()

			s = bufio.NewScanner(rc)
			break
		}
	}

	if s == nil {
		return errors.New("unknown error")
	}

	sParse(s, 0, func(raw []string) bool {
		if len(raw) != 19 {
			return true
		}

		geonameID, err := strconv.Atoi(raw[0])
		if err != nil {
			log.Printf("while parsing feature geoname id %s: %s", raw[0], err.Error())
			return true
		}

		alternateNames := strings.Split(raw[3], ",")
		for i := range alternateNames {
			alternateNames[i] = strings.TrimSpace(alternateNames[i])
			if alternateNames[i] == "" {
				alternateNames = append(alternateNames[:i], alternateNames[i+1:]...)
			}
		}

		latitude, err := strconv.ParseFloat(raw[4], 64)
		if err != nil {
			log.Printf("while parsing feature latitude %s: %s", raw[4], err.Error())
			return true
		}
		longitude, err := strconv.ParseFloat(raw[5], 64)
		if err != nil {
			log.Printf("while parsing feature longitude %s: %s", raw[5], err.Error())
			return true
		}

		var population *int
		if (raw[14]) != "" {
			populationInt, e := strconv.Atoi(raw[14])
			if e == nil {
				population = &populationInt
			}
		}

		var elevation *int
		if (raw[15]) != "" {
			elevationInt, e := strconv.Atoi(raw[15])
			if e == nil {
				elevation = &elevationInt
			}
		}

		dem, err := strconv.Atoi(raw[16])
		if err != nil {
			log.Printf("while parsing feature dem %s: %s", raw[16], err.Error())
			return true
		}
		modificationDate, err := time.Parse("2006-01-02", raw[18])
		if err != nil {
			log.Printf("while parsing feature modification date %s: %s", raw[18], err.Error())
			return true
		}

		handler(&Feature{
			GeonameID:        geonameID,
			Name:             raw[1],
			ASCIIName:        raw[2],
			AlternateNames:   alternateNames,
			Latitude:         latitude,
			Longitude:        longitude,
			Class:            raw[6],
			Code:             raw[7],
			CountryCode:      raw[8],
			Cc2:              raw[9],
			Admin1Code:       raw[10],
			Admin2Code:       raw[11],
			Admin3Code:       raw[12],
			Admin4Code:       raw[13],
			Population:       population,
			Elevation:        elevation,
			Dem:              dem,
			TimeZone:         raw[17],
			ModificationDate: modificationDate,
		})

		return true
	})

	return nil
}
<|endoftext|>


<commit_before>package boil

import (
	"database/sql"
	"fmt"
	"math"
	"math/rand"
	"reflect"
	"sort"
	"time"

	"github.com/nullbio/sqlboiler/strmangle"
	"gopkg.in/nullbio/null.v4"
)

var (
	typeNullFloat32 = reflect.TypeOf(null.Float32{})
	typeNullFloat64 = reflect.TypeOf(null.Float64{})
	typeNullInt     = reflect.TypeOf(null.Int{})
	typeNullInt8    = reflect.TypeOf(null.Int8{})
	typeNullInt16   = reflect.TypeOf(null.Int16{})
	typeNullInt32   = reflect.TypeOf(null.Int32{})
	typeNullInt64   = reflect.TypeOf(null.Int64{})
	typeNullUint    = reflect.TypeOf(null.Uint{})
	typeNullUint8   = reflect.TypeOf(null.Uint8{})
	typeNullUint16  = reflect.TypeOf(null.Uint16{})
	typeNullUint32  = reflect.TypeOf(null.Uint32{})
	typeNullUint64  = reflect.TypeOf(null.Uint64{})
	typeNullString  = reflect.TypeOf(null.String{})
	typeNullBool    = reflect.TypeOf(null.Bool{})
	typeNullTime    = reflect.TypeOf(null.Time{})
	typeTime        = reflect.TypeOf(time.Time{})
)

// Bind executes the query and inserts the
// result into the passed in object pointer
func (q *Query) Bind(obj interface{}) error {
	typ := reflect.TypeOf(obj)
	kind := typ.Kind()

	if kind != reflect.Ptr {
		return fmt.Errorf("Bind not given a pointer to a slice or struct: %s", typ.String())
	}

	typ = typ.Elem()
	kind = typ.Kind()

	if kind == reflect.Struct {
		row := ExecQueryOne(q)
		err := BindOne(row, q.selectCols, obj)
		if err != nil {
			return fmt.Errorf("Failed to execute Bind query for %s: %s", q.table, err)
		}
	} else if kind == reflect.Slice {
		rows, err := ExecQueryAll(q)
		if err != nil {
			return fmt.Errorf("Failed to execute Bind query for %s: %s", q.table, err)
		}
		err = BindAll(rows, q.selectCols, obj)
		if err != nil {
			return fmt.Errorf("Failed to Bind results to object provided for %s: %s", q.table, err)
		}
	} else {
		return fmt.Errorf("Bind given a pointer to a non-slice or non-struct: %s", typ.String())
	}

	return nil
}

// BindOne inserts the returned row columns into the
// passed in object pointer
func BindOne(row *sql.Row, selectCols []string, obj interface{}) error {
	kind := reflect.ValueOf(obj).Kind()
	if kind != reflect.Ptr {
		return fmt.Errorf("BindOne given a non-pointer type")
	}

	pointers := GetStructPointers(obj, selectCols...)
	if err := row.Scan(pointers...); err != nil {
		return fmt.Errorf("Unable to scan into pointers: %s", err)
	}

	return nil
}

// BindAll inserts the returned rows columns into the
// passed in slice of object pointers
func BindAll(rows *sql.Rows, selectCols []string, obj interface{}) error {
	ptrSlice := reflect.ValueOf(obj)
	typ := ptrSlice.Type()
	ptrSlice = ptrSlice.Elem()
	kind := typ.Kind()

	var structTyp reflect.Type

	for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
		if i != 0 {
			typ = typ.Elem()
			kind = typ.Kind()
		}

		if kind != exp {
			return fmt.Errorf("[%d] BindAll object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
		}

		if kind == reflect.Struct {
			structTyp = typ
		}
	}

	for rows.Next() {
		newStruct := reflect.New(structTyp)
		pointers := GetStructPointers(newStruct.Interface(), selectCols...)
		if err := rows.Scan(pointers...); err != nil {
			return fmt.Errorf("Unable to scan into pointers: %s", err)
		}

		ptrSlice.Set(reflect.Append(ptrSlice, newStruct))
	}

	return nil
}

func checkType(obj interface{}) (reflect.Type, bool, error) {
	val := reflect.ValueOf(obj)
	typ := val.Type()
	kind := val.Kind()

	if kind != reflect.Ptr {
		return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
	}

	typ = typ.Elem()
	kind = typ.Kind()
	isSlice := false

	switch kind {
	case reflect.Slice:
		typ = typ.Elem()
		kind = typ.Kind()
		isSlice = true
	case reflect.Struct:
		return typ, isSlice, nil
	default:
		return nil, false, fmt.Errorf("Bind was given an invalid object must be []*T or *T but got type: %s, kind: %s", typ.String(), kind)
	}

	if kind != reflect.Ptr {
		return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
	}

	typ = typ.Elem()
	kind = typ.Kind()

	if kind != reflect.Struct {
		return nil, false, fmt.Errorf("Bind must be a struct but got type: %s, kind: %s", typ.String(), kind)
	}

	return typ, isSlice, nil
}

// GetStructValues returns the values (as interface) of the matching columns in obj
func GetStructValues(obj interface{}, columns ...string) []interface{} {
	ret := make([]interface{}, len(columns))
	val := reflect.Indirect(reflect.ValueOf(obj))

	for i, c := range columns {
		field := val.FieldByName(strmangle.TitleCase(c))
		ret[i] = field.Interface()
	}

	return ret
}

// GetStructPointers returns a slice of pointers to the matching columns in obj
func GetStructPointers(obj interface{}, columns ...string) []interface{} {
	val := reflect.ValueOf(obj).Elem()
	var ret []interface{}

	if len(columns) == 0 {
		fieldsLen := val.NumField()
		ret = make([]interface{}, fieldsLen)
		for i := 0; i < fieldsLen; i++ {
			ret[i] = val.Field(i).Addr().Interface()
		}
		return ret
	}

	ret = make([]interface{}, len(columns))

	for i, c := range columns {
		field := val.FieldByName(strmangle.TitleCase(c))
		if !field.IsValid() {
			panic(fmt.Sprintf("Could not find field on struct %T for field %s", obj, strmangle.TitleCase(c)))
		}

		field = field.Addr()
		ret[i] = field.Interface()
	}

	return ret
}

// RandomizeSlice takes a pointer to a slice of pointers to objects
// and fills the pointed to objects with random data.
// It will ignore the fields in the blacklist.
func RandomizeSlice(obj interface{}, blacklist ...string) error {
	ptrSlice := reflect.ValueOf(obj)
	typ := ptrSlice.Type()
	ptrSlice = ptrSlice.Elem()
	kind := typ.Kind()

	var structTyp reflect.Type

	for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
		if i != 0 {
			typ = typ.Elem()
			kind = typ.Kind()
		}

		if kind != exp {
			return fmt.Errorf("[%d] RandomizeSlice object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
		}

		if kind == reflect.Struct {
			structTyp = typ
		}
	}

	for i := 0; i < ptrSlice.Len(); i++ {
		o := ptrSlice.Index(i)
		o.Set(reflect.New(structTyp))
		if err := RandomizeStruct(o.Interface(), blacklist...); err != nil {
			return err
		}
	}

	return nil
}

// RandomizeStruct takes an object and fills it with random data.
// It will ignore the fields in the blacklist.
func RandomizeStruct(str interface{}, blacklist ...string) error {
	// Don't modify blacklist
	copyBlacklist := make([]string, len(blacklist))
	copy(copyBlacklist, blacklist)
	blacklist = copyBlacklist

	sort.Strings(blacklist)

	// Check if it's pointer
	value := reflect.ValueOf(str)
	kind := value.Kind()
	if kind != reflect.Ptr {
		return fmt.Errorf("Outer element should be a pointer, given a non-pointer: %T", str)
	}

	// Check if it's a struct
	value = value.Elem()
	kind = value.Kind()
	if kind != reflect.Struct {
		return fmt.Errorf("Inner element should be a struct, given a non-struct: %T", str)
	}

	typ := value.Type()
	nFields := value.NumField()

	// Iterate through fields, randomizing
	for i := 0; i < nFields; i++ {
		fieldVal := value.Field(i)
		fieldTyp := typ.Field(i)

		found := sort.Search(len(blacklist), func(i int) bool {
			return blacklist[i] == fieldTyp.Name
		})
		if found != len(blacklist) {
			continue
		}

		if err := randomizeField(fieldVal); err != nil {
			return err
		}
	}

	return nil
}

// randDate generates a random time.Time between 1850 and 2050.
// Only the Day/Month/Year columns are set so that Dates and DateTimes do
// not cause mismatches in the test data comparisons.
func randDate() time.Time {
	t := time.Date(
		1850+rand.Intn(200),
		time.Month(1+rand.Intn(12)),
		1+rand.Intn(25),
		0,
		0,
		0,
		0,
		time.UTC,
	)

	return t
}

func randomizeField(field reflect.Value) error {
	kind := field.Kind()
	typ := field.Type()

	var newVal interface{}

	if kind == reflect.Struct {
		switch typ {
		case typeNullBool:
			newVal = null.NewBool(rand.Intn(2) == 1, rand.Intn(2) == 1)
		case typeNullString:
			newVal = null.NewString(randStr(5+rand.Intn(25)), rand.Intn(2) == 1)
		case typeNullTime:
			newVal = null.NewTime(randDate(), rand.Intn(2) == 1)
		case typeTime:
			newVal = randDate()
		case typeNullFloat32:
			newVal = null.NewFloat32(rand.Float32(), rand.Intn(2) == 1)
		case typeNullFloat64:
			newVal = null.NewFloat64(rand.Float64(), rand.Intn(2) == 1)
		case typeNullInt:
			newVal = null.NewInt(rand.Int(), rand.Intn(2) == 1)
		case typeNullInt8:
			newVal = null.NewInt8(int8(rand.Intn(int(math.MaxInt8))), rand.Intn(2) == 1)
		case typeNullInt16:
			newVal = null.NewInt16(int16(rand.Intn(int(math.MaxInt16))), rand.Intn(2) == 1)
		case typeNullInt32:
			newVal = null.NewInt32(rand.Int31(), rand.Intn(2) == 1)
		case typeNullInt64:
			newVal = null.NewInt64(rand.Int63(), rand.Intn(2) == 1)
		case typeNullUint:
			newVal = null.NewUint(uint(rand.Int()), rand.Intn(2) == 1)
		case typeNullUint8:
			newVal = null.NewUint8(uint8(rand.Intn(int(math.MaxInt8))), rand.Intn(2) == 1)
		case typeNullUint16:
			newVal = null.NewUint16(uint16(rand.Intn(int(math.MaxInt16))), rand.Intn(2) == 1)
		case typeNullUint32:
			newVal = null.NewUint32(uint32(rand.Int31()), rand.Intn(2) == 1)
		case typeNullUint64:
			newVal = null.NewUint64(uint64(rand.Int63()), rand.Intn(2) == 1)
		}
	} else {
		switch kind {
		case reflect.Float32:
			newVal = rand.Float32()
		case reflect.Float64:
			newVal = rand.Float64()
		case reflect.Int:
			newVal = rand.Int()
		case reflect.Int8:
			newVal = int8(rand.Intn(int(math.MaxInt8)))
		case reflect.Int16:
			newVal = int16(rand.Intn(int(math.MaxInt16)))
		case reflect.Int32:
			newVal = rand.Int31()
		case reflect.Int64:
			newVal = rand.Int63()
		case reflect.Uint:
			newVal = uint(rand.Int())
		case reflect.Uint8:
			newVal = uint8(rand.Intn(int(math.MaxInt8)))
		case reflect.Uint16:
			newVal = uint16(rand.Intn(int(math.MaxInt16)))
		case reflect.Uint32:
			newVal = uint32(rand.Int31())
		case reflect.Uint64:
			newVal = uint64(rand.Int63())
		case reflect.Bool:
			var b bool
			if rand.Intn(2) == 1 {
				b = true
			}
			newVal = b
		case reflect.String:
			newVal = randStr(5 + rand.Intn(20))
		case reflect.Slice:
			sliceVal := typ.Elem()
			if sliceVal.Kind() != reflect.Uint8 {
				return fmt.Errorf("unsupported slice type: %T", typ.String())
			}
			newVal = randByteSlice(5 + rand.Intn(20))
		default:
			return fmt.Errorf("unsupported type: %T", typ.String())
		}
	}
	field.Set(reflect.ValueOf(newVal))

	return nil
}

const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randStr(ln int) string {
	str := make([]byte, ln)
	for i := 0; i < ln; i++ {
		str[i] = byte(alphabet[rand.Intn(len(alphabet))])
	}

	return string(str)
}

func randByteSlice(ln int) []byte {
	str := make([]byte, ln)
	for i := 0; i < ln; i++ {
		str[i] = byte(rand.Intn(256))
	}

	return str
}
<commit_msg>Change RandomizeStruct float to single decimal<commit_after>package boil

import (
	"database/sql"
	"fmt"
	"math"
	"math/rand"
	"reflect"
	"sort"
	"time"

	"github.com/nullbio/sqlboiler/strmangle"
	"gopkg.in/nullbio/null.v4"
)

var (
	typeNullFloat32 = reflect.TypeOf(null.Float32{})
	typeNullFloat64 = reflect.TypeOf(null.Float64{})
	typeNullInt     = reflect.TypeOf(null.Int{})
	typeNullInt8    = reflect.TypeOf(null.Int8{})
	typeNullInt16   = reflect.TypeOf(null.Int16{})
	typeNullInt32   = reflect.TypeOf(null.Int32{})
	typeNullInt64   = reflect.TypeOf(null.Int64{})
	typeNullUint    = reflect.TypeOf(null.Uint{})
	typeNullUint8   = reflect.TypeOf(null.Uint8{})
	typeNullUint16  = reflect.TypeOf(null.Uint16{})
	typeNullUint32  = reflect.TypeOf(null.Uint32{})
	typeNullUint64  = reflect.TypeOf(null.Uint64{})
	typeNullString  = reflect.TypeOf(null.String{})
	typeNullBool    = reflect.TypeOf(null.Bool{})
	typeNullTime    = reflect.TypeOf(null.Time{})
	typeTime        = reflect.TypeOf(time.Time{})
)

// Bind executes the query and inserts the
// result into the passed in object pointer
func (q *Query) Bind(obj interface{}) error {
	typ := reflect.TypeOf(obj)
	kind := typ.Kind()

	if kind != reflect.Ptr {
		return fmt.Errorf("Bind not given a pointer to a slice or struct: %s", typ.String())
	}

	typ = typ.Elem()
	kind = typ.Kind()

	if kind == reflect.Struct {
		row := ExecQueryOne(q)
		err := BindOne(row, q.selectCols, obj)
		if err != nil {
			return fmt.Errorf("Failed to execute Bind query for %s: %s", q.table, err)
		}
	} else if kind == reflect.Slice {
		rows, err := ExecQueryAll(q)
		if err != nil {
			return fmt.Errorf("Failed to execute Bind query for %s: %s", q.table, err)
		}
		err = BindAll(rows, q.selectCols, obj)
		if err != nil {
			return fmt.Errorf("Failed to Bind results to object provided for %s: %s", q.table, err)
		}
	} else {
		return fmt.Errorf("Bind given a pointer to a non-slice or non-struct: %s", typ.String())
	}

	return nil
}

// BindOne inserts the returned row columns into the
// passed in object pointer
func BindOne(row *sql.Row, selectCols []string, obj interface{}) error {
	kind := reflect.ValueOf(obj).Kind()
	if kind != reflect.Ptr {
		return fmt.Errorf("BindOne given a non-pointer type")
	}

	pointers := GetStructPointers(obj, selectCols...)
	if err := row.Scan(pointers...); err != nil {
		return fmt.Errorf("Unable to scan into pointers: %s", err)
	}

	return nil
}

// BindAll inserts the returned rows columns into the
// passed in slice of object pointers
func BindAll(rows *sql.Rows, selectCols []string, obj interface{}) error {
	ptrSlice := reflect.ValueOf(obj)
	typ := ptrSlice.Type()
	ptrSlice = ptrSlice.Elem()
	kind := typ.Kind()

	var structTyp reflect.Type

	for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
		if i != 0 {
			typ = typ.Elem()
			kind = typ.Kind()
		}

		if kind != exp {
			return fmt.Errorf("[%d] BindAll object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
		}

		if kind == reflect.Struct {
			structTyp = typ
		}
	}

	for rows.Next() {
		newStruct := reflect.New(structTyp)
		pointers := GetStructPointers(newStruct.Interface(), selectCols...)
		if err := rows.Scan(pointers...); err != nil {
			return fmt.Errorf("Unable to scan into pointers: %s", err)
		}

		ptrSlice.Set(reflect.Append(ptrSlice, newStruct))
	}

	return nil
}

func checkType(obj interface{}) (reflect.Type, bool, error) {
	val := reflect.ValueOf(obj)
	typ := val.Type()
	kind := val.Kind()

	if kind != reflect.Ptr {
		return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
	}

	typ = typ.Elem()
	kind = typ.Kind()
	isSlice := false

	switch kind {
	case reflect.Slice:
		typ = typ.Elem()
		kind = typ.Kind()
		isSlice = true
	case reflect.Struct:
		return typ, isSlice, nil
	default:
		return nil, false, fmt.Errorf("Bind was given an invalid object must be []*T or *T but got type: %s, kind: %s", typ.String(), kind)
	}

	if kind != reflect.Ptr {
		return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
	}

	typ = typ.Elem()
	kind = typ.Kind()

	if kind != reflect.Struct {
		return nil, false, fmt.Errorf("Bind must be a struct but got type: %s, kind: %s", typ.String(), kind)
	}

	return typ, isSlice, nil
}

// GetStructValues returns the values (as interface) of the matching columns in obj
func GetStructValues(obj interface{}, columns ...string) []interface{} {
	ret := make([]interface{}, len(columns))
	val := reflect.Indirect(reflect.ValueOf(obj))

	for i, c := range columns {
		field := val.FieldByName(strmangle.TitleCase(c))
		ret[i] = field.Interface()
	}

	return ret
}

// GetStructPointers returns a slice of pointers to the matching columns in obj
func GetStructPointers(obj interface{}, columns ...string) []interface{} {
	val := reflect.ValueOf(obj).Elem()
	var ret []interface{}

	if len(columns) == 0 {
		fieldsLen := val.NumField()
		ret = make([]interface{}, fieldsLen)
		for i := 0; i < fieldsLen; i++ {
			ret[i] = val.Field(i).Addr().Interface()
		}
		return ret
	}

	ret = make([]interface{}, len(columns))

	for i, c := range columns {
		field := val.FieldByName(strmangle.TitleCase(c))
		if !field.IsValid() {
			panic(fmt.Sprintf("Could not find field on struct %T for field %s", obj, strmangle.TitleCase(c)))
		}

		field = field.Addr()
		ret[i] = field.Interface()
	}

	return ret
}

// RandomizeSlice takes a pointer to a slice of pointers to objects
// and fills the pointed to objects with random data.
// It will ignore the fields in the blacklist.
func RandomizeSlice(obj interface{}, blacklist ...string) error {
	ptrSlice := reflect.ValueOf(obj)
	typ := ptrSlice.Type()
	ptrSlice = ptrSlice.Elem()
	kind := typ.Kind()

	var structTyp reflect.Type

	for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
		if i != 0 {
			typ = typ.Elem()
			kind = typ.Kind()
		}

		if kind != exp {
			return fmt.Errorf("[%d] RandomizeSlice object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
		}

		if kind == reflect.Struct {
			structTyp = typ
		}
	}

	for i := 0; i < ptrSlice.Len(); i++ {
		o := ptrSlice.Index(i)
		o.Set(reflect.New(structTyp))
		if err := RandomizeStruct(o.Interface(), blacklist...); err != nil {
			return err
		}
	}

	return nil
}

// RandomizeStruct takes an object and fills it with random data.
// It will ignore the fields in the blacklist.
func RandomizeStruct(str interface{}, blacklist ...string) error {
	// Don't modify blacklist
	copyBlacklist := make([]string, len(blacklist))
	copy(copyBlacklist, blacklist)
	blacklist = copyBlacklist

	sort.Strings(blacklist)

	// Check if it's pointer
	value := reflect.ValueOf(str)
	kind := value.Kind()
	if kind != reflect.Ptr {
		return fmt.Errorf("Outer element should be a pointer, given a non-pointer: %T", str)
	}

	// Check if it's a struct
	value = value.Elem()
	kind = value.Kind()
	if kind != reflect.Struct {
		return fmt.Errorf("Inner element should be a struct, given a non-struct: %T", str)
	}

	typ := value.Type()
	nFields := value.NumField()

	// Iterate through fields, randomizing
	for i := 0; i < nFields; i++ {
		fieldVal := value.Field(i)
		fieldTyp := typ.Field(i)

		found := sort.Search(len(blacklist), func(i int) bool {
			return blacklist[i] == fieldTyp.Name
		})
		if found != len(blacklist) {
			continue
		}

		if err := randomizeField(fieldVal); err != nil {
			return err
		}
	}

	return nil
}

// randDate generates a random time.Time between 1850 and 2050.
// Only the Day/Month/Year columns are set so that Dates and DateTimes do
// not cause mismatches in the test data comparisons.
func randDate() time.Time {
	t := time.Date(
		1850+rand.Intn(200),
		time.Month(1+rand.Intn(12)),
		1+rand.Intn(25),
		0,
		0,
		0,
		0,
		time.UTC,
	)

	return t
}

func randomizeField(field reflect.Value) error {
	kind := field.Kind()
	typ := field.Type()

	var newVal interface{}

	if kind == reflect.Struct {
		switch typ {
		case typeNullBool:
			newVal = null.NewBool(rand.Intn(2) == 1, rand.Intn(2) == 1)
		case typeNullString:
			newVal = null.NewString(randStr(5+rand.Intn(25)), rand.Intn(2) == 1)
		case typeNullTime:
			newVal = null.NewTime(randDate(), rand.Intn(2) == 1)
		case typeTime:
			newVal = randDate()
		case typeNullFloat32:
			newVal = null.NewFloat32(float32(rand.Intn(9))/10.0, rand.Intn(2) == 1)
		case typeNullFloat64:
			newVal = null.NewFloat64(float64(rand.Intn(9))/10.0, rand.Intn(2) == 1)
		case typeNullInt:
			newVal = null.NewInt(rand.Int(), rand.Intn(2) == 1)
		case typeNullInt8:
			newVal = null.NewInt8(int8(rand.Intn(int(math.MaxInt8))), rand.Intn(2) == 1)
		case typeNullInt16:
			newVal = null.NewInt16(int16(rand.Intn(int(math.MaxInt16))), rand.Intn(2) == 1)
		case typeNullInt32:
			newVal = null.NewInt32(rand.Int31(), rand.Intn(2) == 1)
		case typeNullInt64:
			newVal = null.NewInt64(rand.Int63(), rand.Intn(2) == 1)
		case typeNullUint:
			newVal = null.NewUint(uint(rand.Int()), rand.Intn(2) == 1)
		case typeNullUint8:
			newVal = null.NewUint8(uint8(rand.Intn(int(math.MaxInt8))), rand.Intn(2) == 1)
		case typeNullUint16:
			newVal = null.NewUint16(uint16(rand.Intn(int(math.MaxInt16))), rand.Intn(2) == 1)
		case typeNullUint32:
			newVal = null.NewUint32(uint32(rand.Int31()), rand.Intn(2) == 1)
		case typeNullUint64:
			newVal = null.NewUint64(uint64(rand.Int63()), rand.Intn(2) == 1)
		}
	} else {
		switch kind {
		case reflect.Float32:
			newVal = float32(rand.Intn(9)) / 10.0
		case reflect.Float64:
			newVal = float64(rand.Intn(9)) / 10.0
		case reflect.Int:
			newVal = rand.Int()
		case reflect.Int8:
			newVal = int8(rand.Intn(int(math.MaxInt8)))
		case reflect.Int16:
			newVal = int16(rand.Intn(int(math.MaxInt16)))
		case reflect.Int32:
			newVal = rand.Int31()
		case reflect.Int64:
			newVal = rand.Int63()
		case reflect.Uint:
			newVal = uint(rand.Int())
		case reflect.Uint8:
			newVal = uint8(rand.Intn(int(math.MaxInt8)))
		case reflect.Uint16:
			newVal = uint16(rand.Intn(int(math.MaxInt16)))
		case reflect.Uint32:
			newVal = uint32(rand.Int31())
		case reflect.Uint64:
			newVal = uint64(rand.Int63())
		case reflect.Bool:
			var b bool
			if rand.Intn(2) == 1 {
				b = true
			}
			newVal = b
		case reflect.String:
			newVal = randStr(5 + rand.Intn(20))
		case reflect.Slice:
			sliceVal := typ.Elem()
			if sliceVal.Kind() != reflect.Uint8 {
				return fmt.Errorf("unsupported slice type: %T", typ.String())
			}
			newVal = randByteSlice(5 + rand.Intn(20))
		default:
			return fmt.Errorf("unsupported type: %T", typ.String())
		}
	}
	field.Set(reflect.ValueOf(newVal))

	return nil
}

const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randStr(ln int) string {
	str := make([]byte, ln)
	for i := 0; i < ln; i++ {
		str[i] = byte(alphabet[rand.Intn(len(alphabet))])
	}

	return string(str)
}

func randByteSlice(ln int) []byte {
	str := make([]byte, ln)
	for i := 0; i < ln; i++ {
		str[i] = byte(rand.Intn(256))
	}

	return str
}
<|endoftext|>


<commit_before>// Package versionhack makes sure go/build doesn't disable module support
// whenever GopherJS is compiled by a different Go version than it's targeted
// Go version.
//
// Under the hood, go/build relies on `go list` utility for module support; more
// specifically, for package location discovery. Since ReleaseTags are
// effectively baked into the go binary and can't be overridden, it needs to
// ensure that ReleaseTags set in a go/build.Context instance match the Go tool.
//
// However, it naively assumes that the go tool version in the PATH matches the
// version that was used to build GopherJS and disables module support whenever
// ReleaseTags in the context are set to anything other than the default. This,
// unfortunately, isn't very helpful since gopherjs may be built by a Go version
// other than the PATH's default.
//
// Luckily, even if go tool version is mismatched, it's only used for discovery
// of the package locations, and go/build evaluates build constraints on its own
// with ReleaseTags we've passed.
//
// A better solution would've been for go/build to use go tool from GOROOT and
// check its version against build tags: https://github.com/golang/go/issues/46856.
//
// Until that issue is fixed, we trick go/build into thinking that whatever
// ReleaseTags we've passed are indeed the default. We gain access to the
// variable go/build checks against using "go:linkname" directive and override
// its content as we wish.
package versionhack

import (
	"go/build" // Must be initialized before this package.

	"github.com/gopherjs/gopherjs/compiler"

	_ "unsafe" // For go:linkname
)

//go:linkname releaseTags go/build.defaultReleaseTags
var releaseTags []string

func init() {
	releaseTags = build.Default.ReleaseTags[:compiler.GoVersion]
}
<commit_msg>Hack around go/build.defaultToolTags<commit_after>// Package versionhack makes sure go/build doesn't disable module support
// whenever GopherJS is compiled by a different Go version than it's targeted
// Go version.
//
// Under the hood, go/build relies on `go list` utility for module support; more
// specifically, for package location discovery. Since ReleaseTags are
// effectively baked into the go binary and can't be overridden, it needs to
// ensure that ReleaseTags set in a go/build.Context instance match the Go tool.
//
// However, it naively assumes that the go tool version in the PATH matches the
// version that was used to build GopherJS and disables module support whenever
// ReleaseTags in the context are set to anything other than the default. This,
// unfortunately, isn't very helpful since gopherjs may be built by a Go version
// other than the PATH's default.
//
// Luckily, even if go tool version is mismatched, it's only used for discovery
// of the package locations, and go/build evaluates build constraints on its own
// with ReleaseTags we've passed.
//
// A better solution would've been for go/build to use go tool from GOROOT and
// check its version against build tags: https://github.com/golang/go/issues/46856.
//
// Until that issue is fixed, we trick go/build into thinking that whatever
// ReleaseTags we've passed are indeed the default. We gain access to the
// variable go/build checks against using "go:linkname" directive and override
// its content as we wish.
package versionhack

import (
	"go/build" // Must be initialized before this package.

	"github.com/gopherjs/gopherjs/compiler"

	_ "unsafe" // For go:linkname
)

//go:linkname releaseTags go/build.defaultReleaseTags
var releaseTags []string

//go:linkname toolTags go/build.defaultToolTags
var toolTags []string

func init() {
	releaseTags = build.Default.ReleaseTags[:compiler.GoVersion]
	toolTags = []string{}
}
<|endoftext|>