<commit_before>package aws

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "running",
		Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout: 10 * time.Minute,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:  "terminated",
		Refresh: InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout: 10 * time.Minute,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<commit_msg>aws: Expose host in the ConnInfo<commit_after>package aws

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "running",
		Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout: 10 * time.Minute,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Initialize the connection info
	rs.ConnInfo.Raw["type"] = "ssh"
	rs.ConnInfo.Raw["host"] = instance.PublicIpAddress

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:  "terminated",
		Refresh: InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout: 10 * time.Minute,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<|endoftext|>


<commit_before>package l10n

import (
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

var Global = "global"

type Interface interface {
	IsGlobal() bool
	SetLocale(locale string)
}

type Locale struct {
	LanguageCode string `sql:"size:6" gorm:"primary_key"`
}

func (l Locale) IsGlobal() bool {
	return l.LanguageCode == Global
}

func (l *Locale) SetLocale(locale string) {
	l.LanguageCode = locale
}

type AvailableLocalesInterface interface {
	AvailableLocales() []string
}

type ViewableLocalesInterface interface {
	ViewableLocales() []string
}

type EditableLocalesInterface interface {
	EditableLocales() []string
}

func GetAvailableLocales(req *http.Request, currentUser qor.CurrentUser) []string {
	if user, ok := currentUser.(ViewableLocalesInterface); ok {
		return user.ViewableLocales()
	}

	if user, ok := currentUser.(AvailableLocalesInterface); ok {
		return user.AvailableLocales()
	}
	return []string{}
}

func GetEditableLocales(req *http.Request, currentUser qor.CurrentUser) []string {
	if user, ok := currentUser.(EditableLocalesInterface); ok {
		return user.EditableLocales()
	}

	if user, ok := currentUser.(AvailableLocalesInterface); ok {
		return user.AvailableLocales()
	}
	return []string{}
}

func getLocaleFromContext(context *qor.Context) string {
	if locale := context.Request.Form.Get("locale"); locale != "" {
		if context.Writer != nil {
			cookie := http.Cookie{Name: "locale", Value: locale, Expires: time.Now().AddDate(1, 0, 0)}
			http.SetCookie(context.Writer, &cookie)
		}
		return locale
	}

	if locale, err := context.Request.Cookie("locale"); err == nil {
		return locale.Value
	}

	return Global
}

func (l *Locale) InjectQorAdmin(res *admin.Resource) {
	for _, gopath := range strings.Split(os.Getenv("GOPATH"), ":") {
		admin.RegisterViewPath(path.Join(gopath, "src/github.com/qor/qor/l10n/views"))
	}

	if res.Config == nil {
		res.Config = &admin.Config{}
	}
	if res.Config.Permission == nil {
		res.Config.Permission = roles.NewPermission()
	}

	res.Meta(&admin.Meta{Name: "LanguageCode", Type: "hidden"})

	res.Config.Theme = "l10n"
	res.Config.Permission.Allow(roles.CRUD, "locale_admin").Allow(roles.Read, "locale_reader")

	searcher := res.Searcher
	res.Searcher = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return searcher(result, context)
	}

	finder := res.Finder
	res.Finder = func(result interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return finder(result, metaValues, context)
	}

	saver := res.Saver
	res.Saver = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return saver(result, context)
	}

	deleter := res.Deleter
	res.Deleter = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return deleter(result, context)
	}

	res.GetAdmin().RegisterFuncMap("current_locale", func(context admin.Context) string {
		return getLocaleFromContext(context.Context)
	})

	res.GetAdmin().RegisterFuncMap("viewable_locales", func(context admin.Context) []string {
		return GetAvailableLocales(context.Request, context.CurrentUser)
	})

	res.GetAdmin().RegisterFuncMap("editable_locales", func(context admin.Context) []string {
		return GetEditableLocales(context.Request, context.CurrentUser)
	})

	res.GetAdmin().RegisterFuncMap("createable_locales", func(context admin.Context) []string {
		editableLocales := GetEditableLocales(context.Request, context.CurrentUser)
		if _, ok := context.Resource.Value.(LocaleCreateableInterface); ok {
			return editableLocales
		} else {
			for _, locale := range editableLocales {
				if locale == Global {
					return []string{Global}
				}
			}
		}
		return []string{}
	})

	res.GetAdmin().RegisterFuncMap("locales_of_resource", func(resource interface{}, context admin.Context) []map[string]interface{} {
		scope := context.GetDB().NewScope(resource)
		var languageCodes []string
		context.GetDB().New().Model(resource).Where(fmt.Sprintf("%v = ?", scope.PrimaryKey()), scope.PrimaryKeyValue()).Pluck("language_code", &languageCodes)

		var results []map[string]interface{}
		availableLocales := GetAvailableLocales(context.Request, context.CurrentUser)
	OUT:
		for _, locale := range availableLocales {
			for _, localized := range languageCodes {
				if locale == localized {
					results = append(results, map[string]interface{}{"locale": locale, "localized": true})
					continue OUT
				}
			}
			results = append(results, map[string]interface{}{"locale": locale, "localized": false})
		}
		return results
	})

	role := res.Config.Permission.Role
	if _, ok := role.Get("locale_admin"); !ok {
		role.Register("locale_admin", func(req *http.Request, currentUser qor.CurrentUser) bool {
			currentLocale := getLocaleFromContext(&qor.Context{Request: req})
			for _, locale := range GetEditableLocales(req, currentUser) {
				if locale == currentLocale {
					return true
				}
			}
			return false
		})

		role.Register("locale_reader", func(req *http.Request, currentUser qor.CurrentUser) bool {
			currentLocale := getLocaleFromContext(&qor.Context{Request: req})
			for _, locale := range GetAvailableLocales(req, currentUser) {
				if locale == currentLocale {
					return true
				}
			}
			return false
		})
	}
}
<commit_msg>Fix Set locale<commit_after>package l10n

import (
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

var Global = "global"

type Interface interface {
	IsGlobal() bool
	SetLocale(locale string)
}

type Locale struct {
	LanguageCode string `sql:"size:6" gorm:"primary_key"`
}

func (l Locale) IsGlobal() bool {
	return l.LanguageCode == Global
}

func (l *Locale) SetLocale(locale string) {
	l.LanguageCode = locale
}

type AvailableLocalesInterface interface {
	AvailableLocales() []string
}

type ViewableLocalesInterface interface {
	ViewableLocales() []string
}

type EditableLocalesInterface interface {
	EditableLocales() []string
}

func GetAvailableLocales(req *http.Request, currentUser qor.CurrentUser) []string {
	if user, ok := currentUser.(ViewableLocalesInterface); ok {
		return user.ViewableLocales()
	}

	if user, ok := currentUser.(AvailableLocalesInterface); ok {
		return user.AvailableLocales()
	}
	return []string{}
}

func GetEditableLocales(req *http.Request, currentUser qor.CurrentUser) []string {
	if user, ok := currentUser.(EditableLocalesInterface); ok {
		return user.EditableLocales()
	}

	if user, ok := currentUser.(AvailableLocalesInterface); ok {
		return user.AvailableLocales()
	}
	return []string{}
}

func getLocaleFromContext(context *qor.Context) string {
	if locale := context.Request.Form.Get("locale"); locale != "" {
		if context.Writer != nil {
			cookie := http.Cookie{Name: "locale", Value: locale, Expires: time.Now().AddDate(1, 0, 0), Path: "/"}
			http.SetCookie(context.Writer, &cookie)
		}
		return locale
	}

	if locale, err := context.Request.Cookie("locale"); err == nil {
		return locale.Value
	}

	return Global
}

func (l *Locale) InjectQorAdmin(res *admin.Resource) {
	for _, gopath := range strings.Split(os.Getenv("GOPATH"), ":") {
		admin.RegisterViewPath(path.Join(gopath, "src/github.com/qor/qor/l10n/views"))
	}

	if res.Config == nil {
		res.Config = &admin.Config{}
	}
	if res.Config.Permission == nil {
		res.Config.Permission = roles.NewPermission()
	}

	res.Meta(&admin.Meta{Name: "LanguageCode", Type: "hidden"})

	res.Config.Theme = "l10n"
	res.Config.Permission.Allow(roles.CRUD, "locale_admin").Allow(roles.Read, "locale_reader")

	searcher := res.Searcher
	res.Searcher = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return searcher(result, context)
	}

	finder := res.Finder
	res.Finder = func(result interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return finder(result, metaValues, context)
	}

	saver := res.Saver
	res.Saver = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return saver(result, context)
	}

	deleter := res.Deleter
	res.Deleter = func(result interface{}, context *qor.Context) error {
		context.SetDB(context.GetDB().Set("l10n:locale", getLocaleFromContext(context)))
		return deleter(result, context)
	}

	res.GetAdmin().RegisterFuncMap("current_locale", func(context admin.Context) string {
		return getLocaleFromContext(context.Context)
	})

	res.GetAdmin().RegisterFuncMap("viewable_locales", func(context admin.Context) []string {
		return GetAvailableLocales(context.Request, context.CurrentUser)
	})

	res.GetAdmin().RegisterFuncMap("editable_locales", func(context admin.Context) []string {
		return GetEditableLocales(context.Request, context.CurrentUser)
	})

	res.GetAdmin().RegisterFuncMap("createable_locales", func(context admin.Context) []string {
		editableLocales := GetEditableLocales(context.Request, context.CurrentUser)
		if _, ok := context.Resource.Value.(LocaleCreateableInterface); ok {
			return editableLocales
		} else {
			for _, locale := range editableLocales {
				if locale == Global {
					return []string{Global}
				}
			}
		}
		return []string{}
	})

	res.GetAdmin().RegisterFuncMap("locales_of_resource", func(resource interface{}, context admin.Context) []map[string]interface{} {
		scope := context.GetDB().NewScope(resource)
		var languageCodes []string
		context.GetDB().New().Model(resource).Where(fmt.Sprintf("%v = ?", scope.PrimaryKey()), scope.PrimaryKeyValue()).Pluck("language_code", &languageCodes)

		var results []map[string]interface{}
		availableLocales := GetAvailableLocales(context.Request, context.CurrentUser)
	OUT:
		for _, locale := range availableLocales {
			for _, localized := range languageCodes {
				if locale == localized {
					results = append(results, map[string]interface{}{"locale": locale, "localized": true})
					continue OUT
				}
			}
			results = append(results, map[string]interface{}{"locale": locale, "localized": false})
		}
		return results
	})

	role := res.Config.Permission.Role
	if _, ok := role.Get("locale_admin"); !ok {
		role.Register("locale_admin", func(req *http.Request, currentUser qor.CurrentUser) bool {
			currentLocale := getLocaleFromContext(&qor.Context{Request: req})
			for _, locale := range GetEditableLocales(req, currentUser) {
				if locale == currentLocale {
					return true
				}
			}
			return false
		})

		role.Register("locale_reader", func(req *http.Request, currentUser qor.CurrentUser) bool {
			currentLocale := getLocaleFromContext(&qor.Context{Request: req})
			for _, locale := range GetAvailableLocales(req, currentUser) {
				if locale == currentLocale {
					return true
				}
			}
			return false
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

const rapidSize = 250 * 1024
const rapidFPS = 25

var port int
var crt, key string
var host string
var s string
var ports string
var _case string

func main() {

	flag.StringVar(&crt, "crt", "", "ssl cert file")
	flag.StringVar(&key, "key", "", "ssl key file")
	flag.StringVar(&host, "host", "localhost", "listening server host")
	flag.StringVar(&_case, "case", "", "choose a specialized case, (hang,rapid)")
	flag.IntVar(&port, "port", 6789, "listening server port")
	flag.Parse()

	if crt != "" || key != "" {
		s = "s"
		if port != 443 {
			ports = fmt.Sprintf(":%d", port)
		}
	} else if port != 80 {
		ports = fmt.Sprintf(":%d", port)
	}
	http.HandleFunc("/client", client)
	http.HandleFunc("/echo", socket)
	log.Printf("Running server on %s:%d\n", host, port)
	switch _case {
	default:
		log.Fatalf("case: %s is unknown", _case)
	case "":
	case "hang":
		log.Printf("case: %s (long connection hanging)\n", _case)
	case "rapid":
		log.Printf("case: %s (rapid (250 fps) large (2048 bytes) random text messages)\n", _case)
	}
	log.Printf("ws%s://%s%s/echo      (echo socket)\n", s, host, ports)
	log.Printf("http%s://%s%s/client  (javascript test client)\n", s, host, ports)
	var err error
	if crt != "" || key != "" {
		err = http.ListenAndServeTLS(fmt.Sprintf(":%d", port), crt, key, nil)
	} else {
		err = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	}
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func socket(w http.ResponseWriter, r *http.Request) {
	log.Print("connection established")
	if _case == "hang" {
		hang := time.Minute
		log.Printf("hanging for %s\n", hang.String())
		time.Sleep(hang)
	}
	ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	if err != nil {
		log.Print(err)
		return
	}
	defer func() {
		ws.Close()
		log.Print("connection closed")
	}()
	var mu sync.Mutex
	go func() {
		defer func() {
			ws.Close()
		}()
		msg := make([]byte, rapidSize)
		b := make([]byte, 2048)
		for {
			time.Sleep(time.Second / rapidFPS)
			i := 0
		outer:
			for {
				rand.Read(b)
				for _, c := range b {
					if i == len(msg) {
						break outer
					}
					msg[i] = (c % (126 - 32)) + 32 // ascii #32-126
					i++
				}
			}
			copy(msg, []byte(time.Now().String()+"\n"))
			mu.Lock()
			if err := ws.WriteMessage(websocket.TextMessage, msg); err != nil {
				mu.Unlock()
				return
			}
			mu.Unlock()
		}
	}()
	for {
		msgt, msg, err := ws.ReadMessage()
		if err != nil {
			log.Print(err)
			return
		}
		log.Print("rcvd: '" + string(msg) + "'")
		mu.Lock()
		ws.WriteMessage(msgt, msg)
		mu.Unlock()
	}
}

func client(w http.ResponseWriter, r *http.Request) {
	log.Print("client request")
	w.Header().Set("Content-Type", "text/html")
	if _case != "" {
		fmt.Fprintf(w, "
["+_case+"]
")
	}

	io.WriteString(w, `

		`)

}
<commit_msg>added pong test case<commit_after>package main

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

const rapidSize = 250 * 1024
const rapidFPS = 25

var port int
var crt, key string
var host string
var s string
var ports string
var _case string

func main() {

	flag.StringVar(&crt, "crt", "", "ssl cert file")
	flag.StringVar(&key, "key", "", "ssl key file")
	flag.StringVar(&host, "host", "localhost", "listening server host")
	flag.StringVar(&_case, "case", "", "choose a specialized case, (hang,rapid,pong)")
	flag.IntVar(&port, "port", 6789, "listening server port")
	flag.Parse()

	if crt != "" || key != "" {
		s = "s"
		if port != 443 {
			ports = fmt.Sprintf(":%d", port)
		}
	} else if port != 80 {
		ports = fmt.Sprintf(":%d", port)
	}
	http.HandleFunc("/client", client)
	http.HandleFunc("/echo", socket)
	log.Printf("Running server on %s:%d\n", host, port)
	switch _case {
	default:
		log.Fatalf("case: %s is unknown", _case)
	case "":
	case "hang":
		log.Printf("case: %s (long connection hanging)\n", _case)
	case "rapid":
		log.Printf("case: %s (rapid (250 fps) large (2048 bytes) random text messages)\n", _case)
	case "pong":
		log.Printf("case: pong (send pong events every 3 seconds)\n")
	}
	log.Printf("ws%s://%s%s/echo      (echo socket)\n", s, host, ports)
	log.Printf("http%s://%s%s/client  (javascript test client)\n", s, host, ports)
	var err error
	if crt != "" || key != "" {
		err = http.ListenAndServeTLS(fmt.Sprintf(":%d", port), crt, key, nil)
	} else {
		err = http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
	}
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func socket(w http.ResponseWriter, r *http.Request) {
	log.Print("connection established")
	if _case == "hang" {
		hang := time.Minute
		log.Printf("hanging for %s\n", hang.String())
		time.Sleep(hang)
	}
	ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	if err != nil {
		log.Print(err)
		return
	}
	defer func() {
		ws.Close()
		log.Print("connection closed")
	}()
	var mu sync.Mutex
	if _case == "rapid" {
		go func() {
			defer func() {
				ws.Close()
			}()
			msg := make([]byte, rapidSize)
			b := make([]byte, 2048)
			for {
				time.Sleep(time.Second / rapidFPS)
				i := 0
			outer:
				for {
					rand.Read(b)
					for _, c := range b {
						if i == len(msg) {
							break outer
						}
						msg[i] = (c % (126 - 32)) + 32 // ascii #32-126
						i++
					}
				}
				copy(msg, []byte(time.Now().String()+"\n"))
				mu.Lock()
				if err := ws.WriteMessage(websocket.TextMessage, msg); err != nil {
					mu.Unlock()
					return
				}
				mu.Unlock()
			}
		}()
	}
	if _case == "pong" {
		go func() {
			defer ws.Close()
			i := 0
			for range time.NewTicker(time.Second).C {
				mu.Lock()
				err := ws.WriteControl(websocket.PongMessage,
					[]byte(fmt.Sprintf("PONG:%d", i)), time.Now().Add(time.Second))
				mu.Unlock()
				if err != nil {
					return
				}
				i++
			}
		}()
	}
	for {
		msgt, msg, err := ws.ReadMessage()
		if err != nil {
			log.Print(err)
			return
		}
		log.Print("rcvd: '" + string(msg) + "'")
		time.Sleep(time.Second / 10)
		mu.Lock()
		ws.WriteMessage(msgt, msg)
		mu.Unlock()
	}
}

func client(w http.ResponseWriter, r *http.Request) {
	log.Print("client request")
	w.Header().Set("Content-Type", "text/html")
	if _case != "" {
		fmt.Fprintf(w, "
["+_case+"]
")
	}

	io.WriteString(w, `

		`)

}
<|endoftext|>


<commit_before>package xkcd

import (
	"testing"
)

func TestFixEncoding(t *testing.T) {
	inputs := []string{
		"\u00f0\u009f\u0098\u00b0",
		"\xf0\x9f\x98\xb0",
	}
	expects := []string{
		"\U0001f630",
		"\U0001f630",
	}

	if len(inputs) != len(expects) {
		panic("len(inputs) != len(expects)")
	}

	for i := 0; i < len(inputs); i++ {
		input := inputs[i]
		expect := expects[i]

		actual := fixEncoding(input)

		t.Logf("fix(%+q)=%+q, expect=%+q", input, actual, expect)
		if actual != expect {
			t.Fail()
		}
	}
}
<commit_msg>Check utf8.ValidString in encoding_test.go.<commit_after>package xkcd

import (
	"testing"
	"unicode/utf8"
)

func TestFixEncoding(t *testing.T) {
	inputs := []string{
		"\u00f0\u009f\u0098\u00b0",
		"\xf0\x9f\x98\xb0",
	}
	expects := []string{
		"\U0001f630",
		"\U0001f630",
	}

	if len(inputs) != len(expects) {
		panic("len(inputs) != len(expects)")
	}

	for i := 0; i < len(inputs); i++ {
		input := inputs[i]
		expect := expects[i]

		actual := fixEncoding(input)

		t.Logf("fix(%+q)=%+q, expect=%+q", input, actual, expect)

		if !utf8.ValidString(actual) {
			t.Errorf("%+q isn't valid utf-8", actual)
		}

		if !utf8.ValidString(expect) {
			t.Errorf("%+q isn't valid utf-8", expect)
		}

		if actual != expect {
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package peco

import (
	"fmt"
	"time"
	"unicode/utf8"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

type VerticalAnchor int

const (
	AnchorTop VerticalAnchor = iota + 1
	AnchorBottom
)

type Layout interface {
	ClearStatus(time.Duration)
	PrintStatus(string)
	DrawScreen([]Match)
}

// Utility function
func mergeAttribute(a, b termbox.Attribute) termbox.Attribute {
	if a&0x0F == 0 || b&0x0F == 0 {
		return a | b
	} else {
		return ((a - 1) | (b - 1)) + 1
	}
}

// Utility function
func printScreen(x, y int, fg, bg termbox.Attribute, msg string, fill bool) {
	for len(msg) > 0 {
		c, w := utf8.DecodeRuneInString(msg)
		if c == utf8.RuneError {
			c = '?'
			w = 1
		}
		msg = msg[w:]
		termbox.SetCell(x, y, c, fg, bg)
		x += runewidth.RuneWidth(c)
	}

	if !fill {
		return
	}

	width, _ := termbox.Size()
	for ; x < width; x++ {
		termbox.SetCell(x, y, ' ', fg, bg)
	}
}

// UserPrompt draws the prompt line
type UserPrompt struct {
	*Ctx
	anchor       VerticalAnchor // AnchorTop or AnchorBottom
	anchorOffset int            // offset this many lines from the anchor
	prefix       string
	prefixLen    int
}

func NewUserPrompt(ctx *Ctx, anchor VerticalAnchor, anchorOffset int) *UserPrompt {
	prefix := ctx.config.Prompt
	if len(prefix) <= 0 { // default
		prefix = "QUERY>"
	}
	prefixLen := runewidth.StringWidth(prefix)

	return &UserPrompt{
		Ctx:          ctx,
		anchor:       anchor,
		anchorOffset: anchorOffset,
		prefix:       prefix,
		prefixLen:    prefixLen,
	}
}

func (u UserPrompt) Draw() {
	// print "QUERY>"

	_, h := termbox.Size()

	var location int
	switch u.anchor {
	case AnchorTop:
		location = u.anchorOffset
	case AnchorBottom:
		location = h - u.anchorOffset - 1 // -1 is required because y is 0 base, but h is 1 base
	default:
		panic("Unknown anchor type!")
	}

	printScreen(0, location, u.config.Style.BasicFG(), u.config.Style.BasicBG(), u.prefix, false)

	if u.caretPos <= 0 {
		u.caretPos = 0 // sanity
	}

	if u.caretPos > len(u.query) {
		u.caretPos = len(u.query)
	}

	if u.caretPos == len(u.query) {
		// the entire string + the caret after the string
		fg := u.config.Style.QueryFG()
		bg := u.config.Style.QueryBG()
		qs := string(u.query)
		ql := runewidth.StringWidth(qs)
		printScreen(u.prefixLen+1, location, fg, bg, qs, false)
		printScreen(u.prefixLen+1+ql, location, fg|termbox.AttrReverse, bg|termbox.AttrReverse, " ", false)
		printScreen(u.prefixLen+1+ql+1, location, fg, bg, "", true)
	} else {
		// the caret is in the middle of the string
		prev := 0
		fg := u.config.Style.QueryFG()
		bg := u.config.Style.QueryBG()
		for i, r := range u.query {
			if i == u.caretPos {
				fg |= termbox.AttrReverse
				bg |= termbox.AttrReverse
			}
			termbox.SetCell(u.prefixLen+1+prev, location, r, fg, bg)
			prev += runewidth.RuneWidth(r)
		}
	}

	width, _ := termbox.Size()

	pmsg := fmt.Sprintf("%s [%d/%d]", u.Matcher().String(), u.currentPage.index, u.maxPage)
	printScreen(width-runewidth.StringWidth(pmsg), location, u.config.Style.BasicFG(), u.config.Style.BasicBG(), pmsg, false)
}

// StatusBar draws the status message bar
type StatusBar struct {
	*Ctx
	clearTimer *time.Timer
}

func NewStatusBar(ctx *Ctx) *StatusBar {
	return &StatusBar{
		ctx,
		nil,
	}
}

func (s *StatusBar) stopTimer() {
	if t := s.clearTimer; t != nil {
		t.Stop()
	}
}

func (s *StatusBar) ClearStatus(d time.Duration) {
	s.stopTimer()
	s.clearTimer = time.AfterFunc(d, func() {
		s.PrintStatus("")
	})
}

func (s *StatusBar) PrintStatus(msg string) {
	s.stopTimer()

	w, h := termbox.Size()

	width := runewidth.StringWidth(msg)
	for width > w {
		_, rw := utf8.DecodeRuneInString(msg)
		width = width - rw
		msg = msg[rw:]
	}

	var pad []byte
	if w > width {
		pad = make([]byte, w-width)
		for i := 0; i < w-width; i++ {
			pad[i] = ' '
		}
	}

	fgAttr := s.config.Style.BasicFG()
	bgAttr := s.config.Style.BasicBG()

	if w > width {
		printScreen(0, h-1, fgAttr, bgAttr, string(pad), false)
	}

	if width > 0 {
		printScreen(w-width, h-1, fgAttr|termbox.AttrReverse|termbox.AttrBold, bgAttr|termbox.AttrReverse, msg, false)
	}
	termbox.Flush()
}

type ListArea struct {
	*Ctx
	sortTopDown bool
	start       int
}

func NewListArea(ctx *Ctx) *ListArea {
	return &ListArea{
		ctx,
		true,
		1,
	}
}

// given the n-th element to display, calculate which y offset that line should
// be displayed at
func (l *ListArea) calcYLocation(n int) int {
	if l.sortTopDown {
		return n + l.start
	}
	return l.start - n
}

func (l *ListArea) Draw(targets []Match, perPage int) {
	currentPage := l.currentPage

	var fgAttr, bgAttr termbox.Attribute
	for n := 0; n < perPage; n++ {
		switch {
		case n+currentPage.offset == l.currentLine-l.start:
			fgAttr = l.config.Style.SelectedFG()
			bgAttr = l.config.Style.SelectedBG()
		case l.selection.Has(n+currentPage.offset) || l.SelectedRange().Has(n+currentPage.offset):
			fgAttr = l.config.Style.SavedSelectionFG()
			bgAttr = l.config.Style.SavedSelectionBG()
		default:
			fgAttr = l.config.Style.BasicFG()
			bgAttr = l.config.Style.BasicBG()
		}

		targetIdx := currentPage.offset + n
		if targetIdx >= len(targets) {
			break
		}

		y := l.calcYLocation(n)

		target := targets[targetIdx]
		line := target.Line()
		matches := target.Indices()
		if matches == nil {
			printScreen(0, y, fgAttr, bgAttr, line, true)
		} else {
			prev := 0
			index := 0
			for _, m := range matches {
				if m[0] > index {
					c := line[index:m[0]]
					printScreen(prev, y, fgAttr, bgAttr, c, false)
					prev += runewidth.StringWidth(c)
					index += len(c)
				}
				c := line[m[0]:m[1]]
				printScreen(prev, y, l.config.Style.MatchedFG(), mergeAttribute(bgAttr, l.config.Style.MatchedBG()), c, true)
				prev += runewidth.StringWidth(c)
				index += len(c)
			}

			m := matches[len(matches)-1]
			if m[0] > index {
				printScreen(prev, y, l.config.Style.QueryFG(), mergeAttribute(bgAttr, l.config.Style.QueryBG()), line[m[0]:m[1]], true)
			} else if len(line) > m[1] {
				printScreen(prev, y, fgAttr, bgAttr, line[m[1]:len(line)], true)
			}
		}
	}
}

type basicLayout struct {
	*Ctx
	*StatusBar
	prompt *UserPrompt
	list   *ListArea
}

// DefaultLayout implements the top-down layout
type DefaultLayout struct {
	*basicLayout
}
type BottomUpLayout struct {
	*basicLayout
}

func NewDefaultLayout(ctx *Ctx) *DefaultLayout {
	return &DefaultLayout{
		&basicLayout{
			Ctx:       ctx,
			StatusBar: NewStatusBar(ctx),
			prompt:    NewUserPrompt(ctx, AnchorTop, 0),
			list:      NewListArea(ctx),
		},
	}
}

func (l *DefaultLayout) CalculatePage(targets []Match, perPage int) error {
CALCULATE_PAGE:
	currentPage := l.currentPage
	currentPage.index = ((l.currentLine - 1) / perPage) + 1
	if currentPage.index <= 0 {
		currentPage.index = 1
	}
	currentPage.offset = (currentPage.index - 1) * perPage
	currentPage.perPage = perPage
	if len(targets) == 0 {
		l.maxPage = 1
	} else {
		l.maxPage = ((len(targets) + perPage - 1) / perPage)
	}

	if l.maxPage < currentPage.index {
		if len(targets) == 0 && len(l.query) == 0 {
			// wait for targets
			return fmt.Errorf("no targets or query. nothing to do")
		}
		l.currentLine = currentPage.offset
		goto CALCULATE_PAGE
	}

	return nil
}

func (l *DefaultLayout) DrawScreen(targets []Match) {
	fgAttr := l.config.Style.BasicFG()
	bgAttr := l.config.Style.BasicBG()

	if err := termbox.Clear(fgAttr, bgAttr); err != nil {
		return
	}

	if l.currentLine > len(targets) && len(targets) > 0 {
		l.currentLine = len(targets)
	}

	_, height := termbox.Size()
	perPage := height - 4

	if err := l.CalculatePage(targets, perPage); err != nil {
		return
	}

	l.prompt.Draw()
	l.list.Draw(targets, perPage)
	if err := termbox.Flush(); err != nil {
		return
	}
}
<commit_msg>Change everything to use anchors via AnchorSettings<commit_after>package peco

import (
	"fmt"
	"time"
	"unicode/utf8"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

type VerticalAnchor int

const (
	AnchorTop VerticalAnchor = iota + 1
	AnchorBottom
)

type Layout interface {
	ClearStatus(time.Duration)
	PrintStatus(string)
	DrawScreen([]Match)
}

// Utility function
func mergeAttribute(a, b termbox.Attribute) termbox.Attribute {
	if a&0x0F == 0 || b&0x0F == 0 {
		return a | b
	} else {
		return ((a - 1) | (b - 1)) + 1
	}
}

// Utility function
func printScreen(x, y int, fg, bg termbox.Attribute, msg string, fill bool) {
	for len(msg) > 0 {
		c, w := utf8.DecodeRuneInString(msg)
		if c == utf8.RuneError {
			c = '?'
			w = 1
		}
		msg = msg[w:]
		termbox.SetCell(x, y, c, fg, bg)
		x += runewidth.RuneWidth(c)
	}

	if !fill {
		return
	}

	width, _ := termbox.Size()
	for ; x < width; x++ {
		termbox.SetCell(x, y, ' ', fg, bg)
	}
}

type AnchorSettings struct {
	anchor       VerticalAnchor // AnchorTop or AnchorBottom
	anchorOffset int            // offset this many lines from the anchor
}

// AnchorPosition returns the starting y-offset, based on the
// anchor type and offset
func (as AnchorSettings) AnchorPosition() int {
	var pos int
	switch as.anchor {
	case AnchorTop:
		pos = as.anchorOffset
	case AnchorBottom:
		_, h := termbox.Size()
		pos = h - as.anchorOffset - 1 // -1 is required because y is 0 base, but h is 1 base
	default:
		panic("Unknown anchor type!")
	}

	return pos
}

// UserPrompt draws the prompt line
type UserPrompt struct {
	*Ctx
	*AnchorSettings
	prefix    string
	prefixLen int
}

func NewUserPrompt(ctx *Ctx, anchor VerticalAnchor, anchorOffset int) *UserPrompt {
	prefix := ctx.config.Prompt
	if len(prefix) <= 0 { // default
		prefix = "QUERY>"
	}
	prefixLen := runewidth.StringWidth(prefix)

	return &UserPrompt{
		Ctx:            ctx,
		AnchorSettings: &AnchorSettings{anchor, anchorOffset},
		prefix:         prefix,
		prefixLen:      prefixLen,
	}
}

func (u UserPrompt) Draw() {
	location := u.AnchorPosition()

	// print "QUERY>"
	printScreen(0, location, u.config.Style.BasicFG(), u.config.Style.BasicBG(), u.prefix, false)

	if u.caretPos <= 0 {
		u.caretPos = 0 // sanity
	}

	if u.caretPos > len(u.query) {
		u.caretPos = len(u.query)
	}

	if u.caretPos == len(u.query) {
		// the entire string + the caret after the string
		fg := u.config.Style.QueryFG()
		bg := u.config.Style.QueryBG()
		qs := string(u.query)
		ql := runewidth.StringWidth(qs)
		printScreen(u.prefixLen+1, location, fg, bg, qs, false)
		printScreen(u.prefixLen+1+ql, location, fg|termbox.AttrReverse, bg|termbox.AttrReverse, " ", false)
		printScreen(u.prefixLen+1+ql+1, location, fg, bg, "", true)
	} else {
		// the caret is in the middle of the string
		prev := 0
		fg := u.config.Style.QueryFG()
		bg := u.config.Style.QueryBG()
		for i, r := range u.query {
			if i == u.caretPos {
				fg |= termbox.AttrReverse
				bg |= termbox.AttrReverse
			}
			termbox.SetCell(u.prefixLen+1+prev, location, r, fg, bg)
			prev += runewidth.RuneWidth(r)
		}
	}

	width, _ := termbox.Size()

	pmsg := fmt.Sprintf("%s [%d/%d]", u.Matcher().String(), u.currentPage.index, u.maxPage)
	printScreen(width-runewidth.StringWidth(pmsg), location, u.config.Style.BasicFG(), u.config.Style.BasicBG(), pmsg, false)
}

// StatusBar draws the status message bar
type StatusBar struct {
	*Ctx
	*AnchorSettings
	clearTimer *time.Timer
}

func NewStatusBar(ctx *Ctx, anchor VerticalAnchor, anchorOffset int) *StatusBar {
	return &StatusBar{
		ctx,
		&AnchorSettings{ anchor, anchorOffset },
		nil,
	}
}

func (s *StatusBar) stopTimer() {
	if t := s.clearTimer; t != nil {
		t.Stop()
	}
}

func (s *StatusBar) ClearStatus(d time.Duration) {
	s.stopTimer()
	s.clearTimer = time.AfterFunc(d, func() {
		s.PrintStatus("")
	})
}

func (s *StatusBar) PrintStatus(msg string) {
	s.stopTimer()

	location := s.AnchorPosition()

	w, _ := termbox.Size()
	width := runewidth.StringWidth(msg)
	for width > w {
		_, rw := utf8.DecodeRuneInString(msg)
		width = width - rw
		msg = msg[rw:]
	}

	var pad []byte
	if w > width {
		pad = make([]byte, w-width)
		for i := 0; i < w-width; i++ {
			pad[i] = ' '
		}
	}

	fgAttr := s.config.Style.BasicFG()
	bgAttr := s.config.Style.BasicBG()

	if w > width {
		printScreen(0, location, fgAttr, bgAttr, string(pad), false)
	}

	if width > 0 {
		printScreen(w-width, location, fgAttr|termbox.AttrReverse|termbox.AttrBold, bgAttr|termbox.AttrReverse, msg, false)
	}
	termbox.Flush()
}

type ListArea struct {
	*Ctx
	*AnchorSettings
	sortTopDown  bool
}

func NewListArea(ctx *Ctx, anchor VerticalAnchor, anchorOffset int, sortTopDown bool) *ListArea {
	return &ListArea{
		ctx,
		&AnchorSettings{ anchor, anchorOffset },
		sortTopDown,
	}
}

func (l *ListArea) Draw(targets []Match, perPage int) {
	currentPage := l.currentPage

	start := l.AnchorPosition()

	var y int
	var fgAttr, bgAttr termbox.Attribute
	for n := 0; n < perPage; n++ {
		switch {
		case n+currentPage.offset == l.currentLine-start:
			fgAttr = l.config.Style.SelectedFG()
			bgAttr = l.config.Style.SelectedBG()
		case l.selection.Has(n+currentPage.offset) || l.SelectedRange().Has(n+currentPage.offset):
			fgAttr = l.config.Style.SavedSelectionFG()
			bgAttr = l.config.Style.SavedSelectionBG()
		default:
			fgAttr = l.config.Style.BasicFG()
			bgAttr = l.config.Style.BasicBG()
		}

		targetIdx := currentPage.offset + n
		if targetIdx >= len(targets) {
			break
		}

		if l.sortTopDown {
			y = n + start
		} else {
			y = start - n
		}

		target := targets[targetIdx]
		line := target.Line()
		matches := target.Indices()
		if matches == nil {
			printScreen(0, y, fgAttr, bgAttr, line, true)
		} else {
			prev := 0
			index := 0
			for _, m := range matches {
				if m[0] > index {
					c := line[index:m[0]]
					printScreen(prev, y, fgAttr, bgAttr, c, false)
					prev += runewidth.StringWidth(c)
					index += len(c)
				}
				c := line[m[0]:m[1]]
				printScreen(prev, y, l.config.Style.MatchedFG(), mergeAttribute(bgAttr, l.config.Style.MatchedBG()), c, true)
				prev += runewidth.StringWidth(c)
				index += len(c)
			}

			m := matches[len(matches)-1]
			if m[0] > index {
				printScreen(prev, y, l.config.Style.QueryFG(), mergeAttribute(bgAttr, l.config.Style.QueryBG()), line[m[0]:m[1]], true)
			} else if len(line) > m[1] {
				printScreen(prev, y, fgAttr, bgAttr, line[m[1]:len(line)], true)
			}
		}
	}
}

// BasicLayout is... the basic layout :) At this point this is the
// only struct for layouts, which means that while the position
// of components may be configurable, the actual types of components
// that are used are set and static
type BasicLayout struct {
	*Ctx
	*StatusBar
	prompt *UserPrompt
	list   *ListArea
}

func NewDefaultLayout(ctx *Ctx) *BasicLayout {
	return &BasicLayout{
		Ctx:       ctx,
		StatusBar: NewStatusBar(ctx, AnchorBottom, 0),
		// The prompt is at the top
		prompt: NewUserPrompt(ctx, AnchorTop, 0),
		// The list area is at the top, after the prompt
		// It's also displayed top-to-bottom order
		list: NewListArea(ctx, AnchorTop, 1, true),
	}
}

func NewBottomUpLayout(ctx *Ctx) *BasicLayout {
	return &BasicLayout{
		Ctx:       ctx,
		StatusBar: NewStatusBar(ctx, AnchorBottom, 0),
		// The prompt is at the bottom, above the status bar
		prompt: NewUserPrompt(ctx, AnchorBottom, 1),
		// The list area is at the bottom, above the prompt
		// IT's displayed in bottom-to-top order
		list: NewListArea(ctx, AnchorBottom, 2, false),
	}
}

func (l *BasicLayout) CalculatePage(targets []Match, perPage int) error {
CALCULATE_PAGE:
	currentPage := l.currentPage
	currentPage.index = ((l.currentLine - 1) / perPage) + 1
	if currentPage.index <= 0 {
		currentPage.index = 1
	}
	currentPage.offset = (currentPage.index - 1) * perPage
	currentPage.perPage = perPage
	if len(targets) == 0 {
		l.maxPage = 1
	} else {
		l.maxPage = ((len(targets) + perPage - 1) / perPage)
	}

	if l.maxPage < currentPage.index {
		if len(targets) == 0 && len(l.query) == 0 {
			// wait for targets
			return fmt.Errorf("no targets or query. nothing to do")
		}
		l.currentLine = currentPage.offset
		goto CALCULATE_PAGE
	}

	return nil
}

func (l *BasicLayout) DrawScreen(targets []Match) {
	if err := termbox.Clear(l.config.Style.BasicFG(), l.config.Style.BasicBG()); err != nil {
		return
	}

	if l.currentLine > len(targets) && len(targets) > 0 {
		l.currentLine = len(targets)
	}

	_, height := termbox.Size()
	perPage := height - 2 // list area is always the display area - 2 lines for prompt and status

	if err := l.CalculatePage(targets, perPage); err != nil {
		return
	}

	l.prompt.Draw()
	l.list.Draw(targets, perPage)

	if err := termbox.Flush(); err != nil {
		return
	}
}
<|endoftext|>


<commit_before>package mmm

import (
	"testing"
	"unsafe"
)

// -----------------------------------------------------------------------------

func TestSize_SizeOf_bool(t *testing.T) {
	var v bool
	size, err := SizeOf(v)
	if err != nil {
		t.Error(err)
	}
	if size != unsafe.Sizeof(v) {
		t.Error("invalid size for bool")
	}
}
<commit_msg>added TestSize_SizeOf_int<commit_after>package mmm

import (
	"testing"
	"unsafe"
)

// -----------------------------------------------------------------------------

func TestSize_SizeOf_bool(t *testing.T) {
	var v bool
	size, err := SizeOf(v)
	if err != nil {
		t.Error(err)
	}
	if size != unsafe.Sizeof(v) {
		t.Error("invalid size for bool")
	}
}

func TestSize_SizeOf_int(t *testing.T) {
	var v int
	size, err := SizeOf(v)
	if err != nil {
		t.Error(err)
	}
	if size != unsafe.Sizeof(v) {
		t.Error("invalid size for bool")
	}
}

//var i8 int8
//var i16 int16
//var i32 int32
//var i64 int64
//var ui uint
//var ui8 uint8
//var ui16 uint16
//var ui32 uint32
//var ui64 uint64
//var uiptr uintptr
//var f32 float32
//var f64 float64
//var c64 complex64
//var c128 complex128
//var iarr [42]int
//var ichan chan int
//var itf interface{}
//var imap map[int]int
//var iptr *int
//var islice []int
//var str string
//var srt struct{}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
// +build !windows

package utils

import (
	"os"
	"syscall"
)

// ReplaceFile atomically replaces the destination file or directory
// with the source. The errors that are returned are identical to
// those returned by os.Rename.
func ReplaceFile(source, destination string) error {
	return os.Rename(source, destination)
}

// IsNotExist returns true if the error is consistent with an attempt to
// reference a file that does not exist.
func IsNotExist(err error) bool {
	if os.IsNotExist(err) {
		return true
	}
	if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOTDIR {
		return true
	}
	return false
}
<commit_msg>address review<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
// +build !windows

package utils

import (
	"os"
	"syscall"
)

// ReplaceFile atomically replaces the destination file or directory
// with the source. The errors that are returned are identical to
// those returned by os.Rename.
func ReplaceFile(source, destination string) error {
	return os.Rename(source, destination)
}

// IsNotExist returns true if the error is consistent with an attempt to
// reference a file that does not exist. This works around the occasionally
// unhelpful behaviour of os.IsNotExist, which does not recognise the error
// produced when trying to read a path in which some component appears to
// reference a directory but actually references a file. For example, if
// "foo" is a file, an attempt to read "foo/bar" will generate an error that
// does not satisfy os.IsNotExist, but will satisfy utils.IsNotExist.
func IsNotExist(err error) bool {
	if os.IsNotExist(err) {
		return true
	}
	if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOTDIR {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package ssdp

import (
	"errors"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/huin/goupnp/httpu"
)

const (
	ssdpDiscover = `"ssdp:discover"`
	methodSearch = "M-SEARCH"
	ssdpUDP4Addr = "239.255.255.250:1900"
)

// SSDPRawSearch performs a fairly raw SSDP search request, and returns the
// unique response(s) that it receives. Each response has the requested
// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to
// wait for responses in seconds, and must be a minimum of 1 (the
// implementation waits an additional 100ms for responses to arrive), 2 is a
// reasonable value for this. numSends is the number of requests to send - 3 is
// a reasonable value for this.
func SSDPRawSearch(httpu *httpu.HTTPUClient, searchTarget string, maxWaitSeconds int, numSends int) ([]*http.Response, error) {
	if maxWaitSeconds < 1 {
		return nil, errors.New("ssdp: maxWaitSeconds must be >= 1")
	}

	seenUsns := make(map[string]bool)
	var responses []*http.Response
	req := http.Request{
		Method: methodSearch,
		// TODO: Support both IPv4 and IPv6.
		Host: ssdpUDP4Addr,
		URL:  &url.URL{Opaque: "*"},
		Header: http.Header{
			// Putting headers in here avoids them being title-cased.
			// (The UPnP discovery protocol uses case-sensitive headers)
			"HOST": []string{ssdpUDP4Addr},
			"MX":   []string{strconv.FormatInt(int64(maxWaitSeconds), 10)},
			"MAN":  []string{ssdpDiscover},
			"ST":   []string{searchTarget},
		},
	}
	allResponses, err := httpu.Do(&req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends)
	if err != nil {
		return nil, err
	}
	for _, response := range allResponses {
		if response.StatusCode != 200 {
			log.Printf("ssdp: got response status code %q in search response", response.Status)
			continue
		}
		if st := response.Header.Get("ST"); st != searchTarget {
			log.Printf("ssdp: got unexpected search target result %q", st)
			return nil, nil
		}
		location, err := response.Location()
		if err != nil {
			log.Printf("ssdp: no usable location in search response (discarding): %v", err)
			continue
		}
		usn := response.Header.Get("USN")
		if usn == "" {
			log.Printf("ssdp: empty/missing USN in search response (using location instead): %v", err)
			usn = location.String()
		}
		if _, alreadySeen := seenUsns[usn]; !alreadySeen {
			seenUsns[usn] = true
			responses = append(responses, response)
		}
	}

	return responses, nil
}
<commit_msg>Don't discard all results if an unexpected reply comes back.<commit_after>package ssdp

import (
	"errors"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/huin/goupnp/httpu"
)

const (
	ssdpDiscover = `"ssdp:discover"`
	methodSearch = "M-SEARCH"
	ssdpUDP4Addr = "239.255.255.250:1900"
)

// SSDPRawSearch performs a fairly raw SSDP search request, and returns the
// unique response(s) that it receives. Each response has the requested
// searchTarget, a USN, and a valid location. maxWaitSeconds states how long to
// wait for responses in seconds, and must be a minimum of 1 (the
// implementation waits an additional 100ms for responses to arrive), 2 is a
// reasonable value for this. numSends is the number of requests to send - 3 is
// a reasonable value for this.
func SSDPRawSearch(httpu *httpu.HTTPUClient, searchTarget string, maxWaitSeconds int, numSends int) ([]*http.Response, error) {
	if maxWaitSeconds < 1 {
		return nil, errors.New("ssdp: maxWaitSeconds must be >= 1")
	}

	seenUsns := make(map[string]bool)
	var responses []*http.Response
	req := http.Request{
		Method: methodSearch,
		// TODO: Support both IPv4 and IPv6.
		Host: ssdpUDP4Addr,
		URL:  &url.URL{Opaque: "*"},
		Header: http.Header{
			// Putting headers in here avoids them being title-cased.
			// (The UPnP discovery protocol uses case-sensitive headers)
			"HOST": []string{ssdpUDP4Addr},
			"MX":   []string{strconv.FormatInt(int64(maxWaitSeconds), 10)},
			"MAN":  []string{ssdpDiscover},
			"ST":   []string{searchTarget},
		},
	}
	allResponses, err := httpu.Do(&req, time.Duration(maxWaitSeconds)*time.Second+100*time.Millisecond, numSends)
	if err != nil {
		return nil, err
	}
	for _, response := range allResponses {
		if response.StatusCode != 200 {
			log.Printf("ssdp: got response status code %q in search response", response.Status)
			continue
		}
		if st := response.Header.Get("ST"); st != searchTarget {
			log.Printf("ssdp: got unexpected search target result %q", st)
			continue
		}
		location, err := response.Location()
		if err != nil {
			log.Printf("ssdp: no usable location in search response (discarding): %v", err)
			continue
		}
		usn := response.Header.Get("USN")
		if usn == "" {
			log.Printf("ssdp: empty/missing USN in search response (using location instead): %v", err)
			usn = location.String()
		}
		if _, alreadySeen := seenUsns[usn]; !alreadySeen {
			seenUsns[usn] = true
			responses = append(responses, response)
		}
	}

	return responses, nil
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/asaskevich/govalidator"

	"github.com/techjanitor/pram-libs/config"
	"github.com/techjanitor/pram-libs/db"
	e "github.com/techjanitor/pram-libs/errors"
	"github.com/techjanitor/pram-libs/validate"
)

// Register contains information for initial account creation
type RegisterModel struct {
	Name     string
	Email    string
	Password string
	Hashed   []byte
}

// Validate will check the provided name length and email
func (r *RegisterModel) Validate() (err error) {

	// Validate name input
	name := validate.Validate{Input: r.Name, Max: config.Settings.Limits.NameMaxLength, Min: config.Settings.Limits.NameMinLength}
	if name.IsEmpty() {
		return e.ErrNameEmpty
	} else if name.MinLength() {
		return e.ErrNameShort
	} else if name.MaxLength() {
		return e.ErrNameLong
	} else if !name.IsUsername() {
		return e.ErrNameAlphaNum
	}

	// Validate password input
	password := validate.Validate{Input: r.Password, Max: config.Settings.Limits.NameMaxLength, Min: config.Settings.Limits.NameMinLength}
	if password.IsEmpty() {
		return e.ErrPasswordEmpty
	} else if password.MinLength() {
		return e.ErrPasswordShort
	} else if password.MaxLength() {
		return e.ErrPasswordLong
	}

	// if theres an email validate it
	if r.Email != "" {
		// Validate email
		if !govalidator.IsEmail(r.Email) {
			return e.ErrInvalidEmail
		}
	}
	return

}

// check for duplicate name before registering
func (r *RegisterModel) CheckDuplicate() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	var check bool

	err = dbase.QueryRow("select count(*) from users where user_name = ?", r.Name).Scan(&check)
	if err != nil {
		return
	}

	// Error if it does
	if check {
		return e.ErrDuplicateName
	}

	return

}

// register new user
func (r *RegisterModel) Register() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	ps1, err := dbase.Prepare("INSERT into users (user_name, user_email, user_password, user_confirmed, user_avatar) VALUES (?,?,?,?,ROUND((RAND() * (48-1))+1))")
	if err != nil {
		return
	}
	defer ps1.Close()

	e1, err = ps1.Exec(r.Name, r.Email, r.Hashed, 1)
	if err != nil {
		return
	}

	user_id, err := e1.LastInsertId()
	if err != nil {
		return err
	}

	ps2, err := dbase.Prepare("INSERT into user_group_map VALUES (?,?)")
	if err != nil {
		return
	}
	defer ps1.Close()

	_, err = ps2.Exec(user_id, 2)
	if err != nil {
		return
	}

	return

}
<commit_msg>new user group map<commit_after>package models

import (
	"github.com/asaskevich/govalidator"

	"github.com/techjanitor/pram-libs/config"
	"github.com/techjanitor/pram-libs/db"
	e "github.com/techjanitor/pram-libs/errors"
	"github.com/techjanitor/pram-libs/validate"
)

// Register contains information for initial account creation
type RegisterModel struct {
	Name     string
	Email    string
	Password string
	Hashed   []byte
}

// Validate will check the provided name length and email
func (r *RegisterModel) Validate() (err error) {

	// Validate name input
	name := validate.Validate{Input: r.Name, Max: config.Settings.Limits.NameMaxLength, Min: config.Settings.Limits.NameMinLength}
	if name.IsEmpty() {
		return e.ErrNameEmpty
	} else if name.MinLength() {
		return e.ErrNameShort
	} else if name.MaxLength() {
		return e.ErrNameLong
	} else if !name.IsUsername() {
		return e.ErrNameAlphaNum
	}

	// Validate password input
	password := validate.Validate{Input: r.Password, Max: config.Settings.Limits.NameMaxLength, Min: config.Settings.Limits.NameMinLength}
	if password.IsEmpty() {
		return e.ErrPasswordEmpty
	} else if password.MinLength() {
		return e.ErrPasswordShort
	} else if password.MaxLength() {
		return e.ErrPasswordLong
	}

	// if theres an email validate it
	if r.Email != "" {
		// Validate email
		if !govalidator.IsEmail(r.Email) {
			return e.ErrInvalidEmail
		}
	}
	return

}

// check for duplicate name before registering
func (r *RegisterModel) CheckDuplicate() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	var check bool

	err = dbase.QueryRow("select count(*) from users where user_name = ?", r.Name).Scan(&check)
	if err != nil {
		return
	}

	// Error if it does
	if check {
		return e.ErrDuplicateName
	}

	return

}

// register new user
func (r *RegisterModel) Register() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	ps1, err := dbase.Prepare("INSERT into users (user_name, user_email, user_password, user_confirmed, user_avatar) VALUES (?,?,?,?,ROUND((RAND() * (48-1))+1))")
	if err != nil {
		return
	}
	defer ps1.Close()

	e1, err := ps1.Exec(r.Name, r.Email, r.Hashed, 1)
	if err != nil {
		return
	}

	user_id, err := e1.LastInsertId()
	if err != nil {
		return err
	}

	ps2, err := dbase.Prepare("INSERT into user_group_map VALUES (?,?)")
	if err != nil {
		return
	}
	defer ps1.Close()

	_, err = ps2.Exec(user_id, 2)
	if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package storage

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"github.com/MerlinDMC/dsapid"
	"io/ioutil"
	"os"
	"path"
	"sort"
)

const (
	defaultManifestFilename string = "manifest.json"
)

type ManifestStorage interface {
	Add(string, *dsapid.ManifestResource) error
	Update(string, *dsapid.ManifestResource) error
	Delete(string)
	Reload()
	Get(string) *dsapid.ManifestResource
	GetOK(string) (*dsapid.ManifestResource, bool)
	List() chan *dsapid.ManifestResource
	Filter(...ManifestFilter) chan *dsapid.ManifestResource
	ManifestPath(*dsapid.ManifestResource) string
	FilePath(*dsapid.ManifestResource, *dsapid.ManifestFileResource) string
}

type filesystemManifestStorage struct {
	basedir string

	manifests map[string]*dsapid.ManifestResource
	byDate    []*dsapid.ManifestResource
}

type ManifestFilter func(*dsapid.ManifestResource) bool

type ManifestsByPublishedAt []*dsapid.ManifestResource

func (t ManifestsByPublishedAt) Len() int      { return len(t) }
func (t ManifestsByPublishedAt) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t ManifestsByPublishedAt) Less(i, j int) bool {
	return t[i].PublishedAt.Unix() > t[j].PublishedAt.Unix()
}

func NewManifestStorage(basedir string) ManifestStorage {
	storage := new(filesystemManifestStorage)

	storage.basedir = basedir

	storage.manifests = make(map[string]*dsapid.ManifestResource)
	storage.byDate = make([]*dsapid.ManifestResource, 0)

	storage.load()

	return storage
}

func (me *filesystemManifestStorage) Add(id string, manifest *dsapid.ManifestResource) error {
	os.MkdirAll(path.Join(me.basedir, id), 0770)

	if data, err := json.MarshalIndent(manifest, "", "  "); err == nil {
		if err = ioutil.WriteFile(path.Join(me.basedir, id, defaultManifestFilename), data, 0666); err != nil {
			return err
		}
	}

	me.add(id, manifest)

	return nil
}

func (me *filesystemManifestStorage) Update(id string, manifest *dsapid.ManifestResource) error {
	if data, err := json.MarshalIndent(manifest, "", "  "); err == nil {
		if err = ioutil.WriteFile(path.Join(me.basedir, id, defaultManifestFilename), data, 0666); err != nil {
			return err
		}
	}

	return nil
}

func (me *filesystemManifestStorage) Delete(id string) {
	os.RemoveAll(path.Join(me.basedir, id))

	me.delete(id)
}

func (me *filesystemManifestStorage) Reload() {
	for k := range me.manifests {
		delete(me.manifests, k)
	}

	me.byDate = make([]*dsapid.ManifestResource, 0)

	me.load()
}

func (me *filesystemManifestStorage) Get(id string) *dsapid.ManifestResource {
	return me.manifests[id]
}

func (me *filesystemManifestStorage) GetOK(id string) (*dsapid.ManifestResource, bool) {
	v, ok := me.manifests[id]

	return v, ok
}

func (me *filesystemManifestStorage) List() (c chan *dsapid.ManifestResource) {
	c = make(chan *dsapid.ManifestResource)

	go func() {
		for _, item := range me.byDate {
			c <- item
		}

		close(c)
	}()

	return
}

func (me *filesystemManifestStorage) Filter(flist ...ManifestFilter) (c chan *dsapid.ManifestResource) {
	c = make(chan *dsapid.ManifestResource)

	go func() {
	nextItem:
		for item := range me.List() {
			for _, f := range flist {
				if !f(item) {
					continue nextItem
				}
			}

			c <- item
		}

		close(c)
	}()

	return
}

func (me *filesystemManifestStorage) ManifestPath(manifest *dsapid.ManifestResource) string {
	return path.Join(me.basedir, manifest.Uuid)
}

func (me *filesystemManifestStorage) FilePath(manifest *dsapid.ManifestResource, file *dsapid.ManifestFileResource) string {
	return path.Join(me.basedir, manifest.Uuid, file.Path)
}

func (me *filesystemManifestStorage) add(id string, manifest *dsapid.ManifestResource) {
	me.manifests[id] = manifest
	me.byDate = append(me.byDate, manifest)

	sort.Sort(ManifestsByPublishedAt(me.byDate))
}

func (me *filesystemManifestStorage) delete(id string) {
	for i, m := range me.byDate {
		if m.Uuid == id {
			me.byDate = append(me.byDate[:i], me.byDate[i+1:]...)

			break
		}
	}

	if _, ok := me.manifests[id]; ok {
		delete(me.manifests, id)
	}
}

func (me *filesystemManifestStorage) load() {
	if items, err := ioutil.ReadDir(me.basedir); err == nil {
		for _, item := range items {
			if item.IsDir() {
				manifestFilename := path.Join(me.basedir, item.Name(), defaultManifestFilename)

				if _, err := os.Stat(manifestFilename); err == nil {
					if data, err := ioutil.ReadFile(manifestFilename); err == nil {
						id, manifest := uuid.Parse(item.Name()), dsapid.ManifestResource{}

						json.Unmarshal(data, &manifest)

						if id.String() == manifest.Uuid {
							me.add(manifest.Uuid, &manifest)
						}
					}
				}
			}
		}
	}
}
<commit_msg>only use the last path segment for the filepath<commit_after>package storage

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"github.com/MerlinDMC/dsapid"
	"io/ioutil"
	"os"
	"path"
	"sort"
)

const (
	defaultManifestFilename string = "manifest.json"
)

type ManifestStorage interface {
	Add(string, *dsapid.ManifestResource) error
	Update(string, *dsapid.ManifestResource) error
	Delete(string)
	Reload()
	Get(string) *dsapid.ManifestResource
	GetOK(string) (*dsapid.ManifestResource, bool)
	List() chan *dsapid.ManifestResource
	Filter(...ManifestFilter) chan *dsapid.ManifestResource
	ManifestPath(*dsapid.ManifestResource) string
	FilePath(*dsapid.ManifestResource, *dsapid.ManifestFileResource) string
}

type filesystemManifestStorage struct {
	basedir string

	manifests map[string]*dsapid.ManifestResource
	byDate    []*dsapid.ManifestResource
}

type ManifestFilter func(*dsapid.ManifestResource) bool

type ManifestsByPublishedAt []*dsapid.ManifestResource

func (t ManifestsByPublishedAt) Len() int      { return len(t) }
func (t ManifestsByPublishedAt) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t ManifestsByPublishedAt) Less(i, j int) bool {
	return t[i].PublishedAt.Unix() > t[j].PublishedAt.Unix()
}

func NewManifestStorage(basedir string) ManifestStorage {
	storage := new(filesystemManifestStorage)

	storage.basedir = basedir

	storage.manifests = make(map[string]*dsapid.ManifestResource)
	storage.byDate = make([]*dsapid.ManifestResource, 0)

	storage.load()

	return storage
}

func (me *filesystemManifestStorage) Add(id string, manifest *dsapid.ManifestResource) error {
	os.MkdirAll(path.Join(me.basedir, id), 0770)

	if data, err := json.MarshalIndent(manifest, "", "  "); err == nil {
		if err = ioutil.WriteFile(path.Join(me.basedir, id, defaultManifestFilename), data, 0666); err != nil {
			return err
		}
	}

	me.add(id, manifest)

	return nil
}

func (me *filesystemManifestStorage) Update(id string, manifest *dsapid.ManifestResource) error {
	if data, err := json.MarshalIndent(manifest, "", "  "); err == nil {
		if err = ioutil.WriteFile(path.Join(me.basedir, id, defaultManifestFilename), data, 0666); err != nil {
			return err
		}
	}

	return nil
}

func (me *filesystemManifestStorage) Delete(id string) {
	os.RemoveAll(path.Join(me.basedir, id))

	me.delete(id)
}

func (me *filesystemManifestStorage) Reload() {
	for k := range me.manifests {
		delete(me.manifests, k)
	}

	me.byDate = make([]*dsapid.ManifestResource, 0)

	me.load()
}

func (me *filesystemManifestStorage) Get(id string) *dsapid.ManifestResource {
	return me.manifests[id]
}

func (me *filesystemManifestStorage) GetOK(id string) (*dsapid.ManifestResource, bool) {
	v, ok := me.manifests[id]

	return v, ok
}

func (me *filesystemManifestStorage) List() (c chan *dsapid.ManifestResource) {
	c = make(chan *dsapid.ManifestResource)

	go func() {
		for _, item := range me.byDate {
			c <- item
		}

		close(c)
	}()

	return
}

func (me *filesystemManifestStorage) Filter(flist ...ManifestFilter) (c chan *dsapid.ManifestResource) {
	c = make(chan *dsapid.ManifestResource)

	go func() {
	nextItem:
		for item := range me.List() {
			for _, f := range flist {
				if !f(item) {
					continue nextItem
				}
			}

			c <- item
		}

		close(c)
	}()

	return
}

func (me *filesystemManifestStorage) ManifestPath(manifest *dsapid.ManifestResource) string {
	return path.Join(me.basedir, manifest.Uuid)
}

func (me *filesystemManifestStorage) FilePath(manifest *dsapid.ManifestResource, file *dsapid.ManifestFileResource) string {
	return path.Join(me.basedir, manifest.Uuid, path.Base(file.Path))
}

func (me *filesystemManifestStorage) add(id string, manifest *dsapid.ManifestResource) {
	me.manifests[id] = manifest
	me.byDate = append(me.byDate, manifest)

	sort.Sort(ManifestsByPublishedAt(me.byDate))
}

func (me *filesystemManifestStorage) delete(id string) {
	for i, m := range me.byDate {
		if m.Uuid == id {
			me.byDate = append(me.byDate[:i], me.byDate[i+1:]...)

			break
		}
	}

	if _, ok := me.manifests[id]; ok {
		delete(me.manifests, id)
	}
}

func (me *filesystemManifestStorage) load() {
	if items, err := ioutil.ReadDir(me.basedir); err == nil {
		for _, item := range items {
			if item.IsDir() {
				manifestFilename := path.Join(me.basedir, item.Name(), defaultManifestFilename)

				if _, err := os.Stat(manifestFilename); err == nil {
					if data, err := ioutil.ReadFile(manifestFilename); err == nil {
						id, manifest := uuid.Parse(item.Name()), dsapid.ManifestResource{}

						json.Unmarshal(data, &manifest)

						if id.String() == manifest.Uuid {
							me.add(manifest.Uuid, &manifest)
						}
					}
				}
			}
		}
	}
}
<|endoftext|>


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

package database

import (
	"time"
)

type Config struct {
	Name               string        `env:"DB_NAME" json:",omitempty"`
	User               string        `env:"DB_USER" json:",omitempty"`
	Host               string        `env:"DB_HOST, default=localhost" json:",omitempty"`
	Port               string        `env:"DB_PORT, default=5432" json:",omitempty"`
	SSLMode            string        `env:"DB_SSLMODE, default=require" json:",omitempty"`
	ConnectionTimeout  int           `env:"DB_CONNECT_TIMEOUT" json:",omitempty"`
	Password           string        `env:"DB_PASSWORD" json:"-"` // ignored by zap's JSON formatter
	SSLCertPath        string        `env:"DB_SSLCERT" json:",omitempty"`
	SSLKeyPath         string        `env:"DB_SSLKEY" json:",omitempty"`
	SSLRootCertPath    string        `env:"DB_SSLROOTCERT" json:",omitempty"`
	PoolMinConnections string        `env:"DB_POOL_MIN_CONNS" json:",omitempty"`
	PoolMaxConnections string        `env:"DB_POOL_MAX_CONNS" json:",omitempty"`
	PoolMaxConnLife    time.Duration `env:"DB_POOL_MAX_CONN_LIFETIME" json:",omitempty"`
	PoolMaxConnIdle    time.Duration `env:"DB_POOL_MAX_CONN_IDLE_TIME" json:",omitempty"`
	PoolHealthCheck    time.Duration `env:"DB_POOL_HEALTH_CHECK_PERIOD, default=1m" json:",omitempty"`
}

func (c *Config) DatabaseConfig() *Config {
	return c
}
<commit_msg>Set default idle and life timeouts (#927)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package database

import (
	"time"
)

type Config struct {
	Name               string        `env:"DB_NAME" json:",omitempty"`
	User               string        `env:"DB_USER" json:",omitempty"`
	Host               string        `env:"DB_HOST, default=localhost" json:",omitempty"`
	Port               string        `env:"DB_PORT, default=5432" json:",omitempty"`
	SSLMode            string        `env:"DB_SSLMODE, default=require" json:",omitempty"`
	ConnectionTimeout  int           `env:"DB_CONNECT_TIMEOUT" json:",omitempty"`
	Password           string        `env:"DB_PASSWORD" json:"-"` // ignored by zap's JSON formatter
	SSLCertPath        string        `env:"DB_SSLCERT" json:",omitempty"`
	SSLKeyPath         string        `env:"DB_SSLKEY" json:",omitempty"`
	SSLRootCertPath    string        `env:"DB_SSLROOTCERT" json:",omitempty"`
	PoolMinConnections string        `env:"DB_POOL_MIN_CONNS" json:",omitempty"`
	PoolMaxConnections string        `env:"DB_POOL_MAX_CONNS" json:",omitempty"`
	PoolMaxConnLife    time.Duration `env:"DB_POOL_MAX_CONN_LIFETIME, default=5m" json:",omitempty"`
	PoolMaxConnIdle    time.Duration `env:"DB_POOL_MAX_CONN_IDLE_TIME, default=1m" json:",omitempty"`
	PoolHealthCheck    time.Duration `env:"DB_POOL_HEALTH_CHECK_PERIOD, default=1m" json:",omitempty"`
}

func (c *Config) DatabaseConfig() *Config {
	return c
}
<|endoftext|>


<commit_before>package godge

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

	"github.com/jmoiron/sqlx"
)

const (
	failedVerdict = "Failed"
	passedVerdict = "Passed"
)

func saveToScoreboard(db *sqlx.DB, user, task string, verdict string) error {
	_, err := db.Exec("INSERT INTO scoreboard (username, task_name, verdict, submitted_at) VALUES (?,?,?,?)", user, task, verdict, time.Now())
	if err != nil {
		return fmt.Errorf("failed to save scoreboard record: %v", err)
	}
	return nil
}

func getFromScoreboard(db *sqlx.DB, user, task string) (*string, error) {
	var res string
	err := db.Get(&res, "SELECT verdict FROM scoreboard WHERE username=? AND task_name=? ORDER BY ID DESC LIMIT 1", user, task)
	if err == sql.ErrNoRows {
		e := ""
		return &e, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get from scoreboard: %v", err)
	}
	return &res, nil
}

// returns a 2D array of the results (including the tasks as the first row and
// the users as the first column). The results are rows are sorted by the score
// of each user.
func buildScoreboard(db *sqlx.DB, allUsers, allTasks []string) ([][]string, error) {

	var ret [][]string

	for _, u := range allUsers {
		row := []string{u}
		for _, t := range allTasks {
			v, err := getFromScoreboard(db, u, t)
			if err != nil {
				return nil, fmt.Errorf("failed to build scoreboard: %v", err)
			}
			row = append(row, *v)
		}
		ret = append(ret, row)
	}

	score := func(row []string) int {
		var sc int
		for _, r := range row {
			if r == passedVerdict {
				sc++
			}
		}
		return sc
	}

	sort.Slice(ret, func(i, j int) bool {
		return score(ret[i][1:]) < score(ret[j][1:])
	})

	header := append([]string{}, append([]string{""}, allTasks...)...)
	ret = append([][]string{header}, ret...)

	return ret, nil
}
<commit_msg>Sorting the scoreboard correctly<commit_after>package godge

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

	"github.com/jmoiron/sqlx"
)

const (
	failedVerdict = "Failed"
	passedVerdict = "Passed"
)

func saveToScoreboard(db *sqlx.DB, user, task string, verdict string) error {
	_, err := db.Exec("INSERT INTO scoreboard (username, task_name, verdict, submitted_at) VALUES (?,?,?,?)", user, task, verdict, time.Now())
	if err != nil {
		return fmt.Errorf("failed to save scoreboard record: %v", err)
	}
	return nil
}

func getFromScoreboard(db *sqlx.DB, user, task string) (*string, error) {
	var res string
	err := db.Get(&res, "SELECT verdict FROM scoreboard WHERE username=? AND task_name=? ORDER BY ID DESC LIMIT 1", user, task)
	if err == sql.ErrNoRows {
		e := ""
		return &e, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get from scoreboard: %v", err)
	}
	return &res, nil
}

// returns a 2D array of the results (including the tasks as the first row and
// the users as the first column). The results are rows are sorted by the score
// of each user.
func buildScoreboard(db *sqlx.DB, allUsers, allTasks []string) ([][]string, error) {

	var ret [][]string

	for _, u := range allUsers {
		row := []string{u}
		for _, t := range allTasks {
			v, err := getFromScoreboard(db, u, t)
			if err != nil {
				return nil, fmt.Errorf("failed to build scoreboard: %v", err)
			}
			row = append(row, *v)
		}
		ret = append(ret, row)
	}

	score := func(row []string) int {
		var sc int
		for _, r := range row {
			if r == passedVerdict {
				sc++
			}
		}
		return sc
	}

	sort.Slice(ret, func(i, j int) bool {
		return score(ret[i][1:]) > score(ret[j][1:])
	})

	header := append([]string{}, append([]string{""}, allTasks...)...)
	ret = append([][]string{header}, ret...)

	return ret, nil
}
<|endoftext|>


<commit_before>package thrift_nats

import (
	"io"
	"log"
	"time"

	"git.apache.org/thrift.git/lib/go/thrift"
	"github.com/nats-io/nats"
)

const disconnect = "DISCONNECT"

type natsTransport struct {
	conn              *nats.Conn
	listenTo          string
	replyTo           string
	sub               *nats.Subscription
	reader            *timeoutReader
	writer            *io.PipeWriter
	heartbeat         string
	heartbeatInterval time.Duration
	closed            chan struct{}
}

// NewNATSTransport returns a Thrift TTransport which uses the NATS messaging
// system as the underlying transport. This TTransport can only be used with
// NATSServer.
func NewNATSTransport(conn *nats.Conn, listenTo, replyTo, heartbeat string,
	readTimeout, heartbeatInterval time.Duration) thrift.TTransport {

	reader, writer := io.Pipe()
	timeoutReader := newTimeoutReader(reader)
	timeoutReader.SetTimeout(readTimeout)
	return &natsTransport{
		conn:              conn,
		listenTo:          listenTo,
		replyTo:           replyTo,
		reader:            timeoutReader,
		writer:            writer,
		heartbeat:         heartbeat,
		heartbeatInterval: heartbeatInterval,
		closed:            make(chan struct{}),
	}
}

func (t *natsTransport) Open() error {
	sub, err := t.conn.Subscribe(t.listenTo, func(msg *nats.Msg) {
		if msg.Reply == disconnect {
			// Remote client is disconnecting.
			t.writer.Close()
			return
		}
		t.writer.Write(msg.Data)
	})
	if err != nil {
		return thrift.NewTTransportExceptionFromError(err)
	}
	t.conn.Flush() // Ensure subscription is processed before moving on.
	t.sub = sub
	if t.heartbeatInterval > 0 {
		go t.startHeartbeat()
	}
	return nil
}

func (t *natsTransport) IsOpen() bool {
	return t.sub != nil
}

func (t *natsTransport) Close() error {
	if !t.IsOpen() {
		return nil
	}
	// Signal remote peer for a graceful disconnect.
	t.conn.PublishRequest(t.replyTo, disconnect, nil)
	if err := t.sub.Unsubscribe(); err != nil {
		return err
	}
	t.conn.Flush()
	t.sub = nil
	return nil
}

func (t *natsTransport) Read(p []byte) (int, error) {
	n, err := t.reader.Read(p)
	return n, thrift.NewTTransportExceptionFromError(err)
}

func (t *natsTransport) Write(p []byte) (int, error) {
	if err := t.conn.Publish(t.replyTo, p); err != nil {
		return 0, thrift.NewTTransportExceptionFromError(err)
	}
	return len(p), nil
}

func (t *natsTransport) Flush() error {
	return nil
}

func (t *natsTransport) RemainingBytes() uint64 {
	return ^uint64(0) // We just don't know unless framed is used.
}

func (t *natsTransport) startHeartbeat() {
	for {
		select {
		case <-time.After(t.heartbeatInterval):
			if err := t.conn.Publish(t.heartbeat, nil); err != nil {
				log.Println("thrift_nats: error sending heartbeat", err)
			}
		case <-t.closed:
			return
		}
	}
}
<commit_msg>Buffer writes to avoid hitting NATS limit<commit_after>package thrift_nats

import (
	"bytes"
	"io"
	"log"
	"time"

	"git.apache.org/thrift.git/lib/go/thrift"
	"github.com/nats-io/nats"
)

const (
	disconnect     = "DISCONNECT"
	maxMessageSize = 1024 * 1024
)

type natsTransport struct {
	conn              *nats.Conn
	listenTo          string
	replyTo           string
	sub               *nats.Subscription
	reader            *timeoutReader
	writer            *io.PipeWriter
	heartbeat         string
	heartbeatInterval time.Duration
	closed            chan struct{}
	writeBuffer       *bytes.Buffer
}

// NewNATSTransport returns a Thrift TTransport which uses the NATS messaging
// system as the underlying transport. This TTransport can only be used with
// NATSServer.
func NewNATSTransport(conn *nats.Conn, listenTo, replyTo, heartbeat string,
	readTimeout, heartbeatInterval time.Duration) thrift.TTransport {

	reader, writer := io.Pipe()
	timeoutReader := newTimeoutReader(reader)
	timeoutReader.SetTimeout(readTimeout)
	buf := make([]byte, 0, maxMessageSize)
	return &natsTransport{
		conn:              conn,
		listenTo:          listenTo,
		replyTo:           replyTo,
		reader:            timeoutReader,
		writer:            writer,
		heartbeat:         heartbeat,
		heartbeatInterval: heartbeatInterval,
		closed:            make(chan struct{}),
		writeBuffer:       bytes.NewBuffer(buf),
	}
}

func (t *natsTransport) Open() error {
	sub, err := t.conn.Subscribe(t.listenTo, func(msg *nats.Msg) {
		if msg.Reply == disconnect {
			// Remote client is disconnecting.
			t.writer.Close()
			return
		}
		t.writer.Write(msg.Data)
	})
	if err != nil {
		return thrift.NewTTransportExceptionFromError(err)
	}
	t.conn.Flush() // Ensure subscription is processed before moving on.
	t.sub = sub
	if t.heartbeatInterval > 0 {
		go t.startHeartbeat()
	}
	return nil
}

func (t *natsTransport) IsOpen() bool {
	return t.sub != nil
}

func (t *natsTransport) Close() error {
	if !t.IsOpen() {
		return nil
	}
	// Signal remote peer for a graceful disconnect.
	t.conn.PublishRequest(t.replyTo, disconnect, nil)
	if err := t.sub.Unsubscribe(); err != nil {
		return err
	}
	t.conn.Flush()
	t.sub = nil
	return nil
}

func (t *natsTransport) Read(p []byte) (int, error) {
	n, err := t.reader.Read(p)
	return n, thrift.NewTTransportExceptionFromError(err)
}

func (t *natsTransport) Write(p []byte) (int, error) {
	remaining := t.writeBuffer.Cap() - t.writeBuffer.Len()
	if remaining < len(p) {
		t.writeBuffer.Write(p[0:remaining])
		if err := t.Flush(); err != nil {
			return 0, thrift.NewTTransportExceptionFromError(err)
		}
		return t.Write(p[remaining:])
	}
	return t.writeBuffer.Write(p)
}

func (t *natsTransport) Flush() error {
	data := t.writeBuffer.Bytes()
	err := t.conn.Publish(t.replyTo, data)
	t.writeBuffer.Reset()
	return thrift.NewTTransportExceptionFromError(err)
}

func (t *natsTransport) RemainingBytes() uint64 {
	return ^uint64(0) // We just don't know unless framed is used.
}

func (t *natsTransport) startHeartbeat() {
	for {
		select {
		case <-time.After(t.heartbeatInterval):
			if err := t.conn.Publish(t.heartbeat, nil); err != nil {
				log.Println("thrift_nats: error sending heartbeat", err)
			}
		case <-t.closed:
			return
		}
	}
}
<|endoftext|>


<commit_before>package router

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"reflect"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"

	cf_tcp_router "github.com/cloudfoundry-incubator/cf-tcp-router"
	"github.com/cloudfoundry-incubator/cf-tcp-router-acceptance-tests/assets/tcp-sample-receiver/testrunner"
)

const (
	DEFAULT_CONNECT_TIMEOUT = 1 * time.Second
	CONN_TYPE               = "tcp"
)

var _ = Describe("Routing Test", func() {
	var (
		externalPort        int
		sampleReceiverPort1 int
		sampleReceiverPort2 int
		serverId1           string
		serverId2           string

		receiver1 ifrit.Process
		receiver2 ifrit.Process
	)

	configureMapping := func(externalPort int, backendPorts ...int) {
		backends := cf_tcp_router.BackendHostInfos{}
		for _, backendPort := range backendPorts {
			backends = append(backends, cf_tcp_router.NewBackendHostInfo(externalIP, uint16(backendPort)))
		}

		createMappingRequest := cf_tcp_router.MappingRequests{
			cf_tcp_router.NewMappingRequest(uint16(externalPort), backends),
		}
		payload, err := json.Marshal(createMappingRequest)

		Expect(err).ToNot(HaveOccurred())

		resp, err := http.Post(fmt.Sprintf(
			"http://%s:%d/v0/external_ports",
			routerApiConfig.Address, routerApiConfig.Port),
			"application/json", bytes.NewBuffer(payload))
		Expect(err).ToNot(HaveOccurred())

		Expect(resp.StatusCode).Should(Equal(http.StatusOK))
	}

	checkConnection := func(errChan chan error, address string, serverId string) {
		time.Sleep(2 * time.Second)
		conn, err := net.DialTimeout(CONN_TYPE, address, DEFAULT_CONNECT_TIMEOUT)
		if err != nil {
			errChan <- err
			return
		}

		nanoSeconds := time.Now().Nanosecond()
		message := []byte(fmt.Sprintf("Time is %d", nanoSeconds))
		_, err = conn.Write(message)
		if err != nil {
			errChan <- err
			return
		}

		expectedMessage := []byte(serverId + ":" + string(message))
		buff := make([]byte, len(expectedMessage))
		_, err = conn.Read(buff)
		if err != nil {
			errChan <- err
			return
		}

		if !reflect.DeepEqual(buff, expectedMessage) {
			errChan <- errors.New(fmt.Sprintf("Message mismatch. Actual=[%s], Expected=[%s]", string(buff), string(expectedMessage)))
			return
		}
		errChan <- conn.Close()
	}

	verifyConnection := func(externalPort int, serverId string) {
		errChan := make(chan error, 1)
		address := fmt.Sprintf("%s:%d", routerApiConfig.Address, externalPort)
		go checkConnection(errChan, address, serverId)
		i := 0
	OUTERLOOP:
		for {
			select {
			case err := <-errChan:
				if err != nil {
					logger.Info(fmt.Sprintf("\n%d - Recevied error on errchan:%s\n", i, err.Error()))
					if i < 10 {
						i = i + 1
						go checkConnection(errChan, address, serverId)
					} else {
						Expect(err).ShouldNot(HaveOccurred())
					}
				} else {
					break OUTERLOOP
				}
			}
		}
	}

	spinupTcpReceiver := func(port int, id string) ifrit.Process {
		sampleReceiverArgs := testrunner.Args{
			Address:  fmt.Sprintf("%s:%d", externalIP, port),
			ServerId: id,
		}
		runner1 := testrunner.New(sampleReceiverPath, sampleReceiverArgs)
		return ifrit.Invoke(runner1)
	}

	tearDownTcpReceiver := func(receiverProcess ifrit.Process) {
		ginkgomon.Kill(receiverProcess, 5*time.Second)
	}

	Describe("A sample receiver running as a separate process", func() {
		BeforeEach(func() {
			externalPort = 60000 + GinkgoParallelNode()
			sampleReceiverPort1 = 9000 + GinkgoParallelNode()
			sampleReceiverPort2 = 9500 + GinkgoParallelNode()
			serverId1 = "serverId1"
			serverId2 = "serverId2"

			receiver1 = spinupTcpReceiver(sampleReceiverPort1, serverId1)
			receiver2 = spinupTcpReceiver(sampleReceiverPort2, serverId2)
		})

		AfterEach(func() {
			tearDownTcpReceiver(receiver1)
			tearDownTcpReceiver(receiver2)
		})

		It("routes traffic to sample receiver", func() {
			configureMapping(externalPort, sampleReceiverPort1)
			verifyConnection(externalPort, serverId1)

			By("altering the mapping it routes to new backend")
			configureMapping(externalPort, sampleReceiverPort2)
			verifyConnection(externalPort, serverId2)
		})
	})

	Describe("Multiple sample receivers running as a separate process and mapped to same external port", func() {

		sendAndReceive := func(address string) (net.Conn, string) {
			conn, err := net.DialTimeout(CONN_TYPE, address, DEFAULT_CONNECT_TIMEOUT)
			Expect(err).ShouldNot(HaveOccurred())

			message := "Hello"
			_, err = conn.Write([]byte(message))
			Expect(err).ShouldNot(HaveOccurred())

			response := make([]byte, 1024)
			count, err := conn.Read(response)
			Expect(err).ShouldNot(HaveOccurred())

			return conn, string(response[0:count])
		}

		BeforeEach(func() {
			externalPort = 61000 + GinkgoParallelNode()
			sampleReceiverPort1 = 7000 + GinkgoParallelNode()
			sampleReceiverPort2 = 7500 + GinkgoParallelNode()
			serverId1 = "serverId3"
			serverId2 = "serverId4"

			receiver1 = spinupTcpReceiver(sampleReceiverPort1, serverId1)
			receiver2 = spinupTcpReceiver(sampleReceiverPort2, serverId2)
		})

		AfterEach(func() {
			tearDownTcpReceiver(receiver1)
			tearDownTcpReceiver(receiver2)
		})

		It("load balances the connections", func() {
			configureMapping(externalPort, sampleReceiverPort1, sampleReceiverPort2)
			address := fmt.Sprintf("%s:%d", routerApiConfig.Address, externalPort)
			Eventually(func() error {
				tmpconn, err := net.Dial(CONN_TYPE, address)
				if err == nil {
					tmpconn.Close()
				}
				return err
			}, 10*time.Second, 1*time.Second).ShouldNot(HaveOccurred())

			conn1, response1 := sendAndReceive(address)
			conn2, response2 := sendAndReceive(address)
			Expect(response1).ShouldNot(Equal(response2))

			err := conn1.Close()
			Expect(err).ShouldNot(HaveOccurred())
			err = conn2.Close()
			Expect(err).ShouldNot(HaveOccurred())
		})
	})
})
<commit_msg>Increased the timeout for waiting on haproxy to open a new port<commit_after>package router

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"reflect"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"

	cf_tcp_router "github.com/cloudfoundry-incubator/cf-tcp-router"
	"github.com/cloudfoundry-incubator/cf-tcp-router-acceptance-tests/assets/tcp-sample-receiver/testrunner"
)

const (
	DEFAULT_CONNECT_TIMEOUT = 1 * time.Second
	CONN_TYPE               = "tcp"
)

var _ = Describe("Routing Test", func() {
	var (
		externalPort        int
		sampleReceiverPort1 int
		sampleReceiverPort2 int
		serverId1           string
		serverId2           string

		receiver1 ifrit.Process
		receiver2 ifrit.Process
	)

	configureMapping := func(externalPort int, backendPorts ...int) {
		backends := cf_tcp_router.BackendHostInfos{}
		for _, backendPort := range backendPorts {
			backends = append(backends, cf_tcp_router.NewBackendHostInfo(externalIP, uint16(backendPort)))
		}

		createMappingRequest := cf_tcp_router.MappingRequests{
			cf_tcp_router.NewMappingRequest(uint16(externalPort), backends),
		}
		payload, err := json.Marshal(createMappingRequest)

		Expect(err).ToNot(HaveOccurred())

		resp, err := http.Post(fmt.Sprintf(
			"http://%s:%d/v0/external_ports",
			routerApiConfig.Address, routerApiConfig.Port),
			"application/json", bytes.NewBuffer(payload))
		Expect(err).ToNot(HaveOccurred())

		Expect(resp.StatusCode).Should(Equal(http.StatusOK))
	}

	checkConnection := func(errChan chan error, address string, serverId string) {
		time.Sleep(2 * time.Second)
		conn, err := net.DialTimeout(CONN_TYPE, address, DEFAULT_CONNECT_TIMEOUT)
		if err != nil {
			errChan <- err
			return
		}

		nanoSeconds := time.Now().Nanosecond()
		message := []byte(fmt.Sprintf("Time is %d", nanoSeconds))
		_, err = conn.Write(message)
		if err != nil {
			errChan <- err
			return
		}

		expectedMessage := []byte(serverId + ":" + string(message))
		buff := make([]byte, len(expectedMessage))
		_, err = conn.Read(buff)
		if err != nil {
			errChan <- err
			return
		}

		if !reflect.DeepEqual(buff, expectedMessage) {
			errChan <- errors.New(fmt.Sprintf("Message mismatch. Actual=[%s], Expected=[%s]", string(buff), string(expectedMessage)))
			return
		}
		errChan <- conn.Close()
	}

	verifyConnection := func(externalPort int, serverId string) {
		errChan := make(chan error, 1)
		address := fmt.Sprintf("%s:%d", routerApiConfig.Address, externalPort)
		go checkConnection(errChan, address, serverId)
		i := 0
	OUTERLOOP:
		for {
			select {
			case err := <-errChan:
				if err != nil {
					logger.Info(fmt.Sprintf("\n%d - Recevied error on errchan:%s\n", i, err.Error()))
					if i < 10 {
						i = i + 1
						go checkConnection(errChan, address, serverId)
					} else {
						Expect(err).ShouldNot(HaveOccurred())
					}
				} else {
					break OUTERLOOP
				}
			}
		}
	}

	spinupTcpReceiver := func(port int, id string) ifrit.Process {
		sampleReceiverArgs := testrunner.Args{
			Address:  fmt.Sprintf("%s:%d", externalIP, port),
			ServerId: id,
		}
		runner1 := testrunner.New(sampleReceiverPath, sampleReceiverArgs)
		return ifrit.Invoke(runner1)
	}

	tearDownTcpReceiver := func(receiverProcess ifrit.Process) {
		ginkgomon.Kill(receiverProcess, 5*time.Second)
	}

	Describe("A sample receiver running as a separate process", func() {
		BeforeEach(func() {
			externalPort = 60000 + GinkgoParallelNode()
			sampleReceiverPort1 = 9000 + GinkgoParallelNode()
			sampleReceiverPort2 = 9500 + GinkgoParallelNode()
			serverId1 = "serverId1"
			serverId2 = "serverId2"

			receiver1 = spinupTcpReceiver(sampleReceiverPort1, serverId1)
			receiver2 = spinupTcpReceiver(sampleReceiverPort2, serverId2)
		})

		AfterEach(func() {
			tearDownTcpReceiver(receiver1)
			tearDownTcpReceiver(receiver2)
		})

		It("routes traffic to sample receiver", func() {
			configureMapping(externalPort, sampleReceiverPort1)
			verifyConnection(externalPort, serverId1)

			By("altering the mapping it routes to new backend")
			configureMapping(externalPort, sampleReceiverPort2)
			verifyConnection(externalPort, serverId2)
		})
	})

	Describe("Multiple sample receivers running as a separate process and mapped to same external port", func() {

		sendAndReceive := func(address string) (net.Conn, string) {
			conn, err := net.DialTimeout(CONN_TYPE, address, DEFAULT_CONNECT_TIMEOUT)
			Expect(err).ShouldNot(HaveOccurred())

			message := "Hello"
			_, err = conn.Write([]byte(message))
			Expect(err).ShouldNot(HaveOccurred())

			response := make([]byte, 1024)
			count, err := conn.Read(response)
			Expect(err).ShouldNot(HaveOccurred())

			return conn, string(response[0:count])
		}

		BeforeEach(func() {
			externalPort = 61000 + GinkgoParallelNode()
			sampleReceiverPort1 = 7000 + GinkgoParallelNode()
			sampleReceiverPort2 = 7500 + GinkgoParallelNode()
			serverId1 = "serverId3"
			serverId2 = "serverId4"

			receiver1 = spinupTcpReceiver(sampleReceiverPort1, serverId1)
			receiver2 = spinupTcpReceiver(sampleReceiverPort2, serverId2)
		})

		AfterEach(func() {
			tearDownTcpReceiver(receiver1)
			tearDownTcpReceiver(receiver2)
		})

		It("load balances the connections", func() {
			configureMapping(externalPort, sampleReceiverPort1, sampleReceiverPort2)
			address := fmt.Sprintf("%s:%d", routerApiConfig.Address, externalPort)
			Eventually(func() error {
				tmpconn, err := net.Dial(CONN_TYPE, address)
				if err == nil {
					tmpconn.Close()
				}
				return err
			}, 20*time.Second, 1*time.Second).ShouldNot(HaveOccurred())

			conn1, response1 := sendAndReceive(address)
			conn2, response2 := sendAndReceive(address)
			Expect(response1).ShouldNot(Equal(response2))

			err := conn1.Close()
			Expect(err).ShouldNot(HaveOccurred())
			err = conn2.Close()
			Expect(err).ShouldNot(HaveOccurred())
		})
	})
})
<|endoftext|>