<commit_before>package brightbox

import (
	"bytes"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/brightbox/gobrightbox"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceBrightboxLoadBalancer() *schema.Resource {
	return &schema.Resource{
		Create: resourceBrightboxLoadBalancerCreate,
		Read:   resourceBrightboxLoadBalancerRead,
		Update: resourceBrightboxLoadBalancerUpdate,
		Delete: resourceBrightboxLoadBalancerDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"policy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"certificate_pem": &schema.Schema{
				Type:      schema.TypeString,
				Optional:  true,
				StateFunc: hash_string,
			},
			"certificate_private_key": &schema.Schema{
				Type:      schema.TypeString,
				Optional:  true,
				StateFunc: hash_string,
			},
			"sslv3": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"locked": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"buffer_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"nodes": &schema.Schema{
				Type:     schema.TypeSet,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
			},
			"listener": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"in": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"out": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"timeout": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Default:  50000,
						},
					},
				},
				Set: resourceBrightboxLbListenerHash,
			},
			"healthcheck": &schema.Schema{
				Type:     schema.TypeList,
				MaxItems: 1,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"request": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},
						"interval": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"timeout": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"threshold_up": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"threshold_down": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func resourceBrightboxLbListenerHash(
	v interface{},
) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["in"].(int)))
	buf.WriteString(fmt.Sprintf("%s-",
		strings.ToLower(m["protocol"].(string))))
	buf.WriteString(fmt.Sprintf("%d-", m["out"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int)))

	return hashcode.String(buf.String())
}

func setLoadBalancerAttributes(
	d *schema.ResourceData,
	load_balancer *brightbox.LoadBalancer,
) {
	d.Set("name", load_balancer.Name)
	d.Set("status", load_balancer.Status)
	d.Set("locked", load_balancer.Locked)
	d.Set("policy", load_balancer.Policy)
	d.Set("buffer_size", load_balancer.BufferSize)

	nodeIds := make([]string, 0, len(load_balancer.Nodes))
	for _, node := range load_balancer.Nodes {
		nodeIds = append(nodeIds, node.Id)
	}
	d.Set("nodes", nodeIds)

	cipIds := make([]string, 0, len(load_balancer.CloudIPs))
	for _, cip := range load_balancer.CloudIPs {
		cipIds = append(cipIds, cip.Id)
	}
	d.Set("cloud_ips", cipIds)

	listeners := make([]map[string]interface{}, 0, len(load_balancer.Listeners))
	for _, listener := range load_balancer.Listeners {
		l := map[string]interface{}{
			"protocol": listener.Protocol,
			"in":       listener.In,
			"out":      listener.Out,
			"timeout":  listener.Timeout,
		}

		listeners = append(listeners, l)
	}
	d.Set("listener", listeners)
	log.Printf("[DEBUG] Healthcheck details are %#v", load_balancer.Healthcheck)
	healthchecks := make([]map[string]interface{}, 0, 1)
	chk := map[string]interface{}{
		"type":           load_balancer.Healthcheck.Type,
		"port":           load_balancer.Healthcheck.Port,
		"request":        load_balancer.Healthcheck.Request,
		"interval":       load_balancer.Healthcheck.Interval,
		"timeout":        load_balancer.Healthcheck.Timeout,
		"threshold_up":   load_balancer.Healthcheck.ThresholdUp,
		"threshold_down": load_balancer.Healthcheck.ThresholdDown,
	}
	healthchecks = append(healthchecks, chk)
	d.Set("healthcheck", healthchecks)
}

func loadBalancerStateRefresh(client *brightbox.Client, loadBalancerID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		loadBalancer, err := client.LoadBalancer(loadBalancerID)
		if err != nil {
			log.Printf("Error on Load Balancer State Refresh: %s", err)
			return nil, "", err
		}
		return loadBalancer, loadBalancer.Status, nil
	}
}

func resourceBrightboxLoadBalancerCreate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer create called")
	load_balancer_opts := &brightbox.LoadBalancerOptions{}

	err := addUpdateableLoadBalancerOptions(d, load_balancer_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Load Balancer create configuration %#v", load_balancer_opts)
	output_load_balancer_options(load_balancer_opts)

	load_balancer, err := client.CreateLoadBalancer(load_balancer_opts)
	if err != nil {
		return fmt.Errorf("Error creating server: %s", err)
	}

	d.SetId(load_balancer.Id)

	log.Printf("[INFO] Waiting for Load Balancer (%s) to become available", d.Id())

	stateConf := resource.StateChangeConf{
		Pending:    []string{"creating"},
		Target:     []string{"active"},
		Refresh:    loadBalancerStateRefresh(client, load_balancer.Id),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}
	active_load_balancer, err := stateConf.WaitForState()
	if err != nil {
		return err
	}

	setLoadBalancerAttributes(d, active_load_balancer.(*brightbox.LoadBalancer))

	return nil
}

func resourceBrightboxLoadBalancerRead(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer read called for %s", d.Id())
	load_balancer, err := client.LoadBalancer(d.Id())
	if err != nil {
		if strings.HasPrefix(err.Error(), "missing_resource:") {
			log.Printf("[WARN] Load Balancer not found, removing from state: %s", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error retrieving Load Balancer details: %s", err)
	}

	setLoadBalancerAttributes(d, load_balancer)

	return nil
}

func resourceBrightboxLoadBalancerUpdate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer update called for %s", d.Id())
	load_balancer_opts := &brightbox.LoadBalancerOptions{
		Id: d.Id(),
	}

	err := addUpdateableLoadBalancerOptions(d, load_balancer_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Load Balancer update configuration %#v", load_balancer_opts)
	output_load_balancer_options(load_balancer_opts)

	load_balancer, err := client.UpdateLoadBalancer(load_balancer_opts)
	if err != nil {
		return fmt.Errorf("Error updating load_balancer: %s", err)
	}

	setLoadBalancerAttributes(d, load_balancer)

	return nil
}

func resourceBrightboxLoadBalancerDelete(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer delete called for %s", d.Id())
	err := client.DestroyLoadBalancer(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting Load Balancer: %s", err)
	}
	stateConf := resource.StateChangeConf{
		Pending:    []string{"deleting", "active"},
		Target:     []string{"deleted"},
		Refresh:    loadBalancerStateRefresh(client, d.Id()),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}
	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}
	return nil
}

func addUpdateableLoadBalancerOptions(
	d *schema.ResourceData,
	opts *brightbox.LoadBalancerOptions,
) error {

	assign_string(d, &opts.Name, "name")
	assign_string(d, &opts.Policy, "policy")
	assign_string(d, &opts.CertificatePem, "certificate_pem")
	assign_string(d, &opts.CertificatePrivateKey, "certificate_private_key")
	assign_int(d, &opts.BufferSize, "buffer_size")
	assign_bool(d, &opts.SslV3, "sslv3")
	assign_listeners(d, &opts.Listeners)
	assign_nodes(d, &opts.Nodes)
	return assign_healthcheck(d, &opts.Healthcheck)
}

func assign_healthcheck(d *schema.ResourceData, target **brightbox.LoadBalancerHealthcheck) error {
	if d.HasChange("healthcheck") {
		hc := d.Get("healthcheck").([]interface{})
		check := hc[0].(map[string]interface{})
		temp := brightbox.LoadBalancerHealthcheck{
			Type: check["type"].(string),
			Port: check["port"].(int),
		}
		if attr, ok := check["request"]; ok {
			temp.Request = attr.(string)
		}
		if attr, ok := check["interval"]; ok {
			temp.Interval = attr.(int)
		}
		if attr, ok := check["timeout"]; ok {
			temp.Timeout = attr.(int)
		}
		if attr, ok := check["threshold_up"]; ok {
			temp.ThresholdUp = attr.(int)
		}
		if attr, ok := check["threshold_down"]; ok {
			temp.ThresholdDown = attr.(int)
		}
		*target = &temp
	}
	return nil
}

func assign_listeners(d *schema.ResourceData, target **[]brightbox.LoadBalancerListener) {
	if d.HasChange("listener") {
		*target = expandListeners(d.Get("listener").(*schema.Set).List())
	}
}

func assign_nodes(d *schema.ResourceData, target **[]brightbox.LoadBalancerNode) {
	if d.HasChange("nodes") {
		*target = expandNodes(d.Get("nodes").(*schema.Set).List())
	}
}

func expandListeners(configured []interface{}) *[]brightbox.LoadBalancerListener {
	listeners := make([]brightbox.LoadBalancerListener, len(configured))

	for i, listen_source := range configured {
		data := listen_source.(map[string]interface{})
		listeners[i].Protocol = data["protocol"].(string)
		listeners[i].In = data["in"].(int)
		listeners[i].Out = data["out"].(int)
		if attr, ok := data["timeout"]; ok {
			listeners[i].Timeout = attr.(int)
		}
	}
	return &listeners
}

func expandNodes(configured []interface{}) *[]brightbox.LoadBalancerNode {
	nodes := make([]brightbox.LoadBalancerNode, len(configured))

	for i, data := range configured {
		nodes[i].Node = data.(string)
	}
	return &nodes
}

func output_load_balancer_options(opts *brightbox.LoadBalancerOptions) {
	if opts.Name != nil {
		log.Printf("[DEBUG] Load Balancer Name %v", *opts.Name)
	}
	if opts.Nodes != nil {
		log.Printf("[DEBUG] Load Balancer Nodes %#v", *opts.Nodes)
	}
	if opts.Policy != nil {
		log.Printf("[DEBUG] Load Balancer Policy %v", *opts.Policy)
	}
	if opts.BufferSize != nil {
		log.Printf("[DEBUG] Load Balancer BufferSize %v", *opts.BufferSize)
	}
	if opts.Listeners != nil {
		log.Printf("[DEBUG] Load Balancer Listeners %#v", *opts.Listeners)
	}
	if opts.Healthcheck != nil {
		log.Printf("[DEBUG] Load Balancer Healthcheck %#v", *opts.Healthcheck)
	}
	if opts.CertificatePem != nil {
		log.Printf("[DEBUG] Load Balancer CertificatePem %v", *opts.CertificatePem)
	}
	if opts.CertificatePrivateKey != nil {
		log.Printf("[DEBUG] Load Balancer CertificatePrivateKey %v", *opts.CertificatePrivateKey)
	}
	if opts.SslV3 != nil {
		log.Printf("[DEBUG] Load Balancer SslV3 %v", *opts.SslV3)
	}
}
<commit_msg>Refactor Load Balancer<commit_after>package brightbox

import (
	"bytes"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/brightbox/gobrightbox"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceBrightboxLoadBalancer() *schema.Resource {
	return &schema.Resource{
		Create: resourceBrightboxLoadBalancerCreate,
		Read:   resourceBrightboxLoadBalancerRead,
		Update: resourceBrightboxLoadBalancerUpdate,
		Delete: resourceBrightboxLoadBalancerDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"policy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"certificate_pem": &schema.Schema{
				Type:      schema.TypeString,
				Optional:  true,
				StateFunc: hash_string,
			},
			"certificate_private_key": &schema.Schema{
				Type:      schema.TypeString,
				Optional:  true,
				StateFunc: hash_string,
			},
			"sslv3": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"locked": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"buffer_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"nodes": &schema.Schema{
				Type:     schema.TypeSet,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
			},
			"listener": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"in": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"out": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"timeout": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Default:  50000,
						},
					},
				},
				Set: resourceBrightboxLbListenerHash,
			},
			"healthcheck": &schema.Schema{
				Type:     schema.TypeList,
				MaxItems: 1,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"request": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},
						"interval": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"timeout": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"threshold_up": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"threshold_down": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func resourceBrightboxLbListenerHash(
	v interface{},
) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["in"].(int)))
	buf.WriteString(fmt.Sprintf("%s-",
		strings.ToLower(m["protocol"].(string))))
	buf.WriteString(fmt.Sprintf("%d-", m["out"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int)))

	return hashcode.String(buf.String())
}

func setLoadBalancerAttributes(
	d *schema.ResourceData,
	load_balancer *brightbox.LoadBalancer,
) error {
	d.Set("name", load_balancer.Name)
	d.Set("status", load_balancer.Status)
	d.Set("locked", load_balancer.Locked)
	d.Set("policy", load_balancer.Policy)
	d.Set("buffer_size", load_balancer.BufferSize)

	nodeIds := make([]string, 0, len(load_balancer.Nodes))
	for _, node := range load_balancer.Nodes {
		nodeIds = append(nodeIds, node.Id)
	}
	d.Set("nodes", nodeIds)

	cipIds := make([]string, 0, len(load_balancer.CloudIPs))
	for _, cip := range load_balancer.CloudIPs {
		cipIds = append(cipIds, cip.Id)
	}
	d.Set("cloud_ips", cipIds)

	listeners := make([]map[string]interface{}, 0, len(load_balancer.Listeners))
	for _, listener := range load_balancer.Listeners {
		l := map[string]interface{}{
			"protocol": listener.Protocol,
			"in":       listener.In,
			"out":      listener.Out,
			"timeout":  listener.Timeout,
		}

		listeners = append(listeners, l)
	}
	d.Set("listener", listeners)
	log.Printf("[DEBUG] Healthcheck details are %#v", load_balancer.Healthcheck)
	healthchecks := make([]map[string]interface{}, 0, 1)
	chk := map[string]interface{}{
		"type":           load_balancer.Healthcheck.Type,
		"port":           load_balancer.Healthcheck.Port,
		"request":        load_balancer.Healthcheck.Request,
		"interval":       load_balancer.Healthcheck.Interval,
		"timeout":        load_balancer.Healthcheck.Timeout,
		"threshold_up":   load_balancer.Healthcheck.ThresholdUp,
		"threshold_down": load_balancer.Healthcheck.ThresholdDown,
	}
	healthchecks = append(healthchecks, chk)
	d.Set("healthcheck", healthchecks)
	return nil
}

func loadBalancerStateRefresh(client *brightbox.Client, loadBalancerID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		loadBalancer, err := client.LoadBalancer(loadBalancerID)
		if err != nil {
			log.Printf("Error on Load Balancer State Refresh: %s", err)
			return nil, "", err
		}
		return loadBalancer, loadBalancer.Status, nil
	}
}

func resourceBrightboxLoadBalancerCreate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer create called")
	load_balancer_opts := &brightbox.LoadBalancerOptions{}

	err := addUpdateableLoadBalancerOptions(d, load_balancer_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Load Balancer create configuration %#v", load_balancer_opts)
	output_load_balancer_options(load_balancer_opts)

	load_balancer, err := client.CreateLoadBalancer(load_balancer_opts)
	if err != nil {
		return fmt.Errorf("Error creating server: %s", err)
	}

	d.SetId(load_balancer.Id)

	log.Printf("[INFO] Waiting for Load Balancer (%s) to become available", d.Id())

	stateConf := resource.StateChangeConf{
		Pending:    []string{"creating"},
		Target:     []string{"active"},
		Refresh:    loadBalancerStateRefresh(client, load_balancer.Id),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}
	active_load_balancer, err := stateConf.WaitForState()
	if err != nil {
		return err
	}

	return setLoadBalancerAttributes(d, active_load_balancer.(*brightbox.LoadBalancer))
}

func resourceBrightboxLoadBalancerRead(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer read called for %s", d.Id())
	load_balancer, err := client.LoadBalancer(d.Id())
	if err != nil {
		if strings.HasPrefix(err.Error(), "missing_resource:") {
			log.Printf("[WARN] Load Balancer not found, removing from state: %s", d.Id())
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error retrieving Load Balancer details: %s", err)
	}

	return setLoadBalancerAttributes(d, load_balancer)
}

func resourceBrightboxLoadBalancerUpdate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer update called for %s", d.Id())
	load_balancer_opts := &brightbox.LoadBalancerOptions{
		Id: d.Id(),
	}

	err := addUpdateableLoadBalancerOptions(d, load_balancer_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Load Balancer update configuration %#v", load_balancer_opts)
	output_load_balancer_options(load_balancer_opts)

	load_balancer, err := client.UpdateLoadBalancer(load_balancer_opts)
	if err != nil {
		return fmt.Errorf("Error updating load_balancer: %s", err)
	}

	return setLoadBalancerAttributes(d, load_balancer)
}

func resourceBrightboxLoadBalancerDelete(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*CompositeClient).ApiClient

	log.Printf("[DEBUG] Load Balancer delete called for %s", d.Id())
	err := client.DestroyLoadBalancer(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting Load Balancer: %s", err)
	}
	stateConf := resource.StateChangeConf{
		Pending:    []string{"deleting", "active"},
		Target:     []string{"deleted"},
		Refresh:    loadBalancerStateRefresh(client, d.Id()),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}
	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}
	return nil
}

func addUpdateableLoadBalancerOptions(
	d *schema.ResourceData,
	opts *brightbox.LoadBalancerOptions,
) error {

	assign_string(d, &opts.Name, "name")
	assign_string(d, &opts.Policy, "policy")
	assign_string(d, &opts.CertificatePem, "certificate_pem")
	assign_string(d, &opts.CertificatePrivateKey, "certificate_private_key")
	assign_int(d, &opts.BufferSize, "buffer_size")
	assign_bool(d, &opts.SslV3, "sslv3")
	assign_listeners(d, &opts.Listeners)
	assign_nodes(d, &opts.Nodes)
	return assign_healthcheck(d, &opts.Healthcheck)
}

func assign_healthcheck(d *schema.ResourceData, target **brightbox.LoadBalancerHealthcheck) error {
	if d.HasChange("healthcheck") {
		hc := d.Get("healthcheck").([]interface{})
		check := hc[0].(map[string]interface{})
		temp := brightbox.LoadBalancerHealthcheck{
			Type: check["type"].(string),
			Port: check["port"].(int),
		}
		if attr, ok := check["request"]; ok {
			temp.Request = attr.(string)
		}
		if attr, ok := check["interval"]; ok {
			temp.Interval = attr.(int)
		}
		if attr, ok := check["timeout"]; ok {
			temp.Timeout = attr.(int)
		}
		if attr, ok := check["threshold_up"]; ok {
			temp.ThresholdUp = attr.(int)
		}
		if attr, ok := check["threshold_down"]; ok {
			temp.ThresholdDown = attr.(int)
		}
		*target = &temp
	}
	return nil
}

func assign_listeners(d *schema.ResourceData, target **[]brightbox.LoadBalancerListener) {
	if d.HasChange("listener") {
		*target = expandListeners(d.Get("listener").(*schema.Set).List())
	}
}

func assign_nodes(d *schema.ResourceData, target **[]brightbox.LoadBalancerNode) {
	if d.HasChange("nodes") {
		*target = expandNodes(d.Get("nodes").(*schema.Set).List())
	}
}

func expandListeners(configured []interface{}) *[]brightbox.LoadBalancerListener {
	listeners := make([]brightbox.LoadBalancerListener, len(configured))

	for i, listen_source := range configured {
		data := listen_source.(map[string]interface{})
		listeners[i].Protocol = data["protocol"].(string)
		listeners[i].In = data["in"].(int)
		listeners[i].Out = data["out"].(int)
		if attr, ok := data["timeout"]; ok {
			listeners[i].Timeout = attr.(int)
		}
	}
	return &listeners
}

func expandNodes(configured []interface{}) *[]brightbox.LoadBalancerNode {
	nodes := make([]brightbox.LoadBalancerNode, len(configured))

	for i, data := range configured {
		nodes[i].Node = data.(string)
	}
	return &nodes
}

func output_load_balancer_options(opts *brightbox.LoadBalancerOptions) {
	if opts.Name != nil {
		log.Printf("[DEBUG] Load Balancer Name %v", *opts.Name)
	}
	if opts.Nodes != nil {
		log.Printf("[DEBUG] Load Balancer Nodes %#v", *opts.Nodes)
	}
	if opts.Policy != nil {
		log.Printf("[DEBUG] Load Balancer Policy %v", *opts.Policy)
	}
	if opts.BufferSize != nil {
		log.Printf("[DEBUG] Load Balancer BufferSize %v", *opts.BufferSize)
	}
	if opts.Listeners != nil {
		log.Printf("[DEBUG] Load Balancer Listeners %#v", *opts.Listeners)
	}
	if opts.Healthcheck != nil {
		log.Printf("[DEBUG] Load Balancer Healthcheck %#v", *opts.Healthcheck)
	}
	if opts.CertificatePem != nil {
		log.Printf("[DEBUG] Load Balancer CertificatePem %v", *opts.CertificatePem)
	}
	if opts.CertificatePrivateKey != nil {
		log.Printf("[DEBUG] Load Balancer CertificatePrivateKey %v", *opts.CertificatePrivateKey)
	}
	if opts.SslV3 != nil {
		log.Printf("[DEBUG] Load Balancer SslV3 %v", *opts.SslV3)
	}
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"
	"sync"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"golang.org/x/net/context"
)

// ConnectionHandler is the callback interface for interacting with the connection.
type ConnectionHandler interface {
	// OnConnect is called immediately after a connection has been established.
	// An implementation would likely log something and/or perform authentication.
	OnConnect(context.Context, *Connection, keybase1.GenericClient) error

	// OnConnectError is called whenever there is an error during connection.
	OnConnectError(err error, reconnectThrottleDuration time.Duration)
}

// ConnectionTransportTLS is a ConnectionTransport implementation that uses TLS+rpc2.
type ConnectionTransportTLS struct {
	config          Config
	unwrapErrFunc   rpc2.UnwrapErrorFunc
	transport       *rpc2.Transport
	stagedTransport *rpc2.Transport
	mutex           sync.Mutex // protects transport
}

// Test that ConnectionTransportTLS fully implements the ConnectionTransport interface.
var _ ConnectionTransport = (*ConnectionTransportTLS)(nil)

// Dial is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) Dial(ctx context.Context, srvAddr string) (
	keybase1.GenericClient, error) {
	var conn net.Conn
	var err error
	err = runUnlessCanceled(ctx, func() error {
		// load CA certificate
		certs := x509.NewCertPool()
		if !certs.AppendCertsFromPEM(ct.config.CACert()) {
			return errors.New("Unable to load CA certificate")
		}
		// connect
		config := tls.Config{RootCAs: certs}
		conn, err = tls.Dial("tcp", srvAddr, &config)
		return err
	})
	if err != nil {
		return nil, err
	}

	ct.stagedTransport = rpc2.NewTransport(conn, libkb.NewRPCLogFactory(), libkb.WrapError)
	client := rpc2.NewClient(ct.stagedTransport, ct.unwrapErrFunc)
	return client, nil
}

// IsConnected is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) IsConnected() bool {
	ct.mutex.Lock()
	defer ct.mutex.Unlock()
	return ct.transport != nil && ct.transport.IsConnected()
}

// Finalize is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) Finalize() {
	ct.mutex.Lock()
	defer ct.mutex.Unlock()
	ct.transport = ct.stagedTransport
	ct.stagedTransport = nil
}

// Connection encapsulates all client connection handling.
type Connection struct {
	config    Config
	srvAddr   string
	handler   ConnectionHandler
	transport ConnectionTransport

	mutex         sync.Mutex // protects: client, reconnectChan, and cancelFunc
	client        keybase1.GenericClient
	reconnectChan chan struct{}
	cancelFunc    context.CancelFunc // used to cancel the reconnect loop
}

// NewConnection returns a newly connected connection.
func NewConnection(ctx context.Context, config Config, srvAddr string,
	handler ConnectionHandler, errFunc rpc2.UnwrapErrorFunc) *Connection {
	transport := &ConnectionTransportTLS{config: config, unwrapErrFunc: errFunc}
	return newConnectionWithTransport(ctx, config, srvAddr, handler, transport)
}

// Separate from NewConnection to allow for unit testing.
func newConnectionWithTransport(ctx context.Context, config Config, srvAddr string,
	handler ConnectionHandler, transport ConnectionTransport) *Connection {
	connection := &Connection{
		srvAddr:   srvAddr,
		config:    config,
		handler:   handler,
		transport: transport,
	}
	connection.getReconnectChan() // start connecting
	return connection
}

// connect performs the actual connect() and rpc setup.
func (c *Connection) connect(ctx context.Context) error {
	// connect
	client, err := c.transport.Dial(ctx, c.srvAddr)
	if err != nil {
		return err
	}

	// call the connect handler
	err = c.handler.OnConnect(ctx, c, client)
	if err != nil {
		return err
	}

	// set the client for other callers.
	// we wait to do this so the handler has time to do
	// any setup required, e.g. authenticate.
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.client = client
	c.transport.Finalize()

	return nil
}

// DoCommand executes the specific rpc command wrapped in rpcFunc.
func (c *Connection) DoCommand(ctx context.Context, rpcFunc func() error) error {
	for {
		// we may or may not be in the process of reconnecting.
		// if so we'll block here unless canceled by the caller.
		err := c.waitForConnection(ctx)
		if err != nil {
			return err
		}
		// try the rpc call. this can also be canceled by the caller.
		err = runUnlessCanceled(ctx, rpcFunc)
		// check to see if we need to retry it.
		if !c.checkForRetry(err) {
			return err
		}
	}
}

// Blocks until a connnection is ready for use or the context is canceled.
func (c *Connection) waitForConnection(ctx context.Context) error {
	if c.IsConnected() {
		// already connected
		return nil
	}
	// kick-off a connection and wait for it to complete
	// or for the caller to cancel.
	reconnectChan := c.getReconnectChan()
	select {
	case <-ctx.Done():
		// caller canceled
		return ctx.Err()
	case <-reconnectChan:
		// reconnect complete
		return nil
	}
}

// Returns true if the error indicates we should retry the command.
func (c *Connection) checkForRetry(err error) bool {
	if err == nil {
		return false
	}
	_, disconnected := err.(rpc2.DisconnectedError)
	_, eof := err.(rpc2.EofError)
	return disconnected || eof
}

// IsConnected returns true if the connection is connected.
func (c *Connection) IsConnected() bool {
	return c.transport.IsConnected()
}

// This will either kick-off a new reconnection attempt or wait for an
// existing attempt. Returns the channel associated with an attempt.
func (c *Connection) getReconnectChan() chan struct{} {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if c.reconnectChan == nil {
		var ctx context.Context
		// for canceleing the reconnect loop via Shutdown()
		ctx, c.cancelFunc = context.WithCancel(context.Background())
		c.reconnectChan = make(chan struct{}, 20)
		go c.doReconnect(ctx, c.reconnectChan)
	}
	return c.reconnectChan
}

// doReconnect attempts a reconnection.
func (c *Connection) doReconnect(ctx context.Context, reconnectChan chan struct{}) {
	// retry w/exponential backoff
	backoff.RetryNotify(func() error {
		// try to connect
		err := c.connect(ctx)
		// context was canceled by Shutdown()
		if ctx.Err() != nil {
			c.handler = nil // drop the circular reference
			// short-circuit Retry
			return nil
		}
		return err
	}, backoff.NewExponentialBackOff(),
		// give the caller a chance to log any other error or adjust state
		c.handler.OnConnectError)

	// close the reconnect channel to signal we're connected.
	c.mutex.Lock()
	defer c.mutex.Unlock()
	close(reconnectChan)
	c.reconnectChan = nil
	c.cancelFunc = nil
}

// GetClient is called to retrieve an rpc client suitable for use by the caller.
func (c *Connection) GetClient() keybase1.GenericClient {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.client
}

// Shutdown cancels any reconnect loop in progress.
// Calling this invalidates the connection object.
func (c *Connection) Shutdown() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	// cancel any reconnect loop
	if c.cancelFunc != nil {
		c.cancelFunc()
	}
	// TODO: I think it would be ideal for this to also close
	// the transport but the rpc2 package doesn't appear to
	// expose that ability at the moment.
}
<commit_msg>connection: fix typo<commit_after>package libkbfs

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"
	"sync"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"golang.org/x/net/context"
)

// ConnectionHandler is the callback interface for interacting with the connection.
type ConnectionHandler interface {
	// OnConnect is called immediately after a connection has been established.
	// An implementation would likely log something and/or perform authentication.
	OnConnect(context.Context, *Connection, keybase1.GenericClient) error

	// OnConnectError is called whenever there is an error during connection.
	OnConnectError(err error, reconnectThrottleDuration time.Duration)
}

// ConnectionTransportTLS is a ConnectionTransport implementation that uses TLS+rpc2.
type ConnectionTransportTLS struct {
	config          Config
	unwrapErrFunc   rpc2.UnwrapErrorFunc
	transport       *rpc2.Transport
	stagedTransport *rpc2.Transport
	mutex           sync.Mutex // protects transport
}

// Test that ConnectionTransportTLS fully implements the ConnectionTransport interface.
var _ ConnectionTransport = (*ConnectionTransportTLS)(nil)

// Dial is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) Dial(ctx context.Context, srvAddr string) (
	keybase1.GenericClient, error) {
	var conn net.Conn
	var err error
	err = runUnlessCanceled(ctx, func() error {
		// load CA certificate
		certs := x509.NewCertPool()
		if !certs.AppendCertsFromPEM(ct.config.CACert()) {
			return errors.New("Unable to load CA certificate")
		}
		// connect
		config := tls.Config{RootCAs: certs}
		conn, err = tls.Dial("tcp", srvAddr, &config)
		return err
	})
	if err != nil {
		return nil, err
	}

	ct.stagedTransport = rpc2.NewTransport(conn, libkb.NewRPCLogFactory(), libkb.WrapError)
	client := rpc2.NewClient(ct.stagedTransport, ct.unwrapErrFunc)
	return client, nil
}

// IsConnected is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) IsConnected() bool {
	ct.mutex.Lock()
	defer ct.mutex.Unlock()
	return ct.transport != nil && ct.transport.IsConnected()
}

// Finalize is an implementation of the ConnectionTransport interface.
func (ct *ConnectionTransportTLS) Finalize() {
	ct.mutex.Lock()
	defer ct.mutex.Unlock()
	ct.transport = ct.stagedTransport
	ct.stagedTransport = nil
}

// Connection encapsulates all client connection handling.
type Connection struct {
	config    Config
	srvAddr   string
	handler   ConnectionHandler
	transport ConnectionTransport

	mutex         sync.Mutex // protects: client, reconnectChan, and cancelFunc
	client        keybase1.GenericClient
	reconnectChan chan struct{}
	cancelFunc    context.CancelFunc // used to cancel the reconnect loop
}

// NewConnection returns a newly connected connection.
func NewConnection(ctx context.Context, config Config, srvAddr string,
	handler ConnectionHandler, errFunc rpc2.UnwrapErrorFunc) *Connection {
	transport := &ConnectionTransportTLS{config: config, unwrapErrFunc: errFunc}
	return newConnectionWithTransport(ctx, config, srvAddr, handler, transport)
}

// Separate from NewConnection to allow for unit testing.
func newConnectionWithTransport(ctx context.Context, config Config, srvAddr string,
	handler ConnectionHandler, transport ConnectionTransport) *Connection {
	connection := &Connection{
		srvAddr:   srvAddr,
		config:    config,
		handler:   handler,
		transport: transport,
	}
	connection.getReconnectChan() // start connecting
	return connection
}

// connect performs the actual connect() and rpc setup.
func (c *Connection) connect(ctx context.Context) error {
	// connect
	client, err := c.transport.Dial(ctx, c.srvAddr)
	if err != nil {
		return err
	}

	// call the connect handler
	err = c.handler.OnConnect(ctx, c, client)
	if err != nil {
		return err
	}

	// set the client for other callers.
	// we wait to do this so the handler has time to do
	// any setup required, e.g. authenticate.
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.client = client
	c.transport.Finalize()

	return nil
}

// DoCommand executes the specific rpc command wrapped in rpcFunc.
func (c *Connection) DoCommand(ctx context.Context, rpcFunc func() error) error {
	for {
		// we may or may not be in the process of reconnecting.
		// if so we'll block here unless canceled by the caller.
		err := c.waitForConnection(ctx)
		if err != nil {
			return err
		}
		// try the rpc call. this can also be canceled by the caller.
		err = runUnlessCanceled(ctx, rpcFunc)
		// check to see if we need to retry it.
		if !c.checkForRetry(err) {
			return err
		}
	}
}

// Blocks until a connnection is ready for use or the context is canceled.
func (c *Connection) waitForConnection(ctx context.Context) error {
	if c.IsConnected() {
		// already connected
		return nil
	}
	// kick-off a connection and wait for it to complete
	// or for the caller to cancel.
	reconnectChan := c.getReconnectChan()
	select {
	case <-ctx.Done():
		// caller canceled
		return ctx.Err()
	case <-reconnectChan:
		// reconnect complete
		return nil
	}
}

// Returns true if the error indicates we should retry the command.
func (c *Connection) checkForRetry(err error) bool {
	if err == nil {
		return false
	}
	_, disconnected := err.(rpc2.DisconnectedError)
	_, eof := err.(rpc2.EofError)
	return disconnected || eof
}

// IsConnected returns true if the connection is connected.
func (c *Connection) IsConnected() bool {
	return c.transport.IsConnected()
}

// This will either kick-off a new reconnection attempt or wait for an
// existing attempt. Returns the channel associated with an attempt.
func (c *Connection) getReconnectChan() chan struct{} {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if c.reconnectChan == nil {
		var ctx context.Context
		// for canceling the reconnect loop via Shutdown()
		ctx, c.cancelFunc = context.WithCancel(context.Background())
		c.reconnectChan = make(chan struct{}, 20)
		go c.doReconnect(ctx, c.reconnectChan)
	}
	return c.reconnectChan
}

// doReconnect attempts a reconnection.
func (c *Connection) doReconnect(ctx context.Context, reconnectChan chan struct{}) {
	// retry w/exponential backoff
	backoff.RetryNotify(func() error {
		// try to connect
		err := c.connect(ctx)
		// context was canceled by Shutdown()
		if ctx.Err() != nil {
			c.handler = nil // drop the circular reference
			// short-circuit Retry
			return nil
		}
		return err
	}, backoff.NewExponentialBackOff(),
		// give the caller a chance to log any other error or adjust state
		c.handler.OnConnectError)

	// close the reconnect channel to signal we're connected.
	c.mutex.Lock()
	defer c.mutex.Unlock()
	close(reconnectChan)
	c.reconnectChan = nil
	c.cancelFunc = nil
}

// GetClient is called to retrieve an rpc client suitable for use by the caller.
func (c *Connection) GetClient() keybase1.GenericClient {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.client
}

// Shutdown cancels any reconnect loop in progress.
// Calling this invalidates the connection object.
func (c *Connection) Shutdown() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	// cancel any reconnect loop
	if c.cancelFunc != nil {
		c.cancelFunc()
	}
	// TODO: I think it would be ideal for this to also close
	// the transport but the rpc2 package doesn't appear to
	// expose that ability at the moment.
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"math/rand"
	"net/mail"
	"strconv"
	"time"

	"log"

	"github.com/extemporalgenome/slug"
	"github.com/joshsoftware/curem/config"
	"labix.org/v2/mgo/bson"
)

// contact type holds the fields related to a particular contact.
// omitempty tag will make sure the database doesn't contain content like:
//
//   {
//    _id: someId
//    company: ABC
//    Person: Xyz
//    Phone:
//    Skype:
//    Country:
//   }
// Instead, it will store the above data as:
//
//   {
//    _id: someId
//    company: ABC
//    Person: Xyz
//   }
type contact struct {
	Id        bson.ObjectId `bson:"_id"                  json:"id"`
	Company   string        `bson:"company,omitempty"    json:"company,omitempty"`
	Person    string        `bson:"person,omitempty"     json:"person,omitempty"`
	Slug      string        `bson:"slug,omitempty"       json:"slug,omitempty"`
	Email     string        `bson:"email,omitempty"      json:"email,omitempty"`
	Phone     string        `bson:"phone,omitempty"      json:"phone,omitempty"`
	SkypeId   string        `bson:"skypeid,omitempty"    json:"skypeid,omitempty"`
	Country   string        `bson:"country,omitempty"    json:"country,omitempty"`
	CreatedAt time.Time     `bson:"createdAt,omitempty"  json:"createdAt,omitempty"`
	UpdatedAt time.Time     `bson:"updatedAt,omitempty"  json:"updatedAt,omitempty"`
}

func validateContact(c *contact) error {
	if c.Person == "" {
		err := errors.New("person can't be empty")
		return err
	}
	if c.Email == "" {
		err := errors.New("email can't be empty")
		return err
	}
	if _, err := mail.ParseAddress(c.Email); err != nil {
		return err
	}

	return nil
}

// NewContact takes the fields of a contact, initializes a struct of contact type and returns
// the pointer to that struct.
func NewContact(company, person, email, phone, skypeid, country string) (*contact, error) {
	doc := contact{
		Id:      bson.NewObjectId(),
		Company: company,
		Person:  person,
		Email:   email,
		Phone:   phone,
		SkypeId: skypeid,
		Country: country,
	}
	if err := validateContact(&doc); err != nil {
		return &contact{}, err
	}
	slugify(&doc)

	doc.CreatedAt = doc.Id.Time()
	doc.UpdatedAt = doc.CreatedAt

	err := config.ContactsCollection.Insert(doc)
	if err != nil {
		return &contact{}, err
	}
	return &doc, nil
}

// GetContact takes the contact Id as an argument and returns a pointer to a contact object.
func GetContact(i bson.ObjectId) (*contact, error) {
	var c contact
	err := config.ContactsCollection.FindId(i).One(&c)
	if err != nil {
		return &contact{}, err
	}
	return &c, nil
}

// GetAllContacts fetches all the contacts from the database.
func GetAllContacts() ([]contact, error) {
	var c []contact
	err := config.ContactsCollection.Find(nil).All(&c)
	if err != nil {
		return []contact{}, err
	}
	return c, nil
}

// Update updates the contact in the database.
// First, fetch a contact from the database and change the necessary fields.
// Then call the Update method on that contact object.
func (c *contact) Update() error {
	if err := validateContact(c); err != nil {
		return err
	}
	c.UpdatedAt = bson.Now()
	err := config.ContactsCollection.UpdateId(c.Id, c)
	return err
}

// Delete deletes the contact from the database.
func (c *contact) Delete() error {
	return config.ContactsCollection.RemoveId(c.Id)
}

func slugify(c *contact) {
	base := slug.SlugAscii(c.Person)
	temp := base
	rand.Seed(time.Now().UnixNano()) // takes the current time in nanoseconds as the seed
	i := rand.Intn(10000)
	for {
		if slugExists(temp) {
			temp = base + "-" + strconv.Itoa(i)
			i = rand.Intn(10000)
		} else {
			c.Slug = temp
			return
		}

	}
}

func slugExists(slug string) bool {
	var c []contact
	err := config.ContactsCollection.Find(bson.M{"slug": slug}).All(&c)
	if err != nil {
		log.Fatalf("%s", err)
	}
	if len(c) == 0 {
		return false
	}
	return true
}
<commit_msg>Add GetContactBySlug function<commit_after>package main

import (
	"errors"
	"math/rand"
	"net/mail"
	"strconv"
	"time"

	"log"

	"github.com/extemporalgenome/slug"
	"github.com/joshsoftware/curem/config"
	"labix.org/v2/mgo/bson"
)

// contact type holds the fields related to a particular contact.
// omitempty tag will make sure the database doesn't contain content like:
//
//   {
//    _id: someId
//    company: ABC
//    Person: Xyz
//    Phone:
//    Skype:
//    Country:
//   }
// Instead, it will store the above data as:
//
//   {
//    _id: someId
//    company: ABC
//    Person: Xyz
//   }
type contact struct {
	Id        bson.ObjectId `bson:"_id"                  json:"id"`
	Company   string        `bson:"company,omitempty"    json:"company,omitempty"`
	Person    string        `bson:"person,omitempty"     json:"person,omitempty"`
	Slug      string        `bson:"slug,omitempty"       json:"slug,omitempty"`
	Email     string        `bson:"email,omitempty"      json:"email,omitempty"`
	Phone     string        `bson:"phone,omitempty"      json:"phone,omitempty"`
	SkypeId   string        `bson:"skypeid,omitempty"    json:"skypeid,omitempty"`
	Country   string        `bson:"country,omitempty"    json:"country,omitempty"`
	CreatedAt time.Time     `bson:"createdAt,omitempty"  json:"createdAt,omitempty"`
	UpdatedAt time.Time     `bson:"updatedAt,omitempty"  json:"updatedAt,omitempty"`
}

func validateContact(c *contact) error {
	if c.Person == "" {
		err := errors.New("person can't be empty")
		return err
	}
	if c.Email == "" {
		err := errors.New("email can't be empty")
		return err
	}
	if _, err := mail.ParseAddress(c.Email); err != nil {
		return err
	}

	return nil
}

// NewContact takes the fields of a contact, initializes a struct of contact type and returns
// the pointer to that struct.
func NewContact(company, person, email, phone, skypeid, country string) (*contact, error) {
	doc := contact{
		Id:      bson.NewObjectId(),
		Company: company,
		Person:  person,
		Email:   email,
		Phone:   phone,
		SkypeId: skypeid,
		Country: country,
	}
	if err := validateContact(&doc); err != nil {
		return &contact{}, err
	}
	slugify(&doc)

	doc.CreatedAt = doc.Id.Time()
	doc.UpdatedAt = doc.CreatedAt

	err := config.ContactsCollection.Insert(doc)
	if err != nil {
		return &contact{}, err
	}
	return &doc, nil
}

// GetContact takes the contact Id as an argument and returns a pointer to a contact object.
func GetContact(i bson.ObjectId) (*contact, error) {
	var c contact
	err := config.ContactsCollection.FindId(i).One(&c)
	if err != nil {
		return &contact{}, err
	}
	return &c, nil
}

func GetContactBySlug(slug string) (*contact, error) {
	var c []contact
	err := config.ContactsCollection.Find(bson.M{"slug": slug}).All(&c)
	if err != nil {
		return &contact{}, err
	}

	if len(c) == 0 {
		return &contact{}, errors.New("no contact")
	}

	if len(c) > 1 {
		return &contact{}, errors.New("more than 1 contact found")
	}
	return &c[0], nil
}

// GetAllContacts fetches all the contacts from the database.
func GetAllContacts() ([]contact, error) {
	var c []contact
	err := config.ContactsCollection.Find(nil).All(&c)
	if err != nil {
		return []contact{}, err
	}
	return c, nil
}

// Update updates the contact in the database.
// First, fetch a contact from the database and change the necessary fields.
// Then call the Update method on that contact object.
func (c *contact) Update() error {
	if err := validateContact(c); err != nil {
		return err
	}
	c.UpdatedAt = bson.Now()
	err := config.ContactsCollection.UpdateId(c.Id, c)
	return err
}

// Delete deletes the contact from the database.
func (c *contact) Delete() error {
	return config.ContactsCollection.RemoveId(c.Id)
}

func slugify(c *contact) {
	base := slug.SlugAscii(c.Person)
	temp := base
	rand.Seed(time.Now().UnixNano()) // takes the current time in nanoseconds as the seed
	i := rand.Intn(10000)
	for {
		if slugExists(temp) {
			temp = base + "-" + strconv.Itoa(i)
			i = rand.Intn(10000)
		} else {
			c.Slug = temp
			return
		}

	}
}

func slugExists(slug string) bool {
	var c []contact
	err := config.ContactsCollection.Find(bson.M{"slug": slug}).All(&c)
	if err != nil {
		log.Fatalf("%s", err)
	}
	if len(c) == 0 {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package merkledag

import (
	"fmt"
	"sort"

	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"

	pb "github.com/jbenet/go-ipfs/merkledag/internal/pb"
	u "github.com/jbenet/go-ipfs/util"
)

// for now, we use a PBNode intermediate thing.
// because native go objects are nice.

// Unmarshal decodes raw data into a *Node instance.
// The conversion uses an intermediate PBNode.
func (n *Node) Unmarshal(encoded []byte) error {
	var pbn pb.PBNode
	if err := pbn.Unmarshal(encoded); err != nil {
		return fmt.Errorf("Unmarshal failed. %v", err)
	}

	pbnl := pbn.GetLinks()
	n.Links = make([]*Link, len(pbnl))
	for i, l := range pbnl {
		n.Links[i] = &Link{Name: l.GetName(), Size: l.GetTsize()}
		h, err := mh.Cast(l.GetHash())
		if err != nil {
			return fmt.Errorf("Link hash is not valid multihash. %v", err)
		}
		n.Links[i].Hash = h
	}
	sort.Stable(LinkSlice(n.Links)) // keep links sorted

	n.Data = pbn.GetData()
	return nil
}

// MarshalTo encodes a *Node instance into a given byte slice.
// The conversion uses an intermediate PBNode.
func (n *Node) MarshalTo(encoded []byte) error {
	pbn := n.getPBNode()
	if _, err := pbn.MarshalTo(encoded); err != nil {
		return fmt.Errorf("Marshal failed. %v", err)
	}
	return nil
}

// Marshal encodes a *Node instance into a new byte slice.
// The conversion uses an intermediate PBNode.
func (n *Node) Marshal() ([]byte, error) {
	pbn := n.getPBNode()
	data, err := pbn.Marshal()
	if err != nil {
		return data, fmt.Errorf("Marshal failed. %v", err)
	}
	return data, nil
}

func (n *Node) getPBNode() *pb.PBNode {
	pbn := &pb.PBNode{}
	pbn.Links = make([]*pb.PBLink, len(n.Links))

	sort.Stable(LinkSlice(n.Links)) // keep links sorted
	for i, l := range n.Links {
		pbn.Links[i] = &pb.PBLink{}
		pbn.Links[i].Name = &l.Name
		pbn.Links[i].Tsize = &l.Size
		pbn.Links[i].Hash = []byte(l.Hash)
	}

	pbn.Data = n.Data
	return pbn
}

// Encoded returns the encoded raw data version of a Node instance.
// It may use a cached encoded version, unless the force flag is given.
func (n *Node) Encoded(force bool) ([]byte, error) {
	sort.Stable(LinkSlice(n.Links)) // keep links sorted
	if n.encoded == nil || force {
		var err error
		n.encoded, err = n.Marshal()
		if err != nil {
			return []byte{}, err
		}
		n.cached = u.Hash(n.encoded)
	}

	return n.encoded, nil
}

// Decoded decodes raw data and returns a new Node instance.
func Decoded(encoded []byte) (*Node, error) {
	n := &Node{}
	err := n.Unmarshal(encoded)
	return n, err
}
<commit_msg>more understandable errors from merkledag decoding<commit_after>package merkledag

import (
	"fmt"
	"sort"

	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"

	pb "github.com/jbenet/go-ipfs/merkledag/internal/pb"
	u "github.com/jbenet/go-ipfs/util"
)

// for now, we use a PBNode intermediate thing.
// because native go objects are nice.

// Unmarshal decodes raw data into a *Node instance.
// The conversion uses an intermediate PBNode.
func (n *Node) Unmarshal(encoded []byte) error {
	var pbn pb.PBNode
	if err := pbn.Unmarshal(encoded); err != nil {
		return fmt.Errorf("Unmarshal failed. %v", err)
	}

	pbnl := pbn.GetLinks()
	n.Links = make([]*Link, len(pbnl))
	for i, l := range pbnl {
		n.Links[i] = &Link{Name: l.GetName(), Size: l.GetTsize()}
		h, err := mh.Cast(l.GetHash())
		if err != nil {
			return fmt.Errorf("Link hash is not valid multihash. %v", err)
		}
		n.Links[i].Hash = h
	}
	sort.Stable(LinkSlice(n.Links)) // keep links sorted

	n.Data = pbn.GetData()
	return nil
}

// MarshalTo encodes a *Node instance into a given byte slice.
// The conversion uses an intermediate PBNode.
func (n *Node) MarshalTo(encoded []byte) error {
	pbn := n.getPBNode()
	if _, err := pbn.MarshalTo(encoded); err != nil {
		return fmt.Errorf("Marshal failed. %v", err)
	}
	return nil
}

// Marshal encodes a *Node instance into a new byte slice.
// The conversion uses an intermediate PBNode.
func (n *Node) Marshal() ([]byte, error) {
	pbn := n.getPBNode()
	data, err := pbn.Marshal()
	if err != nil {
		return data, fmt.Errorf("Marshal failed. %v", err)
	}
	return data, nil
}

func (n *Node) getPBNode() *pb.PBNode {
	pbn := &pb.PBNode{}
	pbn.Links = make([]*pb.PBLink, len(n.Links))

	sort.Stable(LinkSlice(n.Links)) // keep links sorted
	for i, l := range n.Links {
		pbn.Links[i] = &pb.PBLink{}
		pbn.Links[i].Name = &l.Name
		pbn.Links[i].Tsize = &l.Size
		pbn.Links[i].Hash = []byte(l.Hash)
	}

	pbn.Data = n.Data
	return pbn
}

// Encoded returns the encoded raw data version of a Node instance.
// It may use a cached encoded version, unless the force flag is given.
func (n *Node) Encoded(force bool) ([]byte, error) {
	sort.Stable(LinkSlice(n.Links)) // keep links sorted
	if n.encoded == nil || force {
		var err error
		n.encoded, err = n.Marshal()
		if err != nil {
			return []byte{}, err
		}
		n.cached = u.Hash(n.encoded)
	}

	return n.encoded, nil
}

// Decoded decodes raw data and returns a new Node instance.
func Decoded(encoded []byte) (*Node, error) {
	n := new(Node)
	err := n.Unmarshal(encoded)
	if err != nil {
		return nil, fmt.Errorf("incorrectly formatted merkledag node: %s", err)
	}
	return n, nil
}
<|endoftext|>


<commit_before>package main

import "github.com/fogleman/pt/pt"

func main() {
	scene := pt.Scene{}
	wall := pt.SpecularMaterial(pt.HexColor(0xFCFAE1), 2)
	scene.AddLight(pt.NewSphere(pt.Vector{2, 30, 0.5}, 2, pt.DiffuseMaterial(pt.Color{1, 1, 1})))
	scene.AddShape(pt.NewCube(pt.Vector{-30, -1, -30}, pt.Vector{-8, 30, 30}, wall))
	scene.AddShape(pt.NewCube(pt.Vector{-30, -1, -30}, pt.Vector{30, 0, 30}, wall))
	material := pt.GlossyMaterial(pt.Color{}, 1.5, pt.Radians(30))
	mesh, _ := pt.LoadOBJ("examples/gopher.obj", material)
	mesh.SmoothNormals()
	mesh.MoveTo(pt.Vector{}, pt.Vector{0.5, 0, 0.5})
	for i := -2; i <= 2; i++ {
		m := pt.Translate(pt.Vector{0, 0, float64(i) * 5})
		scene.AddShape(pt.NewTransformedShape(mesh, m))
	}
	camera := pt.LookAt(pt.Vector{20, 4, 0}, pt.Vector{-1, 2, 0}, pt.Vector{0, 1, 0}, 45)
	pt.IterativeRender("out.png", 1000, &scene, &camera, 2560/4, 1440/4, 0, 16, 4)
}
<commit_msg>single gopher again<commit_after>package main

import "github.com/fogleman/pt/pt"

func main() {
	scene := pt.Scene{}
	wall := pt.SpecularMaterial(pt.HexColor(0xFCFAE1), 2)
	scene.AddLight(pt.NewSphere(pt.Vector{2, 8, 0.5}, 2, pt.DiffuseMaterial(pt.Color{1, 1, 1})))
	scene.AddShape(pt.NewCube(pt.Vector{-30, -1, -30}, pt.Vector{-8, 10, 30}, wall))
	scene.AddShape(pt.NewCube(pt.Vector{-30, -1, -30}, pt.Vector{30, 0.376662, 30}, wall))
	material := pt.GlossyMaterial(pt.Color{}, 1.5, pt.Radians(30))
	mesh, _ := pt.LoadOBJ("examples/gopher.obj", material)
	mesh.SmoothNormals()
	scene.AddShape(mesh)
	camera := pt.LookAt(pt.Vector{8, 3, 0.5}, pt.Vector{-1, 2.5, 0.5}, pt.Vector{0, 1, 0}, 45)
	pt.IterativeRender("out%03d.png", 1000, &scene, &camera, 2560/4, 1440/4, 0, 16, 4)
}
<|endoftext|>


<commit_before>// Copyright 2017 Sergiusz Bazanski <q3k@boson.me>
//
// 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 main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"

	"github.com/golang/glog"
	"github.com/improbable-eng/grpc-web/go/grpcweb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	"github.com/getline-network/getline/metabackend/deployments"
	"github.com/getline-network/getline/metabackend/model"
	"github.com/getline-network/getline/metabackend/server"
	"github.com/getline-network/getline/pb"
)

var (
	flagListen     string
	flagListenHTTP string
	flagReflection bool

	flagDBDriver     string
	flagDBDataSource string
	flagDBInitSchema bool

	flagEthRemote string
)

func main() {
	flag.StringVar(&flagListen, "listen", "0.0.0.0:2000", "gRPC listen address")
	flag.StringVar(&flagListenHTTP, "listen_http", "0.0.0.0:2080", "gRPCWeb (HTTP) listen address")
	flag.BoolVar(&flagReflection, "reflection", true, "gRPC reflection")
	flag.StringVar(&flagDBDriver, "db_driver", "postgres", "SQL driver name")
	flag.StringVar(&flagDBDataSource, "db_data_source", "", "SQL driver data source")
	flag.BoolVar(&flagDBInitSchema, "db_init_schema", false, "Initialize SQL database with empty schema")
	flag.StringVar(&flagEthRemote, "eth_remote", "http://localhost:8545", "Ethereum IPC server address")
	flag.Parse()
	glog.Info("Starting...")

	// Load Truffle project from current working directory.
	cwd, err := os.Getwd()
	if err != nil {
		glog.Exit(err)
	}
	deployment, err := deployments.FromFilesystem(cwd)
	if err != nil {
		glog.Exitf("Could not load deployments: %v", err)
	}

	// Start gRPC.
	lis, err := net.Listen("tcp", flagListen)
	if err != nil {
		glog.Exit(err)
	}
	s := server.Server{
		Deployment: deployment,
	}
	grpc.EnableTracing = true
	grpcServer := grpc.NewServer()
	pb.RegisterMetabackendServer(grpcServer, &s)
	if flagReflection {
		reflection.Register(grpcServer)
	}
	go grpcServer.Serve(lis)
	glog.Infof("gRPC Listening on %q...", flagListen)

	// Start gRPCWeb.
	wrappedGrpc := grpcweb.WrapServer(grpcServer)
	httpServer := http.Server{
		Addr: flagListenHTTP,
	}
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(res, "Hello there. This is metabackend.")
	})
	httpServer.Handler = http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
		if wrappedGrpc.IsGrpcWebRequest(req) {
			wrappedGrpc.ServeHttp(resp, req)
			return
		}
		http.DefaultServeMux.ServeHTTP(resp, req)
	})
	go func() {
		err := httpServer.ListenAndServe()
		if err != nil {
			glog.Exit(err)
		}
	}()
	glog.Infof("gRPCWeb (HTTP) Listening on %q...", flagListenHTTP)

	// Start model.
	model, err := model.New(flagDBDriver, flagDBDataSource, flagEthRemote, &s)
	if err != nil {
		glog.Exitf("Could not start model: %v", err)
	}
	if flagDBInitSchema {
		err = model.InitializeSchema()
		if err != nil {
			glog.Exitf("Could not initialize model schema: %v", err)
		}
		return
	}
	s.Model = model

	select {}
}
<commit_msg>Serve 404 for unknown URLs in metabackend<commit_after>// Copyright 2017 Sergiusz Bazanski <q3k@boson.me>
//
// 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 main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"

	"github.com/golang/glog"
	"github.com/improbable-eng/grpc-web/go/grpcweb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	"github.com/getline-network/getline/metabackend/deployments"
	"github.com/getline-network/getline/metabackend/model"
	"github.com/getline-network/getline/metabackend/server"
	"github.com/getline-network/getline/pb"
)

var (
	flagListen     string
	flagListenHTTP string
	flagReflection bool

	flagDBDriver     string
	flagDBDataSource string
	flagDBInitSchema bool

	flagEthRemote string
)

func main() {
	flag.StringVar(&flagListen, "listen", "0.0.0.0:2000", "gRPC listen address")
	flag.StringVar(&flagListenHTTP, "listen_http", "0.0.0.0:2080", "gRPCWeb (HTTP) listen address")
	flag.BoolVar(&flagReflection, "reflection", true, "gRPC reflection")
	flag.StringVar(&flagDBDriver, "db_driver", "postgres", "SQL driver name")
	flag.StringVar(&flagDBDataSource, "db_data_source", "", "SQL driver data source")
	flag.BoolVar(&flagDBInitSchema, "db_init_schema", false, "Initialize SQL database with empty schema")
	flag.StringVar(&flagEthRemote, "eth_remote", "http://localhost:8545", "Ethereum IPC server address")
	flag.Parse()
	glog.Info("Starting...")

	// Load Truffle project from current working directory.
	cwd, err := os.Getwd()
	if err != nil {
		glog.Exit(err)
	}
	deployment, err := deployments.FromFilesystem(cwd)
	if err != nil {
		glog.Exitf("Could not load deployments: %v", err)
	}

	// Start gRPC.
	lis, err := net.Listen("tcp", flagListen)
	if err != nil {
		glog.Exit(err)
	}
	s := server.Server{
		Deployment: deployment,
	}
	grpc.EnableTracing = true
	grpcServer := grpc.NewServer()
	pb.RegisterMetabackendServer(grpcServer, &s)
	if flagReflection {
		reflection.Register(grpcServer)
	}
	go grpcServer.Serve(lis)
	glog.Infof("gRPC Listening on %q...", flagListen)

	// Start gRPCWeb.
	wrappedGrpc := grpcweb.WrapServer(grpcServer)
	httpServer := http.Server{
		Addr: flagListenHTTP,
	}
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/" {
			http.NotFound(res, req)
			return
		}
		fmt.Fprintf(res, "Hello there. This is metabackend.")
	})
	httpServer.Handler = http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
		if wrappedGrpc.IsGrpcWebRequest(req) {
			wrappedGrpc.ServeHttp(resp, req)
			return
		}
		http.DefaultServeMux.ServeHTTP(resp, req)
	})
	go func() {
		err := httpServer.ListenAndServe()
		if err != nil {
			glog.Exit(err)
		}
	}()
	glog.Infof("gRPCWeb (HTTP) Listening on %q...", flagListenHTTP)

	// Start model.
	model, err := model.New(flagDBDriver, flagDBDataSource, flagEthRemote, &s)
	if err != nil {
		glog.Exitf("Could not start model: %v", err)
	}
	if flagDBInitSchema {
		err = model.InitializeSchema()
		if err != nil {
			glog.Exitf("Could not initialize model schema: %v", err)
		}
		return
	}
	s.Model = model

	select {}
}
<|endoftext|>


<commit_before>package qless

import (
	"sync"

	"fmt"

	"github.com/garyburd/redigo/redis"
)

type Events struct {
	pool *redis.Pool

	// locks following
	l           sync.Mutex
	c           *redis.PubSubConn
	subscribers []chan<- interface{}
}

var channels = []interface{}{"ql:log", "ql:canceled", "ql:completed", "ql:failed", "ql:popped", "ql:stalled", "ql:put", "ql:track", "ql:untrack"}

func (e *Events) Subscribe(ch chan<- interface{}) error {
	e.l.Lock()
	defer e.l.Unlock()

	e.subscribers = append(e.subscribers, ch)

	if e.c == nil {
		return e.start()
	}
	return nil
}

func (e *Events) Unsubscribe(ch chan<- interface{}) {
	e.l.Lock()
	defer e.l.Unlock()

	for i := 0; i < len(e.subscribers); i++ {
		if e.subscribers[i] == ch {
			close(ch)
			l := len(e.subscribers) - 1
			e.subscribers[i] = e.subscribers[l]
			e.subscribers[l] = nil
			e.subscribers = e.subscribers[:l]
		}
	}

	if len(e.subscribers) == 0 {
		e.subscribers = nil
	}
}

func (e *Events) start() error {
	psc := redis.PubSubConn{Conn: e.pool.Get()}
	if err := psc.Subscribe(channels...); err != nil {
		psc.Conn.Close()
		return err
	}

	e.c = &psc
	go e.run(psc)

	return nil
}

func (e *Events) Close() {
	e.l.Lock()
	defer e.l.Unlock()

	if e.subscribers != nil {
		for _, ch := range e.subscribers {
			close(ch)
		}
		e.subscribers = nil
	}

	if e.c != nil {
		e.c.Unsubscribe()
		e.c.Conn.Close()
		e.c = nil
	}
}

func (e *Events) run(psc redis.PubSubConn) {
	fmt.Println("starting loop")

	defer func() {
		fmt.Println("exiting loop")
		e.Close()
	}()

	running := true
	for running {
		val := psc.Receive()
		if _, ok := val.(error); ok {
			running = false
		}

		e.l.Lock()
		sub := e.subscribers
		oldLen := len(sub)
		for i := 0; i < len(sub); i++ {
			ch := sub[i]
			select {
			case ch <- val:
			default:
				// blocking channels are removed
				close(ch)
				e := len(sub) - 1
				sub[i] = sub[e]
				sub[e] = nil
				sub = sub[:e]
			}
		}
		switch len(sub) {
		case 0:
			running = false
			e.subscribers = nil
		case oldLen: // do nothing
		default:
			e.subscribers = sub
		}
		e.l.Unlock()
	}
}
<commit_msg>remove debug<commit_after>package qless

import (
	"sync"

	"github.com/garyburd/redigo/redis"
)

type Events struct {
	pool *redis.Pool

	// locks following
	l           sync.Mutex
	c           *redis.PubSubConn
	subscribers []chan<- interface{}
}

var channels = []interface{}{"ql:log", "ql:canceled", "ql:completed", "ql:failed", "ql:popped", "ql:stalled", "ql:put", "ql:track", "ql:untrack"}

func (e *Events) Subscribe(ch chan<- interface{}) error {
	e.l.Lock()
	defer e.l.Unlock()

	e.subscribers = append(e.subscribers, ch)

	if e.c == nil {
		return e.start()
	}
	return nil
}

func (e *Events) Unsubscribe(ch chan<- interface{}) {
	e.l.Lock()
	defer e.l.Unlock()

	for i := 0; i < len(e.subscribers); i++ {
		if e.subscribers[i] == ch {
			close(ch)
			l := len(e.subscribers) - 1
			e.subscribers[i] = e.subscribers[l]
			e.subscribers[l] = nil
			e.subscribers = e.subscribers[:l]
		}
	}

	if len(e.subscribers) == 0 {
		e.subscribers = nil
	}
}

func (e *Events) start() error {
	psc := redis.PubSubConn{Conn: e.pool.Get()}
	if err := psc.Subscribe(channels...); err != nil {
		psc.Conn.Close()
		return err
	}

	e.c = &psc
	go e.run(psc)

	return nil
}

func (e *Events) Close() {
	e.l.Lock()
	defer e.l.Unlock()

	if e.subscribers != nil {
		for _, ch := range e.subscribers {
			close(ch)
		}
		e.subscribers = nil
	}

	if e.c != nil {
		e.c.Unsubscribe()
		e.c.Conn.Close()
		e.c = nil
	}
}

func (e *Events) run(psc redis.PubSubConn) {
	defer func() {
		e.Close()
	}()

	running := true
	for running {
		val := psc.Receive()
		if _, ok := val.(error); ok {
			running = false
		}

		e.l.Lock()
		sub := e.subscribers
		oldLen := len(sub)
		for i := 0; i < len(sub); i++ {
			ch := sub[i]
			select {
			case ch <- val:
			default:
				// blocking channels are removed
				close(ch)
				e := len(sub) - 1
				sub[i] = sub[e]
				sub[e] = nil
				sub = sub[:e]
			}
		}
		switch len(sub) {
		case 0:
			running = false
			e.subscribers = nil
		case oldLen: // do nothing
		default:
			e.subscribers = sub
		}
		e.l.Unlock()
	}
}
<|endoftext|>


<commit_before>package geojson

// Properties defines the feature properties with some helper methods.
type Properties map[string]interface{}

// MustBool guarantees the return of a `bool` (with optional default).
// This function useful when you explicitly want a `bool` in a single
// value return context, for example:
//     myFunc(f.Properties.MustBool("param1"), f.Properties.MustBool("optional_param", true))
func (p Properties) MustBool(key string, def ...bool) bool {
	b, ok := p[key].(bool)
	if ok {
		return b
	}

	if len(def) > 0 {
		return def[0]
	}

	return false
}

// MustInt guarantees the return of an `int` (with optional default).
// This function useful when you explicitly want a `int` in a single
// value return context, for example:
//     myFunc(f.Properties.MustInt("param1"), f.Properties.MustInt("optional_param", 123))
func (p Properties) MustInt(key string, def ...int) int {
	i, ok := p[key].(int)
	if ok {
		return i
	}

	f, ok := p[key].(float64)
	if ok {
		return int(f)
	}

	if len(def) > 0 {
		return def[0]
	}

	return 0
}

// MustFloat64 guarantees the return of a `float64` (with optional default)
// This function useful when you explicitly want a `float64` in a single
// value return context, for example:
//     myFunc(f.Properties.MustFloat64("param1"), f.Properties.MustFloat64("optional_param", 10.1))
func (p Properties) MustFloat64(key string, def ...float64) float64 {
	f, ok := p[key].(float64)
	if ok {
		return f
	}

	if len(def) > 0 {
		return def[0]
	}

	return 0.0
}

// MustString guarantees the return of a `string` (with optional default)
// This function useful when you explicitly want a `string` in a single
// value return context, for example:
//     myFunc(f.Properties.MustString("param1"), f.Properties.MustString("optional_param", "default"))
func (p Properties) MustString(key string, def ...string) string {
	s, ok := p[key].(string)
	if ok {
		return s
	}

	if len(def) > 0 {
		return def[0]
	}

	return ""
}
<commit_msg>Add geojson.Properties.Clone() method<commit_after>package geojson

// Properties defines the feature properties with some helper methods.
type Properties map[string]interface{}

// MustBool guarantees the return of a `bool` (with optional default).
// This function useful when you explicitly want a `bool` in a single
// value return context, for example:
//     myFunc(f.Properties.MustBool("param1"), f.Properties.MustBool("optional_param", true))
func (p Properties) MustBool(key string, def ...bool) bool {
	b, ok := p[key].(bool)
	if ok {
		return b
	}

	if len(def) > 0 {
		return def[0]
	}

	return false
}

// MustInt guarantees the return of an `int` (with optional default).
// This function useful when you explicitly want a `int` in a single
// value return context, for example:
//     myFunc(f.Properties.MustInt("param1"), f.Properties.MustInt("optional_param", 123))
func (p Properties) MustInt(key string, def ...int) int {
	i, ok := p[key].(int)
	if ok {
		return i
	}

	f, ok := p[key].(float64)
	if ok {
		return int(f)
	}

	if len(def) > 0 {
		return def[0]
	}

	return 0
}

// MustFloat64 guarantees the return of a `float64` (with optional default)
// This function useful when you explicitly want a `float64` in a single
// value return context, for example:
//     myFunc(f.Properties.MustFloat64("param1"), f.Properties.MustFloat64("optional_param", 10.1))
func (p Properties) MustFloat64(key string, def ...float64) float64 {
	f, ok := p[key].(float64)
	if ok {
		return f
	}

	if len(def) > 0 {
		return def[0]
	}

	return 0.0
}

// MustString guarantees the return of a `string` (with optional default)
// This function useful when you explicitly want a `string` in a single
// value return context, for example:
//     myFunc(f.Properties.MustString("param1"), f.Properties.MustString("optional_param", "default"))
func (p Properties) MustString(key string, def ...string) string {
	s, ok := p[key].(string)
	if ok {
		return s
	}

	if len(def) > 0 {
		return def[0]
	}

	return ""
}

// Clone returns a shallow copy of the properties.
func (p Properties) Clone() Properties {
	n := make(Properties, len(p))
	for k, v := range p {
		n[k] = v
	}

	return n
}
<|endoftext|>


<commit_before>package expect

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"unicode/utf8"

	shell "github.com/kballard/go-shellquote"
	"github.com/kr/pty"
)

type buffer struct {
	file  *os.File
	cache bytes.Buffer
	debug bool
}

func (b *buffer) read(chunk []byte) (int, error) {
	nread := 0
	if b.cache.Len() > 0 {
		n, _ := b.cache.Read(chunk)
		if b.debug {
			fmt.Printf("\x1b[36;1mREAD:|>%s<|\x1b[0m\r\n", string(chunk[:n]))
			fmt.Printf("\x1b[36;1mREAD:|>%v<|\x1b[0m\r\n", chunk[:n])
		}
		if n == len(chunk) {
			return n, nil
		}
		nread = n
	}
	fn, err := b.file.Read(chunk[nread:]) // this may be blocked
	if err != nil {
		if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
			// It's just the PTY telling us that it closed all good
			// See: https://github.com/buildbox/agent/pull/34#issuecomment-46080419
			err = io.EOF
		}
	}
	if b.debug {
		fmt.Printf("\x1b[34;1m|>%s<|\x1b[0m\r\n", string(chunk[nread:fn+nread]))
		fmt.Printf("\x1b[34;1m|>%v<|\x1b[0m\r\n", chunk[nread:fn+nread])
		// f, err := os.OpenFile("/tmp/expect_stream_data",
		// 	os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
		// if err != nil {
		// 	panic(err)
		// }
		// defer f.Close()
		// if _, err = f.WriteString(string(chunk[nread : fn+nread])); err != nil {
		// 	panic(err)
		// }
	}
	return fn + nread, err
}

func (b *buffer) unread(chunk []byte) {
	if len(chunk) == 0 {
		return
	}

	if b.debug {
		fmt.Printf("\x1b[35;1mUNREAD:|>%s<|\x1b[0m\r\n", string(chunk))
		fmt.Printf("\x1b[35;1mUNREAD:|>%v<|\x1b[0m\r\n", chunk)
	}
	if b.cache.Len() == 0 {
		b.cache.Write(chunk)
		return
	}

	d := make([]byte, 0, len(chunk)+b.cache.Len())
	d = append(d, chunk...)
	d = append(d, b.cache.Bytes()...)
	b.cache.Reset()
	b.cache.Write(d)
}

func (b *buffer) ReadRune() (rune, int, error) {
	l := b.cache.Len()

	chunk := make([]byte, utf8.UTFMax)
	if l > 0 {
		n, err := b.cache.Read(chunk)
		if err != nil {
			return 0, 0, err
		}
		if utf8.FullRune(chunk[:n]) {
			r, rL := utf8.DecodeRune(chunk)
			if n > rL {
				b.unread(chunk[rL:n])
			}
			return r, rL, nil
		}
	}
	// else add bytes from the file, then try that
	for l < utf8.UTFMax {
		fn, err := b.file.Read(chunk[l : l+1])
		if err != nil {
			return 0, 0, err
		}
		l = l + fn
		if utf8.FullRune(chunk[:l]) {
			r, rL := utf8.DecodeRune(chunk)
			return r, rL, nil
		}
	}
	return 0, 0, errors.New("File is not a valid UTF=8 encoding")
}

type ExpectSubproc struct {
	cmd *exec.Cmd
	buf *buffer
}

func Spawn(command string) (*ExpectSubproc, error) {
	splitArgs, err := shell.Split(command)
	if err != nil {
		return nil, err
	}
	numArgs := len(splitArgs) - 1
	if numArgs < 0 {
		return nil, errors.New("expect: No command given to spawn")
	}
	path, err := exec.LookPath(splitArgs[0])
	if err != nil {
		return nil, err
	}

	proc := new(ExpectSubproc)
	if numArgs >= 1 {
		proc.cmd = exec.Command(path, splitArgs[1:]...)
	} else {
		proc.cmd = exec.Command(path)
	}
	proc.buf = new(buffer)

	f, err := pty.Start(proc.cmd)
	if err != nil {
		return nil, err
	}
	proc.buf.file = f

	return proc, nil
}

func (e *ExpectSubproc) Debug(open bool) {
	e.buf.debug = open
}

func (e *ExpectSubproc) Close() error {
	if err := e.cmd.Process.Kill(); err != nil {
		return err
	}
	if err := e.buf.file.Close(); err != nil {
		return err
	}
	return nil
}

func (e *ExpectSubproc) Wait() error {
	return e.cmd.Wait()
}

func (e *ExpectSubproc) Interact() {
	defer e.cmd.Wait()
	io.Copy(os.Stdout, &e.buf.cache)
	go io.Copy(os.Stdout, e.buf.file)
	go io.Copy(e.buf.file, os.Stdin)
}

func (e *ExpectSubproc) SendLine(cmd string) error {
	return e.Send(cmd + "\r\n")
}

func (e *ExpectSubproc) Send(cmd string) error {
	_, err := io.WriteString(e.buf.file, cmd)
	return err
}

func (e *ExpectSubproc) ReadLine() (string, error) {
	str, err := e.ReadUntil('\n')
	return string(str), err
}

func (e *ExpectSubproc) ReadUntil(delim byte) ([]byte, error) {
	all := make([]byte, 0, 1024)
	chunk := make([]byte, 128)
	for {
		n, err := e.buf.read(chunk)
		for i := 0; i < n; i++ {
			if chunk[i] == delim {
				// if len(chunk) > i+1 {
				if i+1 < n {
					e.buf.unread(chunk[i+1 : n])
				}
				all = append(all, chunk[:i+1]...)
				return all, err
			}
		}
		all = append(all, chunk[:n]...)

		if err != nil {
			return all, err
		}
	}
}

func (e *ExpectSubproc) AsyncInteractChannels() (chan<- string, <-chan string) {
	send := make(chan string)
	receive := make(chan string)

	go func() {
		for {
			str, err := e.ReadLine()
			if err != nil {
				close(receive)
				return
			}
			receive <- str
		}
	}()

	go func() {
		for {
			select {
			case sendCmd, ok := <-send:
				if !ok {
					return
				}
				err := e.Send(sendCmd)
				if err != nil {
					receive <- "expect inner err: " + err.Error()
					return
				}
			}
		}
	}()

	return send, receive
}

func (e *ExpectSubproc) Expect(searchStr string) error {
	num := len(searchStr)
	if num == 0 {
		return errors.New("search string is empty")
	}

	chunk := make([]byte, num*2)
	table := buildKMPTable(searchStr)
	chunkIndex := 0
	strIndex := 0
	for {
		n, err := e.buf.read(chunk)
		offset := chunkIndex + strIndex
		for chunkIndex+strIndex-offset < n {
			if searchStr[strIndex] == chunk[chunkIndex+strIndex-offset] {
				strIndex += 1
				if strIndex == num {
					unreadIndex := chunkIndex + strIndex - offset
					// if len(chunk) > unreadIndex {
					if unreadIndex < n {
						e.buf.unread(chunk[unreadIndex:n])
					}
					return nil
				}
			} else {
				chunkIndex += strIndex - table[strIndex]
				if table[strIndex] > -1 {
					strIndex = table[strIndex]
				} else {
					strIndex = 0
				}
			}
		}
		if err != nil {
			return err
		}
	}
}

func buildKMPTable(searchStr string) []int {
	length := len(searchStr)
	if length < 2 {
		length = 2
	}
	table := make([]int, length)
	table[0] = -1
	table[1] = 0

	pos := 2
	cnd := 0
	for pos < len(searchStr) {
		if searchStr[pos-1] == searchStr[cnd] {
			cnd += 1
			table[pos] = cnd
			pos += 1
		} else if cnd > 0 {
			cnd = table[cnd]
		} else {
			table[pos] = 0
			pos += 1
		}
	}

	return table
}

// ExpectMatch checks whether a textual regular expression matches happened
func (e *ExpectSubproc) ExpectMatch(regex string) (bool, error) {
	return regexp.MatchReader(regex, e.buf)
}
<commit_msg>add win size<commit_after>package expect

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"unicode/utf8"
	"unsafe"

	shell "github.com/kballard/go-shellquote"
	"github.com/kr/pty"
)

type buffer struct {
	file  *os.File
	cache bytes.Buffer
	debug bool
}

func (b *buffer) read(chunk []byte) (int, error) {
	if b.cache.Len() > 0 {
		n, _ := b.cache.Read(chunk)
		if b.debug {
			fmt.Printf("\x1b[36;1mREAD:|>%s<|\x1b[0m\r\n", string(chunk[:n]))
			fmt.Printf("\x1b[36;1mREAD:|>%v<|\x1b[0m\r\n", chunk[:n])
		}
		return n, nil
	}

	n, err := b.file.Read(chunk) // this may be blocked
	if err != nil {
		if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
			// It's just the PTY telling us that it closed all good
			// See: https://github.com/buildbox/agent/pull/34#issuecomment-46080419
			err = io.EOF
		}
	}
	if b.debug {
		fmt.Printf("\x1b[34;1m|>%s<|\x1b[0m\r\n", string(chunk[:n]))
		fmt.Printf("\x1b[34;1m|>%v<|\x1b[0m\r\n", chunk[:n])
		f, err := os.OpenFile("/tmp/expect_stream_data",
			os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		if _, err = f.WriteString(string(chunk[:n])); err != nil {
			panic(err)
		}
	}
	return n, err
}

func (b *buffer) unread(chunk []byte) {
	if len(chunk) == 0 {
		return
	}

	if b.debug {
		fmt.Printf("\x1b[35;1mUNREAD:|>%s<|\x1b[0m\r\n", string(chunk))
		fmt.Printf("\x1b[35;1mUNREAD:|>%v<|\x1b[0m\r\n", chunk)
	}
	if b.cache.Len() == 0 {
		b.cache.Write(chunk)
		return
	}

	d := make([]byte, 0, len(chunk)+b.cache.Len())
	d = append(d, chunk...)
	d = append(d, b.cache.Bytes()...)
	b.cache.Reset()
	b.cache.Write(d)
}

func (b *buffer) ReadRune() (rune, int, error) {
	chunk := make([]byte, utf8.UTFMax)
	for n := 0; n < utf8.UTFMax; {
		n, err := b.read(chunk[n:])
		if utf8.FullRune(chunk[:n]) {
			r, rL := utf8.DecodeRune(chunk)
			if n > rL {
				b.unread(chunk[rL:n])
			}
			return r, rL, err
		}
	}
	return 0, 0, errors.New("file is not a valid UTF=8 encoding")
}

type ExpectSubproc struct {
	cmd *exec.Cmd
	buf *buffer
}

func Command(cmd string) (*ExpectSubproc, error) {
	splitArgs, err := shell.Split(cmd)
	if err != nil {
		return nil, err
	}
	numArgs := len(splitArgs) - 1
	if numArgs < 0 {
		return nil, errors.New("expect: No command given to spawn")
	}
	path, err := exec.LookPath(splitArgs[0])
	if err != nil {
		return nil, err
	}

	proc := new(ExpectSubproc)
	if numArgs >= 1 {
		proc.cmd = exec.Command(path, splitArgs[1:]...)
	} else {
		proc.cmd = exec.Command(path)
	}
	proc.buf = new(buffer)

	return proc, nil
}

func (e *ExpectSubproc) Start() error {
	f, err := pty.Start(e.cmd)
	if err != nil {
		return err
	}
	e.buf.file = f

	return nil
}

func Spawn(cmd string) (*ExpectSubproc, error) {
	proc, err := Command(cmd)
	if err != nil {
		return nil, err
	}
	return proc, proc.Start()
}

func (e *ExpectSubproc) Close() error {
	if err := e.cmd.Process.Kill(); err != nil {
		return err
	}
	if err := e.buf.file.Close(); err != nil {
		return err
	}
	return nil
}

func (e *ExpectSubproc) Wait() error {
	return e.cmd.Wait()
}

func (e *ExpectSubproc) Interact() {
	defer e.cmd.Wait()
	io.Copy(os.Stdout, &e.buf.cache)
	go io.Copy(os.Stdout, e.buf.file)
	go io.Copy(e.buf.file, os.Stdin)
}

func (e *ExpectSubproc) SendLine(cmd string) error {
	return e.Send(cmd + "\r\n")
}

func (e *ExpectSubproc) Send(cmd string) error {
	_, err := io.WriteString(e.buf.file, cmd)
	return err
}

func (e *ExpectSubproc) ReadLine() (string, error) {
	str, err := e.ReadUntil('\n')
	return string(str), err
}

func (e *ExpectSubproc) ReadUntil(delim byte) ([]byte, error) {
	all := make([]byte, 0, 1024)
	chunk := make([]byte, 128)
	for {
		n, err := e.buf.read(chunk)
		for i := 0; i < n; i++ {
			if chunk[i] == delim {
				// if len(chunk) > i+1 {
				if i+1 < n {
					e.buf.unread(chunk[i+1 : n])
				}
				all = append(all, chunk[:i+1]...)
				return all, err
			}
		}
		all = append(all, chunk[:n]...)

		if err != nil {
			return all, err
		}
	}
}

func (e *ExpectSubproc) AsyncInteractChannels() (chan<- string, <-chan string) {
	send := make(chan string)
	receive := make(chan string)

	go func() {
		for {
			str, err := e.ReadLine()
			if err != nil {
				close(receive)
				return
			}
			receive <- str
		}
	}()

	go func() {
		for {
			select {
			case sendCmd, ok := <-send:
				if !ok {
					return
				}
				err := e.Send(sendCmd)
				if err != nil {
					receive <- "expect inner err: " + err.Error()
					return
				}
			}
		}
	}()

	return send, receive
}

func (e *ExpectSubproc) Expect(searchStr string) error {
	num := len(searchStr)
	if num == 0 {
		return errors.New("search string is empty")
	}

	chunk := make([]byte, num*2)
	table := buildKMPTable(searchStr)
	chunkIndex := 0
	strIndex := 0
	for {
		n, err := e.buf.read(chunk)
		offset := chunkIndex + strIndex
		for chunkIndex+strIndex-offset < n {
			if searchStr[strIndex] == chunk[chunkIndex+strIndex-offset] {
				strIndex += 1
				if strIndex == num {
					unreadIndex := chunkIndex + strIndex - offset
					// if len(chunk) > unreadIndex {
					if unreadIndex < n {
						e.buf.unread(chunk[unreadIndex:n])
					}
					return nil
				}
			} else {
				chunkIndex += strIndex - table[strIndex]
				if table[strIndex] > -1 {
					strIndex = table[strIndex]
				} else {
					strIndex = 0
				}
			}
		}
		if err != nil {
			return err
		}
	}
}

func buildKMPTable(searchStr string) []int {
	length := len(searchStr)
	if length < 2 {
		length = 2
	}
	table := make([]int, length)
	table[0] = -1
	table[1] = 0

	pos := 2
	cnd := 0
	for pos < len(searchStr) {
		if searchStr[pos-1] == searchStr[cnd] {
			cnd += 1
			table[pos] = cnd
			pos += 1
		} else if cnd > 0 {
			cnd = table[cnd]
		} else {
			table[pos] = 0
			pos += 1
		}
	}

	return table
}

// ExpectMatch checks whether a textual regular expression matches happened
func (e *ExpectSubproc) ExpectMatch(regex string) (bool, error) {
	return regexp.MatchReader(regex, e.buf)
}

func (e *ExpectSubproc) Debug(open bool) {
	e.buf.debug = open
}

type winsize struct {
	Height uint16
	Width  uint16
	xpixel uint16 //unused
	ypixel uint16 //unused
}

func (e *ExpectSubproc) GetWinsize() (uint16, uint16, error) {
	ws := &winsize{}
	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		uintptr(syscall.Stdin),
		uintptr(syscall.TIOCGWINSZ),
		uintptr(unsafe.Pointer(ws))); errno != 0 {
		return 0, 0, errno
	}
	return ws.Height, ws.Width, nil
}

func (e *ExpectSubproc) SetWinsize(height, width uint16) error {
	ws := &winsize{Height: height, Width: width}
	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
		e.buf.file.Fd(),
		uintptr(syscall.TIOCSWINSZ),
		uintptr(unsafe.Pointer(ws))); errno != 0 {
		fmt.Println(errno)
		return errno
	}
	return nil
}
<|endoftext|>


<commit_before>package baloo

import (
	"fmt"
	"net/http"
	"testing"
  "gopkg.in/h2non/gentleman.v2"
	"gopkg.in/h2non/baloo.v3/assert"
)

// Assertions stores global assertion functions by alias name.
// Use Expect.Assert('<assertion name>') to use
// new assertion at request expectation level.
var Assertions = make(map[string]assert.Func)

// AddAssertFunc adds a new assertion function at global level by alias name.
// Then you can trigger the assertion function in any expectation test.
func AddAssertFunc(name string, fn assert.Func) {
	Assertions[name] = fn
}

// FlushAssertFuncs flushes registered assertion functions.
func FlushAssertFuncs() {
	Assertions = make(map[string]assert.Func)
}

// Expect represents the HTTP expectation suite who is
// able to define multiple assertion functions to match the response.
type Expect struct {
	test       *testing.T
	request    *Request
	assertions []assert.Func
}

// NewExpect creates a new testing expectation instance.
func NewExpect(req *Request) *Expect {
	return &Expect{request: req}
}

// BindTest binds the Go testing instance to the current suite.
// In the future multiple testing interfaces can
// be supported via adapters.
func (e *Expect) BindTest(t *testing.T) *Expect {
	e.test = t
	return e
}

// Status asserts the response status code
// with the given status.
func (e *Expect) Status(code int) *Expect {
	e.AssertFunc(assert.StatusEqual(code))
	return e
}

// StatusOk asserts the response status code
// as valid response (>= 200 && < 400).
func (e *Expect) StatusOk() *Expect {
	e.AssertFunc(assert.StatusOk())
	return e
}

// StatusError asserts the response status code
// as client/server error response (>= 400 && < 600).
func (e *Expect) StatusError() *Expect {
	e.AssertFunc(assert.StatusError())
	return e
}

// StatusServerError asserts the response status code
// as server error response (>= 500 && < 600).
func (e *Expect) StatusServerError() *Expect {
	e.AssertFunc(assert.StatusServerError())
	return e
}

// StatusClientError asserts the response status code
// as server error response (>= 400 && < 500).
func (e *Expect) StatusClientError() *Expect {
	e.AssertFunc(assert.StatusClientError())
	return e
}

// Type asserts the response MIME type with the given alias or value.
func (e *Expect) Type(kind string) *Expect {
	e.AssertFunc(assert.Type(kind))
	return e
}

// Header asserts a response header field value matches.
// Regular expressions can be used as value to perform the specific assertions.
func (e *Expect) Header(key, value string) *Expect {
	e.AssertFunc(assert.Header(key, value))
	return e
}

// HeaderEquals asserts a response header field value
// is equal to the given value.
func (e *Expect) HeaderEquals(key, value string) *Expect {
	e.AssertFunc(assert.HeaderEquals(key, value))
	return e
}

// HeaderNotEquals asserts that a response header field value
// is not equal to the given one.
func (e *Expect) HeaderNotEquals(key, value string) *Expect {
	e.AssertFunc(assert.HeaderNotEquals(key, value))
	return e
}

// HeaderPresent asserts if a header field is present
// in the response.
func (e *Expect) HeaderPresent(key string) *Expect {
	e.AssertFunc(assert.HeaderPresent(key))
	return e
}

// HeaderNotPresent asserts if a header field is not
// present in the response.
func (e *Expect) HeaderNotPresent(key string) *Expect {
	e.AssertFunc(assert.HeaderNotPresent(key))
	return e
}

// RedirectTo asserts the server response redirects
// to the given URL pattern.
// Regular expressions are supported.
func (e *Expect) RedirectTo(uri string) *Expect {
	e.AssertFunc(assert.RedirectTo(uri))
	return e
}

// BodyEquals asserts as strict equality comparison the
// response body with a given string string.
func (e *Expect) BodyEquals(pattern string) *Expect {
	e.AssertFunc(assert.BodyEquals(pattern))
	return e
}

// BodyMatchString asserts a response body matching a string expression.
// Regular expressions can be used as value to perform the specific assertions.
func (e *Expect) BodyMatchString(pattern string) *Expect {
	e.AssertFunc(assert.BodyMatchString(pattern))
	return e
}

// BodyLength asserts a response body length.
func (e *Expect) BodyLength(length int) *Expect {
	e.AssertFunc(assert.BodyLength(length))
	return e
}

// JSON asserts the response body with the given JSON struct.
func (e *Expect) JSON(data interface{}) *Expect {
	e.AssertFunc(assert.JSON(data))
	return e
}

// JSONSchema asserts the response body with the given
// JSON schema definition.
func (e *Expect) JSONSchema(schema string) *Expect {
	e.AssertFunc(assert.JSONSchema(schema))
	return e
}

// Assert adds a new assertion function by alias name.
// Assertion function must be previosly registered
// via baloo.AddAssertFunc("alias", function).
func (e *Expect) Assert(assertions ...string) *Expect {
	for _, alias := range assertions {
		fn, ok := Assertions[alias]
		if !ok {
			panic("No assertion function registered by alias: " + alias)
		}
		e.assertions = append(e.assertions, fn)
	}
	return e
}

// AssertFunc adds a new assertion function.
func (e *Expect) AssertFunc(assertion ...assert.Func) *Expect {
	e.assertions = append(e.assertions, assertion...)
	return e
}

// Done performs and asserts the HTTP response based
// on the defined expectations.
func (e *Expect) Done() error {
	// Perform the HTTP request
	res, err := e.request.Send()
	if err != nil {
		err = fmt.Errorf("request error: %s", err)
		e.test.Error(err)
		return err
	}

	// Run assertions
	err = e.run(res.RawResponse, res.RawRequest)
	if err != nil {
		e.test.Error(err)
	}

	return err
}

// End is an alias to `Done()`.
func (e *Expect) End() error {
	return e.Done()
}

func (e *Expect) run(res *http.Response, req *http.Request) error {
	var err error
	for _, assertion := range e.assertions {
		err = assertion(res, req)
		if err != nil {
			break
		}
	}
	return err
}

// The same as `Done` but return http response,error
func (e *Expect) Send() (*gentleman.Response, error) {
	// Perform the HTTP request
	res, err := e.request.Send()
	if err != nil {
		err = fmt.Errorf("request error: %s", err)
		e.test.Error(err)
		return res, err
	}

	// Run assertions
	err = e.run(res.RawResponse, res.RawRequest)
	if err != nil {
		e.test.Error(err)
	}

	return res, err
}
<commit_msg>fix(lint): code style issue in expect.go<commit_after>package baloo

import (
	"fmt"
	"net/http"
	"testing"
	"gopkg.in/h2non/gentleman.v2"
	"gopkg.in/h2non/baloo.v3/assert"
)

// Assertions stores global assertion functions by alias name.
// Use Expect.Assert('<assertion name>') to use
// new assertion at request expectation level.
var Assertions = make(map[string]assert.Func)

// AddAssertFunc adds a new assertion function at global level by alias name.
// Then you can trigger the assertion function in any expectation test.
func AddAssertFunc(name string, fn assert.Func) {
	Assertions[name] = fn
}

// FlushAssertFuncs flushes registered assertion functions.
func FlushAssertFuncs() {
	Assertions = make(map[string]assert.Func)
}

// Expect represents the HTTP expectation suite who is
// able to define multiple assertion functions to match the response.
type Expect struct {
	test       *testing.T
	request    *Request
	assertions []assert.Func
}

// NewExpect creates a new testing expectation instance.
func NewExpect(req *Request) *Expect {
	return &Expect{request: req}
}

// BindTest binds the Go testing instance to the current suite.
// In the future multiple testing interfaces can
// be supported via adapters.
func (e *Expect) BindTest(t *testing.T) *Expect {
	e.test = t
	return e
}

// Status asserts the response status code
// with the given status.
func (e *Expect) Status(code int) *Expect {
	e.AssertFunc(assert.StatusEqual(code))
	return e
}

// StatusOk asserts the response status code
// as valid response (>= 200 && < 400).
func (e *Expect) StatusOk() *Expect {
	e.AssertFunc(assert.StatusOk())
	return e
}

// StatusError asserts the response status code
// as client/server error response (>= 400 && < 600).
func (e *Expect) StatusError() *Expect {
	e.AssertFunc(assert.StatusError())
	return e
}

// StatusServerError asserts the response status code
// as server error response (>= 500 && < 600).
func (e *Expect) StatusServerError() *Expect {
	e.AssertFunc(assert.StatusServerError())
	return e
}

// StatusClientError asserts the response status code
// as server error response (>= 400 && < 500).
func (e *Expect) StatusClientError() *Expect {
	e.AssertFunc(assert.StatusClientError())
	return e
}

// Type asserts the response MIME type with the given alias or value.
func (e *Expect) Type(kind string) *Expect {
	e.AssertFunc(assert.Type(kind))
	return e
}

// Header asserts a response header field value matches.
// Regular expressions can be used as value to perform the specific assertions.
func (e *Expect) Header(key, value string) *Expect {
	e.AssertFunc(assert.Header(key, value))
	return e
}

// HeaderEquals asserts a response header field value
// is equal to the given value.
func (e *Expect) HeaderEquals(key, value string) *Expect {
	e.AssertFunc(assert.HeaderEquals(key, value))
	return e
}

// HeaderNotEquals asserts that a response header field value
// is not equal to the given one.
func (e *Expect) HeaderNotEquals(key, value string) *Expect {
	e.AssertFunc(assert.HeaderNotEquals(key, value))
	return e
}

// HeaderPresent asserts if a header field is present
// in the response.
func (e *Expect) HeaderPresent(key string) *Expect {
	e.AssertFunc(assert.HeaderPresent(key))
	return e
}

// HeaderNotPresent asserts if a header field is not
// present in the response.
func (e *Expect) HeaderNotPresent(key string) *Expect {
	e.AssertFunc(assert.HeaderNotPresent(key))
	return e
}

// RedirectTo asserts the server response redirects
// to the given URL pattern.
// Regular expressions are supported.
func (e *Expect) RedirectTo(uri string) *Expect {
	e.AssertFunc(assert.RedirectTo(uri))
	return e
}

// BodyEquals asserts as strict equality comparison the
// response body with a given string string.
func (e *Expect) BodyEquals(pattern string) *Expect {
	e.AssertFunc(assert.BodyEquals(pattern))
	return e
}

// BodyMatchString asserts a response body matching a string expression.
// Regular expressions can be used as value to perform the specific assertions.
func (e *Expect) BodyMatchString(pattern string) *Expect {
	e.AssertFunc(assert.BodyMatchString(pattern))
	return e
}

// BodyLength asserts a response body length.
func (e *Expect) BodyLength(length int) *Expect {
	e.AssertFunc(assert.BodyLength(length))
	return e
}

// JSON asserts the response body with the given JSON struct.
func (e *Expect) JSON(data interface{}) *Expect {
	e.AssertFunc(assert.JSON(data))
	return e
}

// JSONSchema asserts the response body with the given
// JSON schema definition.
func (e *Expect) JSONSchema(schema string) *Expect {
	e.AssertFunc(assert.JSONSchema(schema))
	return e
}

// Assert adds a new assertion function by alias name.
// Assertion function must be previosly registered
// via baloo.AddAssertFunc("alias", function).
func (e *Expect) Assert(assertions ...string) *Expect {
	for _, alias := range assertions {
		fn, ok := Assertions[alias]
		if !ok {
			panic("No assertion function registered by alias: " + alias)
		}
		e.assertions = append(e.assertions, fn)
	}
	return e
}

// AssertFunc adds a new assertion function.
func (e *Expect) AssertFunc(assertion ...assert.Func) *Expect {
	e.assertions = append(e.assertions, assertion...)
	return e
}

// Done performs and asserts the HTTP response based
// on the defined expectations.
func (e *Expect) Done() error {
	// Perform the HTTP request
	res, err := e.request.Send()
	if err != nil {
		err = fmt.Errorf("request error: %s", err)
		e.test.Error(err)
		return err
	}

	// Run assertions
	err = e.run(res.RawResponse, res.RawRequest)
	if err != nil {
		e.test.Error(err)
	}

	return err
}

// End is an alias to `Done()`.
func (e *Expect) End() error {
	return e.Done()
}

func (e *Expect) run(res *http.Response, req *http.Request) error {
	var err error
	for _, assertion := range e.assertions {
		err = assertion(res, req)
		if err != nil {
			break
		}
	}
	return err
}

// Send does the same as `Done()`, but it also returns the `*http.Response` along with the `error`.
func (e *Expect) Send() (*gentleman.Response, error) {
	// Perform the HTTP request
	res, err := e.request.Send()
	if err != nil {
		err = fmt.Errorf("request error: %s", err)
		e.test.Error(err)
		return res, err
	}

	// Run assertions
	err = e.run(res.RawResponse, res.RawRequest)
	if err != nil {
		e.test.Error(err)
	}

	return res, err
}
<|endoftext|>