<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, q. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package components

import (
	graph "gopkg.in/r3labs/graph.v2"
)

// Query : mapping of an query component
type Query struct {
	ID                string            `json:"id"`
	ProviderType      string            `json:"_provider"`
	ComponentType     string            `json:"_component"`
	ComponentID       string            `json:"_component_id"`
	State             string            `json:"_state"`
	Action            string            `json:"_action"`
	ResourceGroupName string            `json:"resource_group_name"`
	Tags              map[string]string `json:"tags"`
	DatacenterType    string            `json:"datacenter_type,omitempty"`
	DatacenterName    string            `json:"datacenter_name,omitempty"`
	DatacenterRegion  string            `json:"datacenter_region"`
	ClientID          string            `json:"azure_client_id"`
	ClientSecret      string            `json:"azure_client_secret"`
	TenantID          string            `json:"azure_tenant_id"`
	SubscriptionID    string            `json:"azure_subscription_id"`
	Environment       string            `json:"environment"`
}

// GetID : returns the component's ID
func (q *Query) GetID() string {
	return q.ComponentID
}

// GetName returns a components name
func (q *Query) GetName() string {
	return "query"
}

// GetProvider : returns the provider type
func (q *Query) GetProvider() string {
	return q.ProviderType
}

// GetProviderID returns a components provider id
func (q *Query) GetProviderID() string {
	return ""
}

// GetType : returns the type of the component
func (q *Query) GetType() string {
	return q.ComponentType
}

// GetState : returns the state of the component
func (q *Query) GetState() string {
	return q.State
}

// SetState : sets the state of the component
func (q *Query) SetState(s string) {
	q.State = s
}

// GetAction : returns the action of the component
func (q *Query) GetAction() string {
	return q.Action
}

// SetAction : Sets the action of the component
func (q *Query) SetAction(s string) {
	q.Action = s
}

// GetGroup : returns the components group
func (q *Query) GetGroup() string {
	return ""
}

// GetTags returns a components tags
func (q *Query) GetTags() map[string]string {
	return q.Tags
}

// GetTag returns a components tag
func (q *Query) GetTag(tag string) string {
	return ""
}

// Diff : diff's the component against another component of the same type
func (q *Query) Diff(c graph.Component) bool {
	return false
}

// Update : updates the provider returned values of a component
func (q *Query) Update(c graph.Component) {
	q.SetDefaultVariables()
}

// Rebuild : rebuilds the component's internal state, such as templated values
func (q *Query) Rebuild(g *graph.Graph) {
	q.SetDefaultVariables()
}

// Dependencies : returns a list of component id's upon which the component depends
func (q *Query) Dependencies() []string {
	return []string{}
}

// Validate : validates the components values
func (q *Query) Validate() error {
	return nil
}

// IsStateful : returns true if the component needs to be actioned to be removed.
func (q *Query) IsStateful() bool {
	return true
}

// SetDefaultVariables : sets up the default template variables for a component
func (q *Query) SetDefaultVariables() {
	q.ComponentID = q.ComponentType + TYPEDELIMITER + "query" + q.ResourceGroupName
	q.ProviderType = PROVIDERTYPE
	q.DatacenterType = DATACENTERTYPE
	q.DatacenterRegion = DATACENTERREGION
	q.ClientID = CLIENTID
	q.ClientSecret = CLIENTSECRET
	q.TenantID = TENANTID
	q.SubscriptionID = SUBSCRIPTIONID
	q.Environment = ENVIRONMENT
}
<commit_msg>Fix query name<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, q. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package components

import (
	graph "gopkg.in/r3labs/graph.v2"
)

// Query : mapping of an query component
type Query struct {
	ID                string            `json:"id"`
	ProviderType      string            `json:"_provider"`
	ComponentType     string            `json:"_component"`
	ComponentID       string            `json:"_component_id"`
	State             string            `json:"_state"`
	Action            string            `json:"_action"`
	ResourceGroupName string            `json:"resource_group_name"`
	Tags              map[string]string `json:"tags"`
	DatacenterType    string            `json:"datacenter_type,omitempty"`
	DatacenterName    string            `json:"datacenter_name,omitempty"`
	DatacenterRegion  string            `json:"datacenter_region"`
	ClientID          string            `json:"azure_client_id"`
	ClientSecret      string            `json:"azure_client_secret"`
	TenantID          string            `json:"azure_tenant_id"`
	SubscriptionID    string            `json:"azure_subscription_id"`
	Environment       string            `json:"environment"`
}

// GetID : returns the component's ID
func (q *Query) GetID() string {
	return q.ComponentID
}

// GetName returns a components name
func (q *Query) GetName() string {
	return "query"
}

// GetProvider : returns the provider type
func (q *Query) GetProvider() string {
	return q.ProviderType
}

// GetProviderID returns a components provider id
func (q *Query) GetProviderID() string {
	return ""
}

// GetType : returns the type of the component
func (q *Query) GetType() string {
	return q.ComponentType
}

// GetState : returns the state of the component
func (q *Query) GetState() string {
	return q.State
}

// SetState : sets the state of the component
func (q *Query) SetState(s string) {
	q.State = s
}

// GetAction : returns the action of the component
func (q *Query) GetAction() string {
	return q.Action
}

// SetAction : Sets the action of the component
func (q *Query) SetAction(s string) {
	q.Action = s
}

// GetGroup : returns the components group
func (q *Query) GetGroup() string {
	return ""
}

// GetTags returns a components tags
func (q *Query) GetTags() map[string]string {
	return q.Tags
}

// GetTag returns a components tag
func (q *Query) GetTag(tag string) string {
	return ""
}

// Diff : diff's the component against another component of the same type
func (q *Query) Diff(c graph.Component) bool {
	return false
}

// Update : updates the provider returned values of a component
func (q *Query) Update(c graph.Component) {
	q.SetDefaultVariables()
}

// Rebuild : rebuilds the component's internal state, such as templated values
func (q *Query) Rebuild(g *graph.Graph) {
	q.SetDefaultVariables()
}

// Dependencies : returns a list of component id's upon which the component depends
func (q *Query) Dependencies() []string {
	return []string{}
}

// Validate : validates the components values
func (q *Query) Validate() error {
	return nil
}

// IsStateful : returns true if the component needs to be actioned to be removed.
func (q *Query) IsStateful() bool {
	return true
}

// SetDefaultVariables : sets up the default template variables for a component
func (q *Query) SetDefaultVariables() {
	q.ComponentID = q.ComponentType[0:len(q.ComponentType)-1] + TYPEDELIMITER + "query" + q.ResourceGroupName
	q.ProviderType = PROVIDERTYPE
	q.DatacenterType = DATACENTERTYPE
	q.DatacenterRegion = DATACENTERREGION
	q.ClientID = CLIENTID
	q.ClientSecret = CLIENTSECRET
	q.TenantID = TENANTID
	q.SubscriptionID = SUBSCRIPTIONID
	q.Environment = ENVIRONMENT
}
<|endoftext|>


<commit_before>package jwp

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	id string
)

func TestListSessions(t *testing.T) {
	list, err := sess.ListSessions()
	require.NoError(t, err)
	require.NotNil(t, list)
	assert.IsType(t, &ApiSessions{}, list)
	assert.IsType(t, []SessionItem{}, list.Value)
	assert.IsType(t, ApiCapabilities{}, list.Value[0].Capabilities)
	id = list.Value[0].Id
}
<commit_msg>Test GetCapabilities method.<commit_after>package jwp

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	id string
)

func TestListSessions(t *testing.T) {
	list, err := sess.ListSessions()
	require.NoError(t, err)
	require.NotNil(t, list)
	assert.IsType(t, &ApiSessions{}, list)
	assert.IsType(t, []SessionItem{}, list.Value)
	assert.IsType(t, ApiCapabilities{}, list.Value[0].Capabilities)
	id = list.Value[0].Id
}

func TestGetCapabilities(t *testing.T) {
	capabilities, err := sess.GetCapabilities()
	require.NoError(t, err)
	assert.Equal(t, "phantomjs", capabilities.BrowserName)
}
<|endoftext|>


<commit_before>package smux

import (
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"testing"
	"time"
)

func init() {
	ln, err := net.Listen("tcp", "127.0.0.1:19999")
	if err != nil {
		// handle error
		panic(err)
	}
	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				// handle error
			}
			go handleConnection(conn)
		}
	}()
}

func handleConnection(conn net.Conn) {
	session, _ := Server(conn, nil)
	for {
		if stream, err := session.AcceptStream(); err == nil {
			go func(s io.ReadWriteCloser) {
				buf := make([]byte, 65536)
				for {
					n, err := s.Read(buf)
					if err != nil {
						return
					}
					s.Write(buf[:n])
				}
			}(stream)
		} else {
			log.Println(err)
			return
		}
	}
}

func TestEcho(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	stream, _ := session.OpenStream()
	const N = 100
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		fmt.Println("sent:", msg)
		stream.Write([]byte(msg))
		if n, err := stream.Read(buf); err == nil {
			fmt.Println("recv:", string(buf[:n]))
		} else {
			return
		}
	}
	session.Close()
}

func TestSpeed(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	stream, _ := session.OpenStream()

	start := time.Now()
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		buf := make([]byte, 1024*1024)
		nrecv := 0
		for {
			n, err := stream.Read(buf)
			if err != nil {
				fmt.Println(err)
				break
			} else {
				nrecv += n
				if nrecv == 4096*4096 {
					break
				}
			}
		}
		println("total recv:", nrecv)
		stream.Close()
		fmt.Println("time for 16MB rtt", time.Now().Sub(start))
		wg.Done()
	}()
	msg := make([]byte, 8192)
	for i := 0; i < 2048; i++ {
		stream.Write(msg)
	}
	wg.Wait()
	session.Close()
}

func TestParallel(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)

	par := 1000
	messages := 100
	var wg sync.WaitGroup
	wg.Add(par)
	for i := 0; i < par; i++ {
		stream, _ := session.OpenStream()
		go func(s *Stream) {
			buf := make([]byte, 20)
			for j := 0; j < messages; j++ {
				msg := fmt.Sprintf("hello%v", j)
				s.Write([]byte(msg))
				if _, err := s.Read(buf); err != nil {
					break
				}
			}
			s.Close()
			wg.Done()
		}(stream)
	}
	t.Log("created", session.NumStreams(), "streams")
	wg.Wait()
	session.Close()
}

func BenchmarkAcceptClose(b *testing.B) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		b.Fatal(err)
	}
	session, _ := Client(cli, nil)
	for i := 0; i < b.N; i++ {
		if stream, err := session.OpenStream(); err == nil {
			stream.Close()
		} else {
			b.Fatal(err)
		}
	}
}
<commit_msg>add more tests<commit_after>package smux

import (
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"testing"
	"time"
)

func init() {
	ln, err := net.Listen("tcp", "127.0.0.1:19999")
	if err != nil {
		// handle error
		panic(err)
	}
	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				// handle error
			}
			go handleConnection(conn)
		}
	}()
}

func handleConnection(conn net.Conn) {
	session, _ := Server(conn, nil)
	for {
		if stream, err := session.AcceptStream(); err == nil {
			go func(s io.ReadWriteCloser) {
				buf := make([]byte, 65536)
				for {
					n, err := s.Read(buf)
					if err != nil {
						return
					}
					s.Write(buf[:n])
				}
			}(stream)
		} else {
			log.Println(err)
			return
		}
	}
}

func TestEcho(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	stream, _ := session.OpenStream()
	const N = 100
	buf := make([]byte, 10)
	for i := 0; i < N; i++ {
		msg := fmt.Sprintf("hello%v", i)
		fmt.Println("sent:", msg)
		stream.Write([]byte(msg))
		if n, err := stream.Read(buf); err == nil {
			fmt.Println("recv:", string(buf[:n]))
		} else {
			return
		}
	}
	session.Close()
}

func TestSpeed(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	stream, _ := session.OpenStream()

	start := time.Now()
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		buf := make([]byte, 1024*1024)
		nrecv := 0
		for {
			n, err := stream.Read(buf)
			if err != nil {
				fmt.Println(err)
				break
			} else {
				nrecv += n
				if nrecv == 4096*4096 {
					break
				}
			}
		}
		println("total recv:", nrecv)
		stream.Close()
		fmt.Println("time for 16MB rtt", time.Now().Sub(start))
		wg.Done()
	}()
	msg := make([]byte, 8192)
	for i := 0; i < 2048; i++ {
		stream.Write(msg)
	}
	wg.Wait()
	session.Close()
}

func TestParallel(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)

	par := 1000
	messages := 100
	var wg sync.WaitGroup
	wg.Add(par)
	for i := 0; i < par; i++ {
		stream, _ := session.OpenStream()
		go func(s *Stream) {
			buf := make([]byte, 20)
			for j := 0; j < messages; j++ {
				msg := fmt.Sprintf("hello%v", j)
				s.Write([]byte(msg))
				if _, err := s.Read(buf); err != nil {
					break
				}
			}
			s.Close()
			wg.Done()
		}(stream)
	}
	t.Log("created", session.NumStreams(), "streams")
	wg.Wait()
	session.Close()
}

func TestCloseThenOpen(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	session.Close()
	if _, err := session.OpenStream(); err == nil {
		t.Fatal("opened after close")
	}
}

func TestIsClose(t *testing.T) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		t.Fatal(err)
	}
	session, _ := Client(cli, nil)
	session.Close()
	if session.IsClosed() != true {
		t.Fatal("still open after close")
	}
}

func TestKeepAliveTimeout(t *testing.T) {
	ln, err := net.Listen("tcp", "127.0.0.1:29999")
	if err != nil {
		// handle error
		panic(err)
	}
	go func() {
		ln.Accept()
	}()

	cli, err := net.Dial("tcp", "127.0.0.1:29999")
	if err != nil {
		t.Fatal(err)
	}

	config := DefaultConfig()
	config.KeepAliveInterval = 1
	config.KeepAliveTimeout = 2
	session, _ := Client(cli, config)
	<-time.After(3 * time.Second)
	if session.IsClosed() != true {
		t.Fatal("keepalive-timeout failed")
	}
}

func BenchmarkAcceptClose(b *testing.B) {
	cli, err := net.Dial("tcp", "127.0.0.1:19999")
	if err != nil {
		b.Fatal(err)
	}
	session, _ := Client(cli, nil)
	for i := 0; i < b.N; i++ {
		if stream, err := session.OpenStream(); err == nil {
			stream.Close()
		} else {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

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

func resourceAwsSubnet() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSubnetCreate,
		Read:   resourceAwsSubnetRead,
		Update: resourceAwsSubnetUpdate,
		Delete: resourceAwsSubnetDelete,

		Schema: map[string]*schema.Schema{
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"availability_zone": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"map_public_ip_on_launch": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	createOpts := &ec2.CreateSubnet{
		AvailabilityZone: d.Get("availability_zone").(string),
		CidrBlock:        d.Get("cidr_block").(string),
		VpcId:            d.Get("vpc_id").(string),
	}

	resp, err := ec2conn.CreateSubnet(createOpts)

	if err != nil {
		return fmt.Errorf("Error creating subnet: %s", err)
	}

	// Get the ID and store it
	subnet := &resp.Subnet
	d.SetId(subnet.SubnetId)
	log.Printf("[INFO] Subnet ID: %s", subnet.SubnetId)

	// Wait for the Subnet to become available
	log.Printf("[DEBUG] Waiting for subnet (%s) to become available", subnet.SubnetId)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "available",
		Refresh: SubnetStateRefreshFunc(ec2conn, subnet.SubnetId),
		Timeout: 10 * time.Minute,
	}

	_, err = stateConf.WaitForState()

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

	return resourceAwsSubnetUpdate(d, meta)
}

func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	resp, err := ec2conn.DescribeSubnets([]string{d.Id()}, ec2.NewFilter())

	if err != nil {
		return err
	}
	if resp == nil {
		return nil
	}

	subnet := &resp.Subnets[0]

	d.Set("vpc_id", subnet.VpcId)
	d.Set("availability_zone", subnet.AvailabilityZone)
	d.Set("cidr_block", subnet.CidrBlock)
	d.Set("map_public_ip_on_launch", subnet.MapPublicIpOnLaunch)
	d.Set("tags", tagsToMap(subnet.Tags))

	return nil
}

func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	d.Partial(true)

	if err := setTags(ec2conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	if d.HasChange("map_public_ip_on_launch") {
		modifyOpts := &ec2.ModifySubnetAttribute{
			SubnetId:            d.Id(),
			MapPublicIpOnLaunch: true,
		}

		log.Printf("[DEBUG] Subnet modify attributes: %#v", modifyOpts)

		_, err := ec2conn.ModifySubnetAttribute(modifyOpts)

		if err != nil {
			return err
		} else {
			d.SetPartial("map_public_ip_on_launch")
		}
	}

	d.Partial(false)

	return resourceAwsSubnetRead(d, meta)
}

func resourceAwsSubnetDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	log.Printf("[INFO] Deleting subnet: %s", d.Id())
	if _, err := ec2conn.DeleteSubnet(d.Id()); err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "InvalidSubnetID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting subnet: %s", err)
	}

	return nil
}

// SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch a Subnet.
func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeSubnets([]string{id}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidSubnetID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on SubnetStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		subnet := &resp.Subnets[0]
		return subnet, subnet.State, nil
	}
}
<commit_msg>Avoid unnecessary updating of aws_subnet<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

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

func resourceAwsSubnet() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSubnetCreate,
		Read:   resourceAwsSubnetRead,
		Update: resourceAwsSubnetUpdate,
		Delete: resourceAwsSubnetDelete,

		Schema: map[string]*schema.Schema{
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"availability_zone": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"map_public_ip_on_launch": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	createOpts := &ec2.CreateSubnet{
		AvailabilityZone: d.Get("availability_zone").(string),
		CidrBlock:        d.Get("cidr_block").(string),
		VpcId:            d.Get("vpc_id").(string),
	}

	resp, err := ec2conn.CreateSubnet(createOpts)

	if err != nil {
		return fmt.Errorf("Error creating subnet: %s", err)
	}

	// Get the ID and store it
	subnet := &resp.Subnet
	d.SetId(subnet.SubnetId)
	log.Printf("[INFO] Subnet ID: %s", subnet.SubnetId)

	// Wait for the Subnet to become available
	log.Printf("[DEBUG] Waiting for subnet (%s) to become available", subnet.SubnetId)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "available",
		Refresh: SubnetStateRefreshFunc(ec2conn, subnet.SubnetId),
		Timeout: 10 * time.Minute,
	}

	_, err = stateConf.WaitForState()

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

	return resourceAwsSubnetUpdate(d, meta)
}

func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	resp, err := ec2conn.DescribeSubnets([]string{d.Id()}, ec2.NewFilter())

	if err != nil {
		return err
	}
	if resp == nil {
		return nil
	}

	subnet := &resp.Subnets[0]

	d.Set("vpc_id", subnet.VpcId)
	d.Set("availability_zone", subnet.AvailabilityZone)
	d.Set("cidr_block", subnet.CidrBlock)
	d.Set("map_public_ip_on_launch", subnet.MapPublicIpOnLaunch)
	d.Set("tags", tagsToMap(subnet.Tags))

	return nil
}

func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	d.Partial(true)

	if err := setTags(ec2conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	if d.HasChange("map_public_ip_on_launch") {
		modifyOpts := &ec2.ModifySubnetAttribute{
			SubnetId:            d.Id(),
			MapPublicIpOnLaunch: true,
		}

		log.Printf("[DEBUG] Subnet modify attributes: %#v", modifyOpts)

		_, err := ec2conn.ModifySubnetAttribute(modifyOpts)

		if err != nil {
			return err
		} else {
			d.SetPartial("map_public_ip_on_launch")
		}
	}

	d.Partial(false)

	return resourceAwsSubnetRead(d, meta)
}

func resourceAwsSubnetDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	log.Printf("[INFO] Deleting subnet: %s", d.Id())
	if _, err := ec2conn.DeleteSubnet(d.Id()); err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "InvalidSubnetID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting subnet: %s", err)
	}

	return nil
}

// SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch a Subnet.
func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeSubnets([]string{id}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidSubnetID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on SubnetStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		subnet := &resp.Subnets[0]
		return subnet, subnet.State, nil
	}
}
<|endoftext|>


<commit_before>package arn

import (
	"sort"
	"strings"

	"github.com/aerogo/flow"
)

// MinimumStringSimilarity is the minimum JaroWinkler distance we accept for search results.
const MinimumStringSimilarity = 0.89

// SearchIndex ...
type SearchIndex struct {
	TextToID map[string]string `json:"textToId"`
}

// NewSearchIndex ...
func NewSearchIndex() *SearchIndex {
	return &SearchIndex{
		TextToID: make(map[string]string),
	}
}

// GetSearchIndex ...
func GetSearchIndex(id string) (*SearchIndex, error) {
	obj, err := DB.Get("SearchIndex", id)

	if err != nil {
		return nil, err
	}

	return obj.(*SearchIndex), nil
}

// Search is a fuzzy search.
func Search(term string, maxUsers, maxAnime int) ([]*User, []*Anime) {
	term = strings.ToLower(term)
	term = RemoveSpecialCharacters(term)

	if term == "" {
		return nil, nil
	}

	var userResults []*User
	var animeResults []*Anime

	type SearchItem struct {
		text       string
		similarity float64
	}

	// Search everything in parallel
	flow.Parallel(func() {
		// Search userResults
		var user *User

		userSearchIndex, err := GetSearchIndex("User")

		if err != nil {
			return
		}

		textToID := userSearchIndex.TextToID

		// Search items
		items := make([]*SearchItem, 0)

		for name := range textToID {
			s := StringSimilarity(term, name)

			if strings.Contains(name, term) {
				s += 0.5
			}

			if s < MinimumStringSimilarity {
				continue
			}

			items = append(items, &SearchItem{
				text:       name,
				similarity: s,
			})
		}

		// Sort
		sort.Slice(items, func(i, j int) bool {
			return items[i].similarity > items[j].similarity
		})

		// Limit
		if len(items) >= maxUsers {
			items = items[:maxUsers]
		}

		// Fetch data
		for _, item := range items {
			user, err = GetUser(textToID[item.text])

			if err != nil {
				continue
			}

			userResults = append(userResults, user)
		}
	}, func() {
		// Search anime
		var anime *Anime

		animeSearchIndex, err := GetSearchIndex("Anime")

		if err != nil {
			return
		}

		textToID := animeSearchIndex.TextToID

		// Search items
		items := make([]*SearchItem, 0)
		animeIDAdded := map[string]*SearchItem{}

		for name, id := range textToID {
			cleanName := RemoveSpecialCharacters(name)
			s := StringSimilarity(term, cleanName)

			if strings.Contains(cleanName, term) {
				s += 0.5
			}

			if s < MinimumStringSimilarity {
				continue
			}

			addedEntry, found := animeIDAdded[id]

			// Skip existing anime IDs
			if found {
				// But update existing entry with new similarity if it's higher
				if s > addedEntry.similarity {
					addedEntry.similarity = s
				}

				continue
			}

			item := &SearchItem{
				text:       name,
				similarity: s,
			}
			items = append(items, item)

			animeIDAdded[id] = item
		}

		// Sort
		sort.Slice(items, func(i, j int) bool {
			return items[i].similarity > items[j].similarity
		})

		// Limit
		if len(items) >= maxAnime {
			items = items[:maxAnime]
		}

		// Fetch data
		for _, item := range items {
			anime, err = GetAnime(textToID[item.text])

			if err != nil {
				continue
			}

			animeResults = append(animeResults, anime)
		}
	})

	return userResults, animeResults
}
<commit_msg>Improved search<commit_after>package arn

import (
	"sort"
	"strings"

	"github.com/aerogo/flow"
)

// MinimumStringSimilarity is the minimum JaroWinkler distance we accept for search results.
const MinimumStringSimilarity = 0.89

// SearchIndex ...
type SearchIndex struct {
	TextToID map[string]string `json:"textToId"`
}

// NewSearchIndex ...
func NewSearchIndex() *SearchIndex {
	return &SearchIndex{
		TextToID: make(map[string]string),
	}
}

// GetSearchIndex ...
func GetSearchIndex(id string) (*SearchIndex, error) {
	obj, err := DB.Get("SearchIndex", id)

	if err != nil {
		return nil, err
	}

	return obj.(*SearchIndex), nil
}

// Search is a fuzzy search.
func Search(term string, maxUsers, maxAnime, maxPosts, maxThreads int) ([]*User, []*Anime, []*Post, []*Thread) {
	term = strings.ToLower(term)

	if term == "" {
		return nil, nil, nil, nil
	}

	var userResults []*User
	var animeResults []*Anime
	var postResults []*Post
	var threadResults []*Thread

	type SearchItem struct {
		text       string
		similarity float64
	}

	searchUsers := func() {
		// Search userResults
		var user *User

		userSearchIndex, err := GetSearchIndex("User")

		if err != nil {
			return
		}

		textToID := userSearchIndex.TextToID

		// Search items
		items := make([]*SearchItem, 0)

		for name := range textToID {
			s := StringSimilarity(term, name)

			if strings.Contains(name, term) {
				s += 0.5
			}

			if s < MinimumStringSimilarity {
				continue
			}

			items = append(items, &SearchItem{
				text:       name,
				similarity: s,
			})
		}

		// Sort
		sort.Slice(items, func(i, j int) bool {
			return items[i].similarity > items[j].similarity
		})

		// Limit
		if len(items) >= maxUsers {
			items = items[:maxUsers]
		}

		// Fetch data
		for _, item := range items {
			user, err = GetUser(textToID[item.text])

			if err != nil {
				continue
			}

			userResults = append(userResults, user)
		}
	}

	searchAnime := func() {
		// Remove special characters when searching anime titles
		animeSearchTerm := RemoveSpecialCharacters(term)

		// Search anime
		var anime *Anime

		animeSearchIndex, err := GetSearchIndex("Anime")

		if err != nil {
			return
		}

		textToID := animeSearchIndex.TextToID

		// Search items
		items := make([]*SearchItem, 0)
		animeIDAdded := map[string]*SearchItem{}

		for name, id := range textToID {
			cleanName := RemoveSpecialCharacters(name)
			s := StringSimilarity(animeSearchTerm, cleanName)

			if strings.Contains(cleanName, animeSearchTerm) {
				s += 0.5
			}

			if s < MinimumStringSimilarity {
				continue
			}

			addedEntry, found := animeIDAdded[id]

			// Skip existing anime IDs
			if found {
				// But update existing entry with new similarity if it's higher
				if s > addedEntry.similarity {
					addedEntry.similarity = s
				}

				continue
			}

			item := &SearchItem{
				text:       name,
				similarity: s,
			}
			items = append(items, item)

			animeIDAdded[id] = item
		}

		// Sort
		sort.Slice(items, func(i, j int) bool {
			return items[i].similarity > items[j].similarity
		})

		// Limit
		if len(items) >= maxAnime {
			items = items[:maxAnime]
		}

		// Fetch data
		for _, item := range items {
			anime, err = GetAnime(textToID[item.text])

			if err != nil {
				continue
			}

			animeResults = append(animeResults, anime)
		}
	}

	searchPosts := func() {
		postSearchIndex, err := GetSearchIndex("Post")

		if err != nil {
			return
		}

		textToID := postSearchIndex.TextToID

		// Search items
		items := make([]string, 0)

		for text, postID := range textToID {
			if !strings.Contains(text, term) {
				continue
			}

			items = append(items, postID)

			// Limit
			if len(items) >= maxPosts {
				break
			}
		}

		// Fetch data
		obj, err := DB.GetMany("Post", items)

		if err != nil {
			return
		}

		postResults = obj.([]*Post)
	}

	searchThreads := func() {
		threadSearchIndex, err := GetSearchIndex("Thread")

		if err != nil {
			return
		}

		textToID := threadSearchIndex.TextToID

		// Search items
		items := make([]string, 0)

		for text, threadID := range textToID {
			if !strings.Contains(text, term) {
				continue
			}

			items = append(items, threadID)

			// Limit
			if len(items) >= maxThreads {
				break
			}
		}

		// Fetch data
		obj, err := DB.GetMany("Thread", items)

		if err != nil {
			return
		}

		threadResults = obj.([]*Thread)
	}

	// Search everything in parallel
	flow.Parallel(
		searchUsers,
		searchAnime,
		searchPosts,
		searchThreads,
	)

	return userResults, animeResults, postResults, threadResults
}
<|endoftext|>


<commit_before>package dilbert

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

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
	"github.com/blacktop/scifgif/elasticsearch"
	"github.com/jpillora/backoff"
)

var attempt int

// MaxAttempts max number of download attempts
const MaxAttempts = 20

// Comic is the dilbert comic strip meta data
type Comic struct {
	Title      string
	Tags       []string
	ImageURL   string
	Transcript string
}

// GetComicMetaData gets all the comic strips meta data
func GetComicMetaData(url, date string, b *backoff.Backoff) Comic {
	comic := Comic{}

	if attempt > MaxAttempts {
		return comic
	}

	doc, err := goquery.NewDocument(url)
	if err != nil {
		log.Error(err)
		// backoff and try again
		backoff := b.Duration()
		log.WithFields(log.Fields{
			"backoff": backoff,
			"attempt": attempt,
		}).Info("waiting to try to again")
		time.Sleep(backoff)
		// retry url meta data parse
		attempt++
		GetComicMetaData(url, date, b)
	}
	// GET TITLE
	comic.Title = doc.Find(".comic-title-name").Text()
	// GET IMAGE URL
	doc.Find(".img-comic-container").Each(func(i int, s *goquery.Selection) {
		comic.ImageURL, _ = s.Find("img").Attr("src")
	})
	// GET TAGS
	doc.Find(".comic-tags").Each(func(i int, s *goquery.Selection) {
		s.Find("a").Each(func(i int, a *goquery.Selection) {
			comic.Tags = append(comic.Tags, strings.TrimPrefix(a.Text(), "#"))
		})
	})
	// GET TRANSCRIPT
	id := "js-toggle-transcript-" + date
	transcripts := doc.Find("div#" + id).Text()
	// clean up string
	transcripts = strings.TrimSpace(transcripts)
	transcripts = strings.TrimPrefix(transcripts, "Transcript")
	transcripts = strings.TrimSpace(transcripts)
	comic.Transcript = transcripts

	return comic
}

// GetAllDilbert havest all teh comics strips
func GetAllDilbert(folder string, date string) error {
	count := 0
	attempt = 0
	b := &backoff.Backoff{
		//These are the defaults
		Min:    100 * time.Millisecond,
		Max:    1200 * time.Second,
		Factor: 3,
		Jitter: true,
	}

	if len(date) < 1 {
		// date = "1989-04-17"
		date = "2017-09-08"
	}
	start, _ := time.Parse("2006-01-02", date)

	for d := start; time.Now().After(d); d = d.AddDate(0, 0, 1) {
		date := fmt.Sprintf("%04d-%02d-%02d", d.Year(), d.Month(), d.Day())
		url := "http://dilbert.com/strip/" + date
		comic := GetComicMetaData(url, date, b)
		// download image
		log.WithFields(log.Fields{
			"id":    date,
			"title": comic.Title,
		}).Debug("downloading file")

		filepath := filepath.Join(folder, date+".jpg")
		go elasticsearch.DownloadImage(comic.ImageURL, filepath)

		// index into elasticsearch
		elasticsearch.WriteImageToDatabase(elasticsearch.ImageMetaData{
			Name:   comic.Title,
			ID:     date,
			Source: "dilbert",
			Title:  strings.Join(comic.Tags, " "),
			Text:   comic.Transcript,
			Path:   filepath,
		}, "dilbert")
		// incr count, reset attempts and reset backoff
		count++
		attempt = 0
		b.Reset()
	}
	log.WithFields(log.Fields{"count": count}).Info("dilbert comic complete")
	return nil
}

// // DownloadImage downloads image to filepath
// func downloadImageWithBackOff(url, filepath string, b *backoff.Backoff) error {
// 	// Create the file
// 	out, err := os.Create(filepath)
// 	if err != nil {
// 		log.Error(err)
// 	}
// 	defer out.Close()

// 	resp, err := http.Get(url)
// 	if err != nil {
// 		log.Error(err)
// 		log.Info("waiting to try to download again")
// 		time.Sleep(b.Duration())
// 		// retry image download
// 		downloadImageWithBackOff(url, filepath, b)
// 	}
// 	defer resp.Body.Close()

// 	// resert backoff
// 	b.Reset()

// 	log.WithFields(log.Fields{
// 		"status":   resp.Status,
// 		"size":     resp.ContentLength,
// 		"filepath": filepath,
// 	}).Debug("downloading file")

// 	// Writer the body to file
// 	_, err = io.Copy(out, resp.Body)
// 	if err != nil {
// 		return err
// 	}
// 	return nil
// }
<commit_msg>dump out after max attempts<commit_after>package dilbert

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

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
	"github.com/blacktop/scifgif/elasticsearch"
	"github.com/jpillora/backoff"
)

var attempt int

// MaxAttempts max number of download attempts
const MaxAttempts = 20

// Comic is the dilbert comic strip meta data
type Comic struct {
	Title      string
	Tags       []string
	ImageURL   string
	Transcript string
}

// GetComicMetaData gets all the comic strips meta data
func GetComicMetaData(url, date string, b *backoff.Backoff) Comic {
	comic := Comic{}

	if attempt > MaxAttempts {
		return comic
	}

	doc, err := goquery.NewDocument(url)
	if err != nil {
		log.Error(err)
		// backoff and try again
		backoff := b.Duration()
		log.WithFields(log.Fields{
			"backoff": backoff,
			"attempt": attempt,
		}).Info("waiting to try to again")
		time.Sleep(backoff)
		// retry url meta data parse
		attempt++
		GetComicMetaData(url, date, b)
	}
	// GET TITLE
	comic.Title = doc.Find(".comic-title-name").Text()
	// GET IMAGE URL
	doc.Find(".img-comic-container").Each(func(i int, s *goquery.Selection) {
		comic.ImageURL, _ = s.Find("img").Attr("src")
	})
	// GET TAGS
	doc.Find(".comic-tags").Each(func(i int, s *goquery.Selection) {
		s.Find("a").Each(func(i int, a *goquery.Selection) {
			comic.Tags = append(comic.Tags, strings.TrimPrefix(a.Text(), "#"))
		})
	})
	// GET TRANSCRIPT
	id := "js-toggle-transcript-" + date
	transcripts := doc.Find("div#" + id).Text()
	// clean up string
	transcripts = strings.TrimSpace(transcripts)
	transcripts = strings.TrimPrefix(transcripts, "Transcript")
	transcripts = strings.TrimSpace(transcripts)
	comic.Transcript = transcripts

	return comic
}

// GetAllDilbert havest all teh comics strips
func GetAllDilbert(folder string, date string) error {
	count := 0
	attempt = 0
	b := &backoff.Backoff{
		//These are the defaults
		Min:    100 * time.Millisecond,
		Max:    1200 * time.Second,
		Factor: 3,
		Jitter: true,
	}

	if len(date) < 1 {
		// date = "1989-04-17"
		date = "2017-09-08"
	}
	start, _ := time.Parse("2006-01-02", date)

	for d := start; time.Now().After(d); d = d.AddDate(0, 0, 1) {
		date := fmt.Sprintf("%04d-%02d-%02d", d.Year(), d.Month(), d.Day())
		url := "http://dilbert.com/strip/" + date
		comic := GetComicMetaData(url, date, b)
		if len(comic.Title) > 0 {
			return errors.New("max number of attempts reached")
		}
		// download image
		log.WithFields(log.Fields{
			"id":    date,
			"title": comic.Title,
		}).Debug("downloading file")

		filepath := filepath.Join(folder, date+".jpg")
		go elasticsearch.DownloadImage(comic.ImageURL, filepath)

		// index into elasticsearch
		elasticsearch.WriteImageToDatabase(elasticsearch.ImageMetaData{
			Name:   comic.Title,
			ID:     date,
			Source: "dilbert",
			Title:  strings.Join(comic.Tags, " "),
			Text:   comic.Transcript,
			Path:   filepath,
		}, "dilbert")
		// incr count, reset attempts and reset backoff
		count++
		attempt = 0
		b.Reset()
	}
	log.WithFields(log.Fields{"count": count}).Info("dilbert comic complete")
	return nil
}
<|endoftext|>


<commit_before>package yamux

import (
	"fmt"
	"io"
	"sync"
	"testing"
	"time"
)

type pipeConn struct {
	reader *io.PipeReader
	writer *io.PipeWriter
}

func (p *pipeConn) Read(b []byte) (int, error) {
	return p.reader.Read(b)
}

func (p *pipeConn) Write(b []byte) (int, error) {
	return p.writer.Write(b)
}

func (p *pipeConn) Close() error {
	p.reader.Close()
	return p.writer.Close()
}

func testConn() (io.ReadWriteCloser, io.ReadWriteCloser) {
	read1, write1 := io.Pipe()
	read2, write2 := io.Pipe()
	return &pipeConn{read1, write2}, &pipeConn{read2, write1}
}

func testClientServer() (*Session, *Session) {
	conn1, conn2 := testConn()
	client, _ := Client(conn1, nil)
	server, _ := Server(conn2, nil)
	return client, server
}

func TestPing(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	rtt, err := client.Ping()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if rtt == 0 {
		t.Fatalf("bad: %v", rtt)
	}

	rtt, err = server.Ping()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if rtt == 0 {
		t.Fatalf("bad: %v", rtt)
	}
}

func TestAccept(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}
	wg.Add(4)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 1 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 2 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := server.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 2 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 1 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()

	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestSendData_Small(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		buf := make([]byte, 4)
		for i := 0; i < 1000; i++ {
			n, err := stream.Read(buf)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("short read: %d", n)
			}
			if string(buf) != "test" {
				t.Fatalf("bad: %s", buf)
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		for i := 0; i < 1000; i++ {
			n, err := stream.Write([]byte("test"))
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("short write %d", n)
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()
	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestSendData_Large(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	data := make([]byte, 512*1024)
	for idx := range data {
		data[idx] = byte(idx % 256)
	}

	wg := &sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		buf := make([]byte, 4*1024)
		for i := 0; i < 128; i++ {
			n, err := stream.Read(buf)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4*1024 {
				t.Fatalf("short read: %d", n)
			}
			for idx := range buf {
				if buf[idx] != byte(idx%256) {
					t.Fatalf("bad: %v %v %v", i, idx, buf[idx])
				}
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		n, err := stream.Write(data)
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if n != len(data) {
			t.Fatalf("short write %d", n)
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()
	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestGoAway(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	if err := server.GoAway(); err != nil {
		t.Fatalf("err: %v", err)
	}

	_, err := client.Open()
	if err != ErrRemoteGoAway {
		t.Fatalf("err: %v", err)
	}
}

func TestManyStreams(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}

	acceptor := func(i int) {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		buf := make([]byte, 512)
		for {
			n, err := stream.Read(buf)
			println("read")
			if err == io.EOF {
				return
			}
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n == 0 {
				t.Fatalf("err: %v", err)
			}
		}
	}
	sender := func(i int) {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		msg := fmt.Sprintf("%08d", i)
		for i := 0; i < 1000; i++ {
			n, err := stream.Write([]byte(msg))
			println("write")
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != len(msg) {
				t.Fatalf("short write %d", n)
			}
		}
	}

	for i := 0; i < 50; i++ {
		wg.Add(2)
		go acceptor(i)
		go sender(i)
	}

	wg.Wait()
}
<commit_msg>Adding ping pong test<commit_after>package yamux

import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"testing"
	"time"
)

type pipeConn struct {
	reader *io.PipeReader
	writer *io.PipeWriter
}

func (p *pipeConn) Read(b []byte) (int, error) {
	return p.reader.Read(b)
}

func (p *pipeConn) Write(b []byte) (int, error) {
	return p.writer.Write(b)
}

func (p *pipeConn) Close() error {
	p.reader.Close()
	return p.writer.Close()
}

func testConn() (io.ReadWriteCloser, io.ReadWriteCloser) {
	read1, write1 := io.Pipe()
	read2, write2 := io.Pipe()
	return &pipeConn{read1, write2}, &pipeConn{read2, write1}
}

func testClientServer() (*Session, *Session) {
	conn1, conn2 := testConn()
	client, _ := Client(conn1, nil)
	server, _ := Server(conn2, nil)
	return client, server
}

func TestPing(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	rtt, err := client.Ping()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if rtt == 0 {
		t.Fatalf("bad: %v", rtt)
	}

	rtt, err = server.Ping()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if rtt == 0 {
		t.Fatalf("bad: %v", rtt)
	}
}

func TestAccept(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}
	wg.Add(4)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 1 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 2 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := server.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 2 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if id := stream.StreamID(); id != 1 {
			t.Fatalf("bad: %v", id)
		}
		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()

	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestSendData_Small(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		buf := make([]byte, 4)
		for i := 0; i < 1000; i++ {
			n, err := stream.Read(buf)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("short read: %d", n)
			}
			if string(buf) != "test" {
				t.Fatalf("bad: %s", buf)
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		for i := 0; i < 1000; i++ {
			n, err := stream.Write([]byte("test"))
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("short write %d", n)
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()
	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestSendData_Large(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	data := make([]byte, 512*1024)
	for idx := range data {
		data[idx] = byte(idx % 256)
	}

	wg := &sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		buf := make([]byte, 4*1024)
		for i := 0; i < 128; i++ {
			n, err := stream.Read(buf)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4*1024 {
				t.Fatalf("short read: %d", n)
			}
			for idx := range buf {
				if buf[idx] != byte(idx%256) {
					t.Fatalf("bad: %v %v %v", i, idx, buf[idx])
				}
			}
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	go func() {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}

		n, err := stream.Write(data)
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		if n != len(data) {
			t.Fatalf("short write %d", n)
		}

		if err := stream.Close(); err != nil {
			t.Fatalf("err: %v", err)
		}
	}()

	doneCh := make(chan struct{})
	go func() {
		wg.Wait()
		close(doneCh)
	}()
	select {
	case <-doneCh:
	case <-time.After(time.Second):
		panic("timeout")
	}
}

func TestGoAway(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	if err := server.GoAway(); err != nil {
		t.Fatalf("err: %v", err)
	}

	_, err := client.Open()
	if err != ErrRemoteGoAway {
		t.Fatalf("err: %v", err)
	}
}

func TestManyStreams(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}

	acceptor := func(i int) {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		buf := make([]byte, 512)
		for {
			n, err := stream.Read(buf)
			if err == io.EOF {
				return
			}
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n == 0 {
				t.Fatalf("err: %v", err)
			}
		}
	}
	sender := func(i int) {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		msg := fmt.Sprintf("%08d", i)
		for i := 0; i < 1000; i++ {
			n, err := stream.Write([]byte(msg))
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != len(msg) {
				t.Fatalf("short write %d", n)
			}
		}
	}

	for i := 0; i < 50; i++ {
		wg.Add(2)
		go acceptor(i)
		go sender(i)
	}

	wg.Wait()
}

func TestManyStreams_PingPong(t *testing.T) {
	client, server := testClientServer()
	defer client.Close()
	defer server.Close()

	wg := &sync.WaitGroup{}

	ping := []byte("ping")
	pong := []byte("pong")

	acceptor := func(i int) {
		defer wg.Done()
		stream, err := server.AcceptStream()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		buf := make([]byte, 4)
		for {
			n, err := stream.Read(buf)
			if err == io.EOF {
				return
			}
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("err: %v", err)
			}
			if !bytes.Equal(buf, ping) {
				t.Fatalf("bad: %s", buf)
			}
			n, err = stream.Write(pong)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("err: %v", err)
			}
		}
	}
	sender := func(i int) {
		defer wg.Done()
		stream, err := client.Open()
		if err != nil {
			t.Fatalf("err: %v", err)
		}
		defer stream.Close()

		buf := make([]byte, 4)
		for i := 0; i < 10000; i++ {
			n, err := stream.Write(ping)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("short write %d", n)
			}

			n, err = stream.Read(buf)
			if err != nil {
				t.Fatalf("err: %v", err)
			}
			if n != 4 {
				t.Fatalf("err: %v", err)
			}
			if !bytes.Equal(buf, pong) {
				t.Fatalf("bad: %s", buf)
			}
		}
	}

	for i := 0; i < 100; i++ {
		wg.Add(2)
		go acceptor(i)
		go sender(i)
	}

	wg.Wait()
}
<|endoftext|>


<commit_before>package discord

import (
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	"github.com/bwmarrin/discordgo"

	"github.com/adayoung/ada-bot/discord/botReactions"
	"github.com/adayoung/ada-bot/settings"
)

// BotID is set by InitDiscordSession for subsequent use in reactions dispatcher
var BotID string
var dg *discordgo.Session

func init() {
	rand.Seed(time.Now().Unix())
}

// InitDiscordSession creates a new Discord session using the provided login information.
func InitDiscordSession(token string, qLength int, waitMs string) error {
	var err error
	if dg, err = discordgo.New(fmt.Sprintf("Bot %s", token)); err == nil {
		if u, err := dg.User("@me"); err == nil {
			BotID = u.ID

			dg.AddHandler(ready)
			// Add handlers for messages received
			dg.AddHandler(messageCreate)
			dg.AddHandler(messageUpdate)
			dg.AddHandler(messageDelete)
			dg.AddHandler(guildMemberAdd)
			if err = dg.Open(); err == nil {
				fmt.Println("Successfully launched a new Discord session.")
			} else {
				return err // Error at opening Discord Session
			}
		} else {
			return err // Error at obtaining account details
		}
	} else {
		return err // Error at creating a new Discord session
	}

	if _waitMs, err := time.ParseDuration(waitMs); err == nil {
		messageQueue = make(chan message, qLength)
		rateLimit = time.NewTicker(_waitMs)
		go dispatchMessages()
	} else {
		return err
	}
	return nil
}

// PostMessage queues a message for posting via Discord API, takes channelID and message
func PostMessage(c string, m string) {
	if len(m) > 0 {
		mq := message{ChannelID: c, Message: m}
		messageQueue <- mq
	}
}

// CloseDiscordSession closes Discord Gateway websocket, to be used on exit
func CloseDiscordSession() {
	dg.Close()
}

func ready(s *discordgo.Session, r *discordgo.Ready) {
	if guilds, err := s.UserGuilds(100, "", ""); err != nil {
		fmt.Println("ERROR: We couldn't get UserGuilds")
		log.Fatalf("error: %v", err)
	} else {
		for index, guild := range guilds {
			fmt.Printf("[%d] ------------------------------\n", index)
			fmt.Println("Guild ID: ", guild.ID)
			fmt.Println("Guild Name: ", guild.Name)
			fmt.Println("Guild Permissions: ", guild.Permissions)

		}
		fmt.Println("----------------------------------")
	}
	if err := s.UpdateStatus(0, "play.achaea.com"); err != nil {
		log.Printf("warning: discordgo.Session.UpdateStatus: %v", err) // Not a fatal error
	}
}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	go _botReactions(s, m.Message, "CREATE")
}

func messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
	go _botReactions(s, m.Message, "UPDATE")
}

func messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) {
	go _botReactions(s, m.Message, "DELETE")
}

func _botReactions(s *discordgo.Session, m *discordgo.Message, mType string) {
	// if m.Author == nil { // iopred - Yeah, Author isn't guaranteed to be non nil
	// 	return // iopred - @Ada, in _botReactions you really should just do <-- that
	// }

	if m.Author != nil {
		if m.Author.ID == BotID { // ignore the bot's own messages from processing
			return
		}
	} else {
		return // let's not bother with a message without an Author!@
	}

	if channel, err := s.State.Channel(m.ChannelID); err == nil {
		guildID := channel.GuildID

		if guildID == "" { // log direct messages sent to the bot
			fmt.Printf("Message received from %s: %s\n", m.Author.Username, m.Content)
			_postReactions(m, &discordgo.Member{}, mType)
			return
		}

		var member *discordgo.Member
		if m.Author != nil {
			if member, err = s.State.Member(guildID, m.Author.ID); err != nil {
				member = nil
				log.Printf("warning: discordgo.Session.State.Member: %v", err) // Non-fatal error at s.State.Member() call
				return                                                         // This is usually followed by a crash, obviously a fatal error! Oops D:
			}

			if m.Author.ID == settings.Settings.Discord.BotAdmin {
				if strings.HasPrefix(m.Content, "!join") {
					vid := strings.TrimSpace(m.Content[5:])
					if len(vid) > 0 {
						JoinVoice(guildID, vid)
					}
				} else if strings.HasPrefix(m.Content, "!leave") {
					LeaveVoice()
				} else if strings.HasPrefix(m.Content, "!setrole") {
					setRole(s, m, guildID, strings.TrimSpace(m.Content[8:]), nil)
				}
			}
		}
		_postReactions(m, member, mType)

	} else {
		log.Printf("warning: discordgo.Session.State.Channel: %v", err) // Non-fatal error at s.State.Channel() call
	}
}

func _postReactions(m *discordgo.Message, member *discordgo.Member, mType string) {
	for _, reaction := range botReactions.GetReactions(m, member, mType, "", 0) {
		if reaction.Timer != nil {
			time.AfterFunc(*reaction.Timer, func() {
				for _, reaction := range botReactions.GetReactions(m, member, mType, reaction.Trigger, reaction.TriggerIndex) {
					PostMessage(m.ChannelID, reaction.Text)
				}
			})
		} else {
			PostMessage(m.ChannelID, reaction.Text)
		}
	}
}
<commit_msg>Enable Privileged Intents for GuildMembers state cache<commit_after>package discord

import (
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	"github.com/bwmarrin/discordgo"

	"github.com/adayoung/ada-bot/discord/botReactions"
	"github.com/adayoung/ada-bot/settings"
)

// BotID is set by InitDiscordSession for subsequent use in reactions dispatcher
var BotID string
var dg *discordgo.Session

func init() {
	rand.Seed(time.Now().Unix())
}

// InitDiscordSession creates a new Discord session using the provided login information.
func InitDiscordSession(token string, qLength int, waitMs string) error {
	var err error
	if dg, err = discordgo.New(fmt.Sprintf("Bot %s", token)); err == nil {
		if u, err := dg.User("@me"); err == nil {
			BotID = u.ID

			dg.AddHandler(ready)
			// Add handlers for messages received
			dg.AddHandler(messageCreate)
			dg.AddHandler(messageUpdate)
			dg.AddHandler(messageDelete)
			dg.AddHandler(guildMemberAdd)
			dg.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAll)
			if err = dg.Open(); err == nil {
				fmt.Println("Successfully launched a new Discord session.")
			} else {
				return err // Error at opening Discord Session
			}
		} else {
			return err // Error at obtaining account details
		}
	} else {
		return err // Error at creating a new Discord session
	}

	if _waitMs, err := time.ParseDuration(waitMs); err == nil {
		messageQueue = make(chan message, qLength)
		rateLimit = time.NewTicker(_waitMs)
		go dispatchMessages()
	} else {
		return err
	}
	return nil
}

// PostMessage queues a message for posting via Discord API, takes channelID and message
func PostMessage(c string, m string) {
	if len(m) > 0 {
		mq := message{ChannelID: c, Message: m}
		messageQueue <- mq
	}
}

// CloseDiscordSession closes Discord Gateway websocket, to be used on exit
func CloseDiscordSession() {
	dg.Close()
}

func ready(s *discordgo.Session, r *discordgo.Ready) {
	if guilds, err := s.UserGuilds(100, "", ""); err != nil {
		fmt.Println("ERROR: We couldn't get UserGuilds")
		log.Fatalf("error: %v", err)
	} else {
		for index, guild := range guilds {
			fmt.Printf("[%d] ------------------------------\n", index)
			fmt.Println("Guild ID: ", guild.ID)
			fmt.Println("Guild Name: ", guild.Name)
			fmt.Println("Guild Permissions: ", guild.Permissions)

		}
		fmt.Println("----------------------------------")
	}
	if err := s.UpdateStatus(0, "play.achaea.com"); err != nil {
		log.Printf("warning: discordgo.Session.UpdateStatus: %v", err) // Not a fatal error
	}
}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	go _botReactions(s, m.Message, "CREATE")
}

func messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
	go _botReactions(s, m.Message, "UPDATE")
}

func messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) {
	go _botReactions(s, m.Message, "DELETE")
}

func _botReactions(s *discordgo.Session, m *discordgo.Message, mType string) {
	// if m.Author == nil { // iopred - Yeah, Author isn't guaranteed to be non nil
	// 	return // iopred - @Ada, in _botReactions you really should just do <-- that
	// }

	if m.Author != nil {
		if m.Author.ID == BotID { // ignore the bot's own messages from processing
			return
		}
	} else {
		return // let's not bother with a message without an Author!@
	}

	if channel, err := s.State.Channel(m.ChannelID); err == nil {
		guildID := channel.GuildID

		if guildID == "" { // log direct messages sent to the bot
			fmt.Printf("Message received from %s: %s\n", m.Author.Username, m.Content)
			_postReactions(m, &discordgo.Member{}, mType)
			return
		}

		var member *discordgo.Member
		if m.Author != nil {
			if member, err = s.State.Member(guildID, m.Author.ID); err != nil {
				member = nil
				log.Printf("warning: discordgo.Session.State.Member: %v", err) // Non-fatal error at s.State.Member() call
				return                                                         // This is usually followed by a crash, obviously a fatal error! Oops D:
			}

			if m.Author.ID == settings.Settings.Discord.BotAdmin {
				if strings.HasPrefix(m.Content, "!join") {
					vid := strings.TrimSpace(m.Content[5:])
					if len(vid) > 0 {
						JoinVoice(guildID, vid)
					}
				} else if strings.HasPrefix(m.Content, "!leave") {
					LeaveVoice()
				} else if strings.HasPrefix(m.Content, "!setrole") {
					setRole(s, m, guildID, strings.TrimSpace(m.Content[8:]), nil)
				}
			}
		}
		_postReactions(m, member, mType)

	} else {
		log.Printf("warning: discordgo.Session.State.Channel: %v", err) // Non-fatal error at s.State.Channel() call
	}
}

func _postReactions(m *discordgo.Message, member *discordgo.Member, mType string) {
	for _, reaction := range botReactions.GetReactions(m, member, mType, "", 0) {
		if reaction.Timer != nil {
			time.AfterFunc(*reaction.Timer, func() {
				for _, reaction := range botReactions.GetReactions(m, member, mType, reaction.Trigger, reaction.TriggerIndex) {
					PostMessage(m.ChannelID, reaction.Text)
				}
			})
		} else {
			PostMessage(m.ChannelID, reaction.Text)
		}
	}
}
<|endoftext|>


<commit_before>package discover

import (
	"errors"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/flynn/rpcplus"
)

type Service struct {
	Index  int // not used yet
	Name   string
	Host   string
	Port   string
	Addr   string
	Attrs  map[string]string
	Online bool
}

type ServiceSet struct {
	services  map[string]*Service
	filters   map[string]string
	listeners map[chan *ServiceUpdate]struct{}
	serMutex  sync.RWMutex
	filMutex  sync.RWMutex
	lisMutex  sync.RWMutex
}

func (s *ServiceSet) Bind(updates chan *ServiceUpdate) {
	go func() {
		for update := range updates {
			// TODO: apply filters
			s.serMutex.Lock()
			if _, exists := s.services[update.Addr]; !exists {
				host, port, _ := net.SplitHostPort(update.Addr)
				s.services[update.Addr] = &Service{
					Name: update.Name,
					Addr: update.Addr,
					Host: host,
					Port: port,
				}
			}
			s.services[update.Addr].Online = update.Online
			s.services[update.Addr].Attrs = update.Attrs
			s.serMutex.Unlock()
			if s.listeners != nil {
				s.lisMutex.Lock()
				for ch := range s.listeners {
					ch <- update
				}
				s.lisMutex.Unlock()
			}
		}
	}()
}

func (s *ServiceSet) Online() []*Service {
	s.serMutex.Lock()
	defer s.serMutex.Unlock()
	list := make([]*Service, 0, len(s.services))
	for _, service := range s.services {
		if service.Online {
			list = append(list, service)
		}
	}
	return list
}

func (s *ServiceSet) Offline() []*Service {
	s.serMutex.Lock()
	defer s.serMutex.Unlock()
	list := make([]*Service, 0, len(s.services))
	for _, service := range s.services {
		if !service.Online {
			list = append(list, service)
		}
	}
	return list
}

func (s *ServiceSet) OnlineAddrs() []string {
	list := make([]string, 0, len(s.services))
	for _, service := range s.Online() {
		list = append(list, service.Addr)
	}
	return list
}

func (s *ServiceSet) OfflineAddrs() []string {
	list := make([]string, 0, len(s.services))
	for _, service := range s.Offline() {
		list = append(list, service.Addr)
	}
	return list
}

func (s *ServiceSet) Filter(attrs map[string]string) {
	s.filters = attrs
}

// Still not sure about this API, but it's a start
func (s *ServiceSet) Subscribe(ch chan *ServiceUpdate) {
	s.lisMutex.Lock()
	defer s.lisMutex.Unlock()
	s.listeners[ch] = struct{}{}
}

func (s *ServiceSet) Unsubscribe(ch chan *ServiceUpdate) {
	// TODO: close update stream
}

type DiscoverClient struct {
	client     *rpcplus.Client
	heartbeats map[string]bool
	hbMutex    sync.RWMutex
}

func NewClient() (*DiscoverClient, error) {
	client, err := rpcplus.DialHTTP("tcp", "127.0.0.1:1111") // TODO: default, not hardcoded
	return &DiscoverClient{
		client:     client,
		heartbeats: make(map[string]bool),
	}, err
}

func pickMostPublicIp() string {
	// TODO: prefer non 10.0.0.0, 172.16.0.0, and 192.168.0.0
	addrs, _ := net.InterfaceAddrs()
	var ip string
	for _, addr := range addrs {
		ip = strings.SplitN(addr.String(), "/", 2)[0]
		if !strings.Contains(ip, "::") && ip != "127.0.0.1" {
			return ip
		}
	}
	return ip
}

func (c *DiscoverClient) Services(name string) *ServiceSet {
	updates := make(chan *ServiceUpdate, 10)
	c.client.StreamGo("DiscoverAgent.Subscribe", &Args{
		Name: name,
	}, updates)
	set := &ServiceSet{
		services:  make(map[string]*Service),
		filters:   make(map[string]string),
		listeners: make(map[chan *ServiceUpdate]struct{}),
	}
	set.Bind(updates)
	return set
}

func (c *DiscoverClient) Register(name, port string, attributes map[string]string) error {
	return c.RegisterWithHost(name, pickMostPublicIp(), port, attributes)
}

func (c *DiscoverClient) RegisterWithHost(name, host, port string, attributes map[string]string) error {
	args := &Args{
		Name:  name,
		Addr:  net.JoinHostPort(host, port),
		Attrs: attributes,
	}
	var ret struct{}
	err := c.client.Call("DiscoverAgent.Register", args, &ret)
	if err != nil {
		return errors.New("discover: register failed: " + err.Error())
	}
	c.hbMutex.Lock()
	c.heartbeats[args.Addr] = true
	c.hbMutex.Unlock()
	go func() {
		var heartbeated struct{}
		for c.heartbeats[args.Addr] {
			time.Sleep(HeartbeatIntervalSecs * time.Second) // TODO: add jitter
			c.client.Call("DiscoverAgent.Heartbeat", &Args{
				Name: name,
				Addr: args.Addr,
			}, &heartbeated)
		}
	}()
	return nil
}

func (c *DiscoverClient) Unregister(name, port string) error {
	return c.UnregisterWithHost(name, pickMostPublicIp(), port)
}

func (c *DiscoverClient) UnregisterWithHost(name, host, port string) error {
	args := &Args{
		Name: name,
		Addr: net.JoinHostPort(host, port),
	}
	var resp struct{}
	err := c.client.Call("DiscoverAgent.Unregister", args, &resp)
	if err != nil {
		return errors.New("discover: unregister failed: " + err.Error())
	}
	c.hbMutex.Lock()
	delete(c.heartbeats, args.Addr)
	c.hbMutex.Unlock()
	return nil
}
<commit_msg>discoverd: removing unnecessary channel buffer<commit_after>package discover

import (
	"errors"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/flynn/rpcplus"
)

type Service struct {
	Index  int // not used yet
	Name   string
	Host   string
	Port   string
	Addr   string
	Attrs  map[string]string
	Online bool
}

type ServiceSet struct {
	services  map[string]*Service
	filters   map[string]string
	listeners map[chan *ServiceUpdate]struct{}
	serMutex  sync.RWMutex
	filMutex  sync.RWMutex
	lisMutex  sync.RWMutex
}

func (s *ServiceSet) Bind(updates chan *ServiceUpdate) {
	go func() {
		for update := range updates {
			// TODO: apply filters
			s.serMutex.Lock()
			if _, exists := s.services[update.Addr]; !exists {
				host, port, _ := net.SplitHostPort(update.Addr)
				s.services[update.Addr] = &Service{
					Name: update.Name,
					Addr: update.Addr,
					Host: host,
					Port: port,
				}
			}
			s.services[update.Addr].Online = update.Online
			s.services[update.Addr].Attrs = update.Attrs
			s.serMutex.Unlock()
			if s.listeners != nil {
				s.lisMutex.Lock()
				for ch := range s.listeners {
					ch <- update
				}
				s.lisMutex.Unlock()
			}
		}
	}()
}

func (s *ServiceSet) Online() []*Service {
	s.serMutex.Lock()
	defer s.serMutex.Unlock()
	list := make([]*Service, 0, len(s.services))
	for _, service := range s.services {
		if service.Online {
			list = append(list, service)
		}
	}
	return list
}

func (s *ServiceSet) Offline() []*Service {
	s.serMutex.Lock()
	defer s.serMutex.Unlock()
	list := make([]*Service, 0, len(s.services))
	for _, service := range s.services {
		if !service.Online {
			list = append(list, service)
		}
	}
	return list
}

func (s *ServiceSet) OnlineAddrs() []string {
	list := make([]string, 0, len(s.services))
	for _, service := range s.Online() {
		list = append(list, service.Addr)
	}
	return list
}

func (s *ServiceSet) OfflineAddrs() []string {
	list := make([]string, 0, len(s.services))
	for _, service := range s.Offline() {
		list = append(list, service.Addr)
	}
	return list
}

func (s *ServiceSet) Filter(attrs map[string]string) {
	s.filters = attrs
}

// Still not sure about this API, but it's a start
func (s *ServiceSet) Subscribe(ch chan *ServiceUpdate) {
	s.lisMutex.Lock()
	defer s.lisMutex.Unlock()
	s.listeners[ch] = struct{}{}
}

func (s *ServiceSet) Unsubscribe(ch chan *ServiceUpdate) {
	// TODO: close update stream
}

type DiscoverClient struct {
	client     *rpcplus.Client
	heartbeats map[string]bool
	hbMutex    sync.RWMutex
}

func NewClient() (*DiscoverClient, error) {
	client, err := rpcplus.DialHTTP("tcp", "127.0.0.1:1111") // TODO: default, not hardcoded
	return &DiscoverClient{
		client:     client,
		heartbeats: make(map[string]bool),
	}, err
}

func pickMostPublicIp() string {
	// TODO: prefer non 10.0.0.0, 172.16.0.0, and 192.168.0.0
	addrs, _ := net.InterfaceAddrs()
	var ip string
	for _, addr := range addrs {
		ip = strings.SplitN(addr.String(), "/", 2)[0]
		if !strings.Contains(ip, "::") && ip != "127.0.0.1" {
			return ip
		}
	}
	return ip
}

func (c *DiscoverClient) Services(name string) *ServiceSet {
	updates := make(chan *ServiceUpdate)
	c.client.StreamGo("DiscoverAgent.Subscribe", &Args{
		Name: name,
	}, updates)
	set := &ServiceSet{
		services:  make(map[string]*Service),
		filters:   make(map[string]string),
		listeners: make(map[chan *ServiceUpdate]struct{}),
	}
	set.Bind(updates)
	return set
}

func (c *DiscoverClient) Register(name, port string, attributes map[string]string) error {
	return c.RegisterWithHost(name, pickMostPublicIp(), port, attributes)
}

func (c *DiscoverClient) RegisterWithHost(name, host, port string, attributes map[string]string) error {
	args := &Args{
		Name:  name,
		Addr:  net.JoinHostPort(host, port),
		Attrs: attributes,
	}
	var ret struct{}
	err := c.client.Call("DiscoverAgent.Register", args, &ret)
	if err != nil {
		return errors.New("discover: register failed: " + err.Error())
	}
	c.hbMutex.Lock()
	c.heartbeats[args.Addr] = true
	c.hbMutex.Unlock()
	go func() {
		var heartbeated struct{}
		for c.heartbeats[args.Addr] {
			time.Sleep(HeartbeatIntervalSecs * time.Second) // TODO: add jitter
			c.client.Call("DiscoverAgent.Heartbeat", &Args{
				Name: name,
				Addr: args.Addr,
			}, &heartbeated)
		}
	}()
	return nil
}

func (c *DiscoverClient) Unregister(name, port string) error {
	return c.UnregisterWithHost(name, pickMostPublicIp(), port)
}

func (c *DiscoverClient) UnregisterWithHost(name, host, port string) error {
	args := &Args{
		Name: name,
		Addr: net.JoinHostPort(host, port),
	}
	var resp struct{}
	err := c.client.Call("DiscoverAgent.Unregister", args, &resp)
	if err != nil {
		return errors.New("discover: unregister failed: " + err.Error())
	}
	c.hbMutex.Lock()
	delete(c.heartbeats, args.Addr)
	c.hbMutex.Unlock()
	return nil
}
<|endoftext|>


<commit_before>package instance

import (
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"model"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	cfg_folder     = "cfg"
	server_ini     = "server_cfg.ini"
	entry_list_ini = "entry_list.ini"
	sep            = "\n"
)

func writeConfig(config *model.Configuration) error {
	iniPath := filepath.Join(cfg_folder, int64ToStr(config.Id))
	if err := os.MkdirAll(iniPath, 0755); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error creating cfg folder")
		return err
	}

	iniServerCfg, err := writeServerIni(config)
	if err != nil {
		return err
	}

	iniEntryList, err := writeEntryListIni(config)
	if err != nil {
		return err
	}

	return iniServerCfg, iniEntryList, nil
}

func writeServerIni(config *model.Configuration) error {
	ini := "[SERVER]" + sep
	ini += "NAME=" + config.Name + sep
	ini += "CARS=" + getCars(config) + sep
	ini += "CONFIG_TRACK=" + config.TrackConfig + sep
	ini += "TRACK=" + config.Track + sep
	ini += "SUN_ANGLE=" + intToStr(config.SunAngle) + sep
	ini += "PASSWORD=" + config.Pwd + sep
	ini += "ADMIN_PASSWORD=" + config.AdminPwd + sep
	ini += "UDP_PORT=" + intToStr(config.UDP) + sep
	ini += "TCP_PORT=" + intToStr(config.TCP) + sep
	ini += "HTTP_PORT=" + intToStr(config.HTTP) + sep
	ini += "MAX_BALLAST_KG=" + intToStr(config.MaxBallast) + sep
	ini += "QUALIFY_MAX_WAIT_PERC=120" + sep
	ini += "RACE_PIT_WINDOW_START=" + intToStr(config.RacePitWindowStart) + sep
	ini += "RACE_PIT_WINDOW_END=" + intToStr(config.RacePitWindowEnd) + sep
	ini += "REVERSED_GRID_RACE_POSITIONS=" + intToStr(config.ReversedGridRacePos) + sep
	ini += "LOCKED_ENTRY_LIST=" + boolToStr(config.LockEntryList) + sep
	ini += "PICKUP_MODE_ENABLED=" + boolToStr(config.PickupMode) + sep
	ini += "LOOP_MODE=" + boolToStr(config.LoopMode) + sep
	ini += "SLEEP_TIME=1" + sep
	ini += "CLIENT_SEND_INTERVAL_HZ=" + intToStr(config.PacketsHz) + sep
	ini += "SEND_BUFFER_SIZE=0" + sep
	ini += "RECV_BUFFER_SIZE=0" + sep
	ini += "RACE_OVER_TIME=" + intToStr(config.RaceOvertime) + sep
	ini += "KICK_QUORUM=" + intToStr(config.KickVoteQuorum) + sep
	ini += "VOTING_QUORUM=" + intToStr(config.SessionVoteQuorum) + sep
	ini += "VOTE_DURATION=" + intToStr(config.VoteDuration) + sep
	ini += "BLACKLIST_MODE=" + intToStr(config.Blacklist) + sep
	ini += "FUEL_RATE=" + intToStr(config.FuelRate) + sep
	ini += "DAMAGE_MULTIPLIER=" + intToStr(config.DamageRate) + sep
	ini += "TYRE_WEAR_RATE=" + intToStr(config.TiresWearRate) + sep
	ini += "ALLOWED_TYRES_OUT=" + intToStr(config.AllowedTiresOut) + sep
	ini += "ABS_ALLOWED=" + intToStr(config.ABS) + sep
	ini += "TC_ALLOWED=" + intToStr(config.TC) + sep
	ini += "START_RULE=1" + sep
	ini += "RACE_GAS_PENALTY_DISABLED=" + boolToStr(config.DisableGasCutPenality) + sep
	ini += "RESULT_SCREEN_TIME=" + intToStr(config.ResultScreenTime) + sep
	ini += "MAX_CONTACTS_PER_KM=" + intToStr(config.MaxCollisionsKm) + sep
	ini += "STABILITY_ALLOWED=" + boolToStr(config.StabilityAid) + sep
	ini += "AUTOCLUTCH_ALLOWED=" + boolToStr(config.AutoClutch) + sep
	ini += "TYRE_BLANKETS_ALLOWED=" + boolToStr(config.TyreBlankets) + sep
	ini += "FORCE_VIRTUAL_MIRROR=" + boolToStr(config.ForceVirtualMirror) + sep
	ini += "REGISTER_TO_LOBBY=" + boolToStr(config.ShowInLobby) + sep
	ini += "MAX_CLIENTS=" + intToStr(config.MaxSlots) + sep
	ini += "NUM_THREADS=" + intToStr(config.Threads) + sep
	ini += "UDP_PLUGIN_LOCAL_PORT=" + intToStr(config.UdpPluginPort) + sep
	ini += "UDP_PLUGIN_ADDRESS=" + config.UdpPluginAddr + sep
	ini += "AUTH_PLUGIN_ADDRESS=" + sep
	ini += "LEGAL_TYRES=" + config.LegalTyres + sep
	ini += "RACE_EXTRA_LAP=" + boolToStr(config.RaceExtraLap) + sep
	ini += "WELCOME_MESSAGE=" + config.Welcome + sep

	if config.Practice {
		ini += sep
		ini += "[PRACTICE]" + sep
		ini += "NAME=Practice" + sep
		ini += "TIME=" + intToStr(config.PracticeTime) + sep
		ini += "IS_OPEN=" + boolToStr(config.CanJoinPractice) + sep
	}

	if config.Qualify {
		ini += sep
		ini += "[QUALIFY]" + sep
		ini += "NAME=Qualify" + sep
		ini += "TIME=" + intToStr(config.QualifyTime) + sep
		ini += "IS_OPEN=" + boolToStr(config.CanJoinQualify) + sep
	}

	if config.Race {
		ini += sep
		ini += "[RACE]" + sep
		ini += "NAME=Race" + sep
		ini += "LAPS=" + intToStr(config.RaceLaps) + sep
		ini += "TIME=" + intToStr(config.RaceTime) + sep
		ini += "WAIT_TIME=" + intToStr(config.RaceWaitTime) + sep
		ini += "IS_OPEN=" + intToStr(config.JoinType) + sep
	}

	if config.DynamicTrack {
		ini += sep
		ini += "[DYNAMIC_TRACK]" + sep
		ini += "SESSION_START=" + intToStr(config.StartValue) + sep
		ini += "RANDOMNESS=" + intToStr(config.Randomness) + sep
		ini += "SESSION_TRANSFER=" + intToStr(config.TransferredGrip) + sep
		ini += "LAP_GAIN=" + intToStr(config.LapsToImproveGrip) + sep
	}

	// weather
	for i, w := range config.Weather {
		ini += sep
		ini += "[WEATHER_" + intToStr(i) + "]" + sep
		ini += "GRAPHICS=" + w.Weather + sep
		ini += "BASE_TEMPERATURE_AMBIENT=" + intToStr(w.BaseAmbientTemp) + sep
		ini += "BASE_TEMPERATURE_ROAD=" + intToStr(w.BaseRoadTemp) + sep
		ini += "VARIATION_AMBIENT=" + intToStr(w.AmbientVariation) + sep
		ini += "VARIATION_ROAD=" + intToStr(w.RoadVariation) + sep
		ini += "WIND_BASE_SPEED_MIN=" + intToStr(w.WindBaseSpeedMin) + sep
		ini += "WIND_BASE_SPEED_MAX=" + intToStr(w.WindBaseSpeedMax) + sep
		ini += "WIND_BASE_DIRECTION=" + intToStr(w.WindBaseDirection) + sep
		ini += "WIND_VARIATION_DIRECTION=" + intToStr(w.WindVariationDirection) + sep
	}

	ini += sep
	ini += "[DATA]" + sep
	ini += "DESCRIPTION=" + sep
	ini += "EXSERVEREXE=" + sep
	ini += "EXSERVERBAT=" + sep
	ini += "EXSERVERHIDEWIN=0" + sep
	ini += "WEBLINK=" + sep
	ini += "WELCOME_PATH=" + sep

	// write ini
	iniFile := filepath.Join(cfg_folder, int64ToStr(config.Id), server_ini)
	if err := ioutil.WriteFile(iniFile, []byte(ini), 0775); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error writing server_cfg.ini")
		return err
	}

	return iniFile, nil
}

func getCars(config *model.Configuration) string {
	cars := make([]string, 0)

	for _, car := range config.Cars {
		found := false

		for _, str := range cars {
			if str == car.Car {
				found = true
				break
			}
		}

		if !found {
			cars = append(cars, car.Car)
		}
	}

	return strings.Join(cars, ";")
}

func writeEntryListIni(config *model.Configuration) error {
	ini := ""

	for i, car := range config.Cars {
		ini += "[CAR_" + intToStr(i) + "]" + sep
		ini += "MODEL=" + car.Car + sep
		ini += "SKIN=" + car.Painting + sep
		ini += "SPECTATOR_MODE=" + boolToStr(car.Spectator) + sep
		ini += "DRIVERNAME=" + car.Driver + sep
		ini += "TEAM=" + car.Team + sep
		ini += "GUID=" + car.GUID + sep
		ini += "BALLAST=0" + sep
		ini += "FIXED_SETUP=" + car.FixedSetup + sep
		ini += sep
	}

	// write ini
	iniFile := filepath.Join(cfg_folder, int64ToStr(config.Id), entry_list_ini)
	if err := ioutil.WriteFile(iniFile, []byte(ini), 0775); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error writing entry_list.ini")
		return err
	}

	return iniFile, nil
}

func boolToStr(b bool) string {
	if b {
		return "1"
	}

	return "0"
}

func intToStr(i int) string {
	return strconv.Itoa(i)
}

func int64ToStr(i int64) string {
	return strconv.FormatInt(i, 10)
}
<commit_msg>Missing return types<commit_after>package instance

import (
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"model"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	cfg_folder     = "cfg"
	server_ini     = "server_cfg.ini"
	entry_list_ini = "entry_list.ini"
	sep            = "\n"
)

func writeConfig(config *model.Configuration) (string, string, error) {
	iniPath := filepath.Join(cfg_folder, int64ToStr(config.Id))
	if err := os.MkdirAll(iniPath, 0755); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error creating cfg folder")
		return err
	}

	iniServerCfg, err := writeServerIni(config)
	if err != nil {
		return iniServerCfg, nil, err
	}

	iniEntryList, err := writeEntryListIni(config)
	if err != nil {
		return iniServerCfg, iniEntryList, err
	}

	return iniServerCfg, iniEntryList, nil
}

func writeServerIni(config *model.Configuration) (string, error) {
	ini := "[SERVER]" + sep
	ini += "NAME=" + config.Name + sep
	ini += "CARS=" + getCars(config) + sep
	ini += "CONFIG_TRACK=" + config.TrackConfig + sep
	ini += "TRACK=" + config.Track + sep
	ini += "SUN_ANGLE=" + intToStr(config.SunAngle) + sep
	ini += "PASSWORD=" + config.Pwd + sep
	ini += "ADMIN_PASSWORD=" + config.AdminPwd + sep
	ini += "UDP_PORT=" + intToStr(config.UDP) + sep
	ini += "TCP_PORT=" + intToStr(config.TCP) + sep
	ini += "HTTP_PORT=" + intToStr(config.HTTP) + sep
	ini += "MAX_BALLAST_KG=" + intToStr(config.MaxBallast) + sep
	ini += "QUALIFY_MAX_WAIT_PERC=120" + sep
	ini += "RACE_PIT_WINDOW_START=" + intToStr(config.RacePitWindowStart) + sep
	ini += "RACE_PIT_WINDOW_END=" + intToStr(config.RacePitWindowEnd) + sep
	ini += "REVERSED_GRID_RACE_POSITIONS=" + intToStr(config.ReversedGridRacePos) + sep
	ini += "LOCKED_ENTRY_LIST=" + boolToStr(config.LockEntryList) + sep
	ini += "PICKUP_MODE_ENABLED=" + boolToStr(config.PickupMode) + sep
	ini += "LOOP_MODE=" + boolToStr(config.LoopMode) + sep
	ini += "SLEEP_TIME=1" + sep
	ini += "CLIENT_SEND_INTERVAL_HZ=" + intToStr(config.PacketsHz) + sep
	ini += "SEND_BUFFER_SIZE=0" + sep
	ini += "RECV_BUFFER_SIZE=0" + sep
	ini += "RACE_OVER_TIME=" + intToStr(config.RaceOvertime) + sep
	ini += "KICK_QUORUM=" + intToStr(config.KickVoteQuorum) + sep
	ini += "VOTING_QUORUM=" + intToStr(config.SessionVoteQuorum) + sep
	ini += "VOTE_DURATION=" + intToStr(config.VoteDuration) + sep
	ini += "BLACKLIST_MODE=" + intToStr(config.Blacklist) + sep
	ini += "FUEL_RATE=" + intToStr(config.FuelRate) + sep
	ini += "DAMAGE_MULTIPLIER=" + intToStr(config.DamageRate) + sep
	ini += "TYRE_WEAR_RATE=" + intToStr(config.TiresWearRate) + sep
	ini += "ALLOWED_TYRES_OUT=" + intToStr(config.AllowedTiresOut) + sep
	ini += "ABS_ALLOWED=" + intToStr(config.ABS) + sep
	ini += "TC_ALLOWED=" + intToStr(config.TC) + sep
	ini += "START_RULE=1" + sep
	ini += "RACE_GAS_PENALTY_DISABLED=" + boolToStr(config.DisableGasCutPenality) + sep
	ini += "RESULT_SCREEN_TIME=" + intToStr(config.ResultScreenTime) + sep
	ini += "MAX_CONTACTS_PER_KM=" + intToStr(config.MaxCollisionsKm) + sep
	ini += "STABILITY_ALLOWED=" + boolToStr(config.StabilityAid) + sep
	ini += "AUTOCLUTCH_ALLOWED=" + boolToStr(config.AutoClutch) + sep
	ini += "TYRE_BLANKETS_ALLOWED=" + boolToStr(config.TyreBlankets) + sep
	ini += "FORCE_VIRTUAL_MIRROR=" + boolToStr(config.ForceVirtualMirror) + sep
	ini += "REGISTER_TO_LOBBY=" + boolToStr(config.ShowInLobby) + sep
	ini += "MAX_CLIENTS=" + intToStr(config.MaxSlots) + sep
	ini += "NUM_THREADS=" + intToStr(config.Threads) + sep
	ini += "UDP_PLUGIN_LOCAL_PORT=" + intToStr(config.UdpPluginPort) + sep
	ini += "UDP_PLUGIN_ADDRESS=" + config.UdpPluginAddr + sep
	ini += "AUTH_PLUGIN_ADDRESS=" + sep
	ini += "LEGAL_TYRES=" + config.LegalTyres + sep
	ini += "RACE_EXTRA_LAP=" + boolToStr(config.RaceExtraLap) + sep
	ini += "WELCOME_MESSAGE=" + config.Welcome + sep

	if config.Practice {
		ini += sep
		ini += "[PRACTICE]" + sep
		ini += "NAME=Practice" + sep
		ini += "TIME=" + intToStr(config.PracticeTime) + sep
		ini += "IS_OPEN=" + boolToStr(config.CanJoinPractice) + sep
	}

	if config.Qualify {
		ini += sep
		ini += "[QUALIFY]" + sep
		ini += "NAME=Qualify" + sep
		ini += "TIME=" + intToStr(config.QualifyTime) + sep
		ini += "IS_OPEN=" + boolToStr(config.CanJoinQualify) + sep
	}

	if config.Race {
		ini += sep
		ini += "[RACE]" + sep
		ini += "NAME=Race" + sep
		ini += "LAPS=" + intToStr(config.RaceLaps) + sep
		ini += "TIME=" + intToStr(config.RaceTime) + sep
		ini += "WAIT_TIME=" + intToStr(config.RaceWaitTime) + sep
		ini += "IS_OPEN=" + intToStr(config.JoinType) + sep
	}

	if config.DynamicTrack {
		ini += sep
		ini += "[DYNAMIC_TRACK]" + sep
		ini += "SESSION_START=" + intToStr(config.StartValue) + sep
		ini += "RANDOMNESS=" + intToStr(config.Randomness) + sep
		ini += "SESSION_TRANSFER=" + intToStr(config.TransferredGrip) + sep
		ini += "LAP_GAIN=" + intToStr(config.LapsToImproveGrip) + sep
	}

	// weather
	for i, w := range config.Weather {
		ini += sep
		ini += "[WEATHER_" + intToStr(i) + "]" + sep
		ini += "GRAPHICS=" + w.Weather + sep
		ini += "BASE_TEMPERATURE_AMBIENT=" + intToStr(w.BaseAmbientTemp) + sep
		ini += "BASE_TEMPERATURE_ROAD=" + intToStr(w.BaseRoadTemp) + sep
		ini += "VARIATION_AMBIENT=" + intToStr(w.AmbientVariation) + sep
		ini += "VARIATION_ROAD=" + intToStr(w.RoadVariation) + sep
		ini += "WIND_BASE_SPEED_MIN=" + intToStr(w.WindBaseSpeedMin) + sep
		ini += "WIND_BASE_SPEED_MAX=" + intToStr(w.WindBaseSpeedMax) + sep
		ini += "WIND_BASE_DIRECTION=" + intToStr(w.WindBaseDirection) + sep
		ini += "WIND_VARIATION_DIRECTION=" + intToStr(w.WindVariationDirection) + sep
	}

	ini += sep
	ini += "[DATA]" + sep
	ini += "DESCRIPTION=" + sep
	ini += "EXSERVEREXE=" + sep
	ini += "EXSERVERBAT=" + sep
	ini += "EXSERVERHIDEWIN=0" + sep
	ini += "WEBLINK=" + sep
	ini += "WELCOME_PATH=" + sep

	// write ini
	iniFile := filepath.Join(cfg_folder, int64ToStr(config.Id), server_ini)
	if err := ioutil.WriteFile(iniFile, []byte(ini), 0775); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error writing server_cfg.ini")
		return iniFile, err
	}

	return iniFile, nil
}

func getCars(config *model.Configuration) string {
	cars := make([]string, 0)

	for _, car := range config.Cars {
		found := false

		for _, str := range cars {
			if str == car.Car {
				found = true
				break
			}
		}

		if !found {
			cars = append(cars, car.Car)
		}
	}

	return strings.Join(cars, ";")
}

func writeEntryListIni(config *model.Configuration) (string, error) {
	ini := ""

	for i, car := range config.Cars {
		ini += "[CAR_" + intToStr(i) + "]" + sep
		ini += "MODEL=" + car.Car + sep
		ini += "SKIN=" + car.Painting + sep
		ini += "SPECTATOR_MODE=" + boolToStr(car.Spectator) + sep
		ini += "DRIVERNAME=" + car.Driver + sep
		ini += "TEAM=" + car.Team + sep
		ini += "GUID=" + car.GUID + sep
		ini += "BALLAST=0" + sep
		ini += "FIXED_SETUP=" + car.FixedSetup + sep
		ini += sep
	}

	// write ini
	iniFile := filepath.Join(cfg_folder, int64ToStr(config.Id), entry_list_ini)
	if err := ioutil.WriteFile(iniFile, []byte(ini), 0775); err != nil {
		log.WithFields(log.Fields{"err": err}).Error("Error writing entry_list.ini")
		return iniFile, err
	}

	return iniFile, nil
}

func boolToStr(b bool) string {
	if b {
		return "1"
	}

	return "0"
}

func intToStr(i int) string {
	return strconv.Itoa(i)
}

func int64ToStr(i int64) string {
	return strconv.FormatInt(i, 10)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"github.com/getsentry/raven-go"
	"github.com/WhiteHatCP/seclab-listener/backend"
	"github.com/WhiteHatCP/seclab-listener/server"
)

const (
	maxPacketAge = 10
)

func openSock(path string) (net.Listener, error) {
	if err := syscall.Unlink(path); err != nil && err != syscall.EEXIST {
		return nil, err
	}
	ln, err := net.Listen("unix", path)
	if err != nil {
		return nil, err
	}
	if err := syscall.Chmod(path, 0770); err != nil {
		return nil, err
	}
	return ln, nil
}

func main() {
	if len(os.Args)%4 != 2 {
		fmt.Fprintf(os.Stderr, "usage: seclab key [dest open closed coffee fire [..]]\n")
		return
	}
	keypath := os.Args[1]
	s := server.New(keypath, maxPacketAge)

	for i := 2; i+2 < len(os.Args); i += 5 {
		dest := os.Args[i]
		openfile := os.Args[i+1]
		closedfile := os.Args[i+2]
		coffeefile := os.Args[i+3]
		firefile := os.Args[i+4]
		s.AddBackend(backend.New(dest, openfile, closedfile, coffeefile, firefile))
	}

	syscall.Umask(0007)

	socket := "seclab.sock"
	ln, err := openSock(socket)
	if err != nil {
		raven.CaptureErrorAndWait(err, nil)
		log.Fatal(err)
	}
	defer ln.Close()

	// Make sure the socket closes
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		for _ = range c {
			ln.Close()
		}
	}()

	s.Serve(ln)
}
<commit_msg>fire v5.1<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"github.com/getsentry/raven-go"
	"github.com/WhiteHatCP/seclab-listener/backend"
	"github.com/WhiteHatCP/seclab-listener/server"
)

const (
	maxPacketAge = 10
)

func openSock(path string) (net.Listener, error) {
	if err := syscall.Unlink(path); err != nil && err != syscall.EEXIST {
		return nil, err
	}
	ln, err := net.Listen("unix", path)
	if err != nil {
		return nil, err
	}
	if err := syscall.Chmod(path, 0770); err != nil {
		return nil, err
	}
	return ln, nil
}

func main() {
	if len(os.Args)%4 != 2 {
		fmt.Fprintf(os.Stderr, "usage: seclab key [dest open closed coffee fire [..]]\n")
		return
	}
	keypath := os.Args[1]
	s := server.New(keypath, maxPacketAge)

	for i := 2; i+2 < len(os.Args); i += 5 {
		dest := os.Args[i]
		openfile := os.Args[i+1]
		closedfile := os.Args[i+2]
		coffeefile := os.Args[i+3]
		firefile := os.Args[i+4]
		s.AddBackend(backend.New(dest, openfile, closedfile, coffeefile, firefile))
	}

	syscall.Umask(0007)

	socket := "seclab.sock"
	ln, err := openSock(socket)
	if err != nil {
		raven.CaptureErrorAndWait(err, nil)
		log.Fatal(err)
	}
	defer ln.Close()

	// Make sure the socket closes
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		for _ = range c {
			ln.Close()
		}
	}()

	s.Serve(ln)
}
<|endoftext|>


<commit_before>package memory

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"strings"
)

var filename string = "/proc/meminfo"

func (p *prober) probe() error {
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		if err := p.processMeminfoLine(scanner.Text()); err != nil {
			return err
		}
	}
	return scanner.Err()
}

func (p *prober) processMeminfoLine(line string) error {
	splitLine := strings.SplitN(line, ":", 2)
	if len(splitLine) != 2 {
		return nil
	}
	meminfoName := splitLine[0]
	meminfoDataString := strings.TrimSpace(splitLine[1])
	var ptr *uint64
	switch meminfoName {
	case "MemAvailable":
		ptr = &p.available
	case "MemFree":
		ptr = &p.free
	case "MemTotal":
		ptr = &p.total
	default:
		return nil
	}
	var meminfoData uint64
	var meminfoUnit string
	fmt.Sscanf(meminfoDataString, "%d %s", &meminfoData, &meminfoUnit)
	if meminfoUnit != "kB" {
		return errors.New(fmt.Sprintf("unknown unit: %s for: %s",
			meminfoUnit, meminfoName))
	}
	*ptr = meminfoData * 1024
	return nil
}
<commit_msg>Make use of github.com/Symantec/Dominator/lib/meminfo package.<commit_after>package memory

import (
	"github.com/Symantec/Dominator/lib/meminfo"
)

func (p *prober) probe() error {
	if info, err := meminfo.GetMemInfo(); err != nil {
		return err
	} else {
		p.available = info.Available
		p.free = info.Free
		p.total = info.Total
	}
	return nil
}
<|endoftext|>


<commit_before>package dev

import (
	"github.com/nanobox-io/nanobox/models"
)

// Reset all the counters for all dev applications
func Reset() error {
	return models.DeleteAllCounters()
}
<commit_msg>Add display logic to dev reset processor<commit_after>package dev

import (
	"fmt"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/util/display"
)

// Reset all the counters for all dev applications
func Reset() error {
	display.OpenContext("Resetting dev state")
	defer display.CloseContext()

	display.StartTask("Clear usage counters")
	if err := models.DeleteAllCounters(); err != nil {
		display.ErrorTask()
		return fmt.Errorf("failed to remove usage counters: %s", err.Error())
	}
	display.StopTask()

	return nil
}
<|endoftext|>