<commit_before>package ec2

import (
	"fmt"
	"io/ioutil"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/dynport/dgtk/cli"
	"github.com/dynport/gocli"
	"github.com/dynport/gocloud/aws/ec2"
)

const HOURS_PER_MONTH = 365 * 24.0 / 12.0

func Register(router *cli.Router) {
	router.Register("aws/ec2/instances/describe", &DescribeInstances{}, "Describe ec2 instances")
	router.Register("aws/ec2/instances/run", &RunInstances{}, "Run ec2 instances")
	router.Register("aws/ec2/images/create", &CreateImage{}, "Create image from instance")
	router.Register("aws/ec2/instances/terminate", &TerminateInstances{}, "Terminate ec2 instances")
	router.Register("aws/ec2/tags/create", &CreateTags{}, "Create Tags")
	router.RegisterFunc("aws/ec2/tags/describe", DescribeTags, "Describe Tags")
	router.Register("aws/ec2/images/describe", &DescribeImages{}, "Describe ec2 Images")
	router.RegisterFunc("aws/ec2/key-pairs/describe", DescribeKeyPairs, "Describe key pairs")
	router.RegisterFunc("aws/ec2/addresses/describe", DescribeAddresses, "Describe Addresses")
	router.RegisterFunc("aws/ec2/security-groups/describe", DescribeSecurityGroups, "Describe Security Groups")
	router.RegisterFunc("aws/ec2/spot-price-history/describe", DescribeSpotPriceHistory, "Describe Spot Price History")
	//router.Register("aws/ec2/prices", &Prices{Region: os.Getenv("AWS_DEFAULT_REGION")}, "EC2 Prices")
}

func client() *ec2.Client {
	return ec2.NewFromEnv()
}

// http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
var regionMapping = map[string]string{
	"eu-ireland": "eu-west-1",
	"eu-west":    "eu-west-1",
	"apac-tokyo": "ap-northeast-1",
	"apac-sin":   "ap-southeast-1",
	"apac-syd":   "ap-southeast-2",
}

// http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
var regionMappingForOd = map[string]string{
	"eu-west-1":      "eu-ireland",
	"us-east-1":      "us-east",
	"us-west-1":      "us-west",
	"ap-northeast-1": "apac-tokyo",
	"ap-southeast-1": "apac-sin",
	"ap-southeast-2": "apac-syd",
}

func normalizeRegionForOd(region string) string {
	normalized, ok := regionMappingForOd[region]
	if ok {
		return normalized
	}
	return region
}

func normalizeRegion(raw string) string {
	if v, ok := regionMapping[raw]; ok {
		return v
	}
	return raw
}
func monthlyPrice(price float64) string {
	return fmt.Sprintf("%.02f", price)
}

type DescribeImages struct {
	Canonical bool `cli:"type=opt long=canonical"`
	Self      bool `cli:"type=opt long=self"`
	Ubuntu    bool `cli:"type=opt long=ubuntu"`
	Raring    bool `cli:"type=opt long=raring"`
	Saucy     bool `cli:"type=opt long=saucy"`
}

func (a *DescribeImages) Run() error {
	log.Println("describing images")
	filter := &ec2.ImageFilter{}
	if a.Canonical {
		filter.Owner = ec2.CANONICAL_OWNER_ID
	} else if a.Self {
		filter.Owner = ec2.SELF_OWNER_ID
	}

	if a.Ubuntu {
		filter.Name = ec2.UBUNTU_PREFIX
	} else if a.Raring {
		filter.Name = ec2.UBUNTU_RARING_PREFIX
	} else if a.Saucy {
		filter.Name = ec2.UBUNTU_SAUCY_PREFIX
	}

	images, e := client().DescribeImagesWithFilter(filter)
	if e != nil {
		return e
	}
	sort.Sort(images)
	table := gocli.NewTable()
	for _, image := range images {
		table.Add(image.ImageId, image.Name, image.ImageState)
	}
	fmt.Println(table)
	return nil
}

func DescribeSpotPriceHistory() error {
	filter := &ec2.SpotPriceFilter{
		InstanceTypes:       []string{"c1.medium"},
		ProductDescriptions: []string{ec2.DESC_LINUX_UNIX},
		StartTime:           time.Now().Add(-7 * 24 * time.Hour),
	}
	prices, e := client().DescribeSpotPriceHistory(filter)
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, price := range prices {
		table.Add(price.InstanceType, price.ProductDescription, price.SpotPrice, price.Timestamp, price.AvailabilityZone)
	}
	fmt.Println(table)
	return nil
}

func DescribeSecurityGroups() error {
	groups, e := client().DescribeSecurityGroups()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, group := range groups {
		table.Add(group.GroupId, "", "", group.GroupName)
		for _, perm := range group.IpPermissions {
			ports := ""
			if perm.FromPort > 0 {
				if perm.FromPort == perm.ToPort {
					ports += fmt.Sprintf("%d", perm.FromPort)
				} else {
					ports += fmt.Sprintf("%d-%d", perm.FromPort, perm.ToPort)
				}
			}
			groups := []string{}
			for _, group := range perm.Groups {
				groups = append(groups, group.GroupId)
			}
			if len(groups) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(groups, ","))
			}

			if len(perm.IpRanges) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(perm.IpRanges, ","))
			}
		}
	}
	fmt.Print(table)
	return nil
}

func DescribeAddresses() error {
	addresses, e := client().DescribeAddresses()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, address := range addresses {
		table.Add(address.PublicIp, address.PrivateIpAddress, address.Domain, address.InstanceId)
	}
	fmt.Print(table)
	return nil
}

func DescribeKeyPairs() error {
	pairs, e := client().DescribeKeyPairs()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, pair := range pairs {
		table.Add(pair.KeyName, pair.KeyFingerprint)
	}
	fmt.Print(table)
	return nil
}

type CreateImage struct {
	ImageId string `cli:"type=arg required=true"`
}

func (a *CreateImage) Run() error {
	log.Printf("creating image of instance %s", a.ImageId)
	return fmt.Errorf("implement me")
}

type RunInstances struct {
	Name             string `cli:"type=opt long=name desc='Name of the Instanze'"`
	InstanceType     string `cli:"type=opt short=t desc='Instance Type' required=true"`
	ImageId          string `cli:"type=opt short=i desc='Image Id' required=true"`
	KeyName          string `cli:"type=opt short=k desc='SSH Key' required=true"`
	SecurityGroup    string `cli:"type=opt short=g desc='Security Group'"`
	SubnetId         string `cli:"type=opt long=subnet-id desc='Subnet Id'"`
	PublicIp         bool   `cli:"type=opt long=public-ip desc='Assign Public IP'"`
	AvailabilityZone string `cli:"type=opt long=availability-zone desc='Availability Zone'"`
	UserDataFile     string `cli:"type=opt long=userdata desc='Path to file with userdata'"`
}

func (a *RunInstances) Run() error {
	config := &ec2.RunInstancesConfig{
		ImageId:          a.ImageId,
		KeyName:          a.KeyName,
		InstanceType:     a.InstanceType,
		AvailabilityZone: a.AvailabilityZone,
		SubnetId:         a.SubnetId,
	}
	if a.UserDataFile != "" {
		b, e := ioutil.ReadFile(a.UserDataFile)
		if e != nil {
			return e
		}
		config.UserData = string(b)
	}
	if a.PublicIp {
		config.AddPublicIp()
	} else {
		if a.SecurityGroup != "" {
			config.SecurityGroups = []string{a.SecurityGroup}
		}
	}
	list, e := client().RunInstances(config)
	ids := []string{}
	for _, i := range list {
		ids = append(ids, i.InstanceId)
	}
	if a.Name != "" {
		log.Printf("tagging %v with %q", ids, a.Name)
		e := client().CreateTags(ids, map[string]string{"Name": a.Name})
		if e != nil {
			log.Printf("ERROR: " + e.Error())
		}
	}
	log.Printf("started instances %v", ids)
	return e
}

type TerminateInstances struct {
	InstanceIds []string `cli:"type=arg required=true"`
}

func (a *TerminateInstances) Run() error {
	_, e := client().TerminateInstances(a.InstanceIds)
	return e
}

type CreateTags struct {
	ResourceId string `cli:"type=arg required=true"`
	Key        string `cli:"type=arg required=true"`
	Value      string `cli:"type=arg required=true"`
}

func (r *CreateTags) Run() error {
	tags := map[string]string{
		r.Key: r.Value,
	}
	return client().CreateTags([]string{r.ResourceId}, tags)
}

func DescribeTags() error {
	tags, e := client().DescribeTags()
	if e != nil {
		return e
	}
	sort.Sort(tags)
	table := gocli.NewTable()
	for _, tag := range tags {
		table.Add(tag.ResourceType, tag.ResourceId, tag.Key, tag.Value)
	}
	fmt.Println(table)
	return nil
}

type DescribeInstances struct {
	Detailed bool `cli:"type=opt long=detailed"`
}

func (a *DescribeInstances) Run() error {
	log.Print("describing ec2 instances")
	instances, e := client().DescribeInstances()
	if e != nil {
		return e
	}
	if a.Detailed {
		for _, i := range instances {
			table := gocli.NewTable()
			table.Add(i.InstanceId, "Name", i.Name())
			table.Add(i.InstanceId, "ImageId", i.ImageId)
			table.Add(i.InstanceId, "InstanceType", i.InstanceType)
			table.Add(i.InstanceId, "InstanceStateName", i.InstanceStateName)
			table.Add(i.InstanceId, "Availability Zone", i.PlacementAvailabilityZone)
			table.Add(i.InstanceId, "KeyName", i.KeyName)
			table.Add(i.InstanceId, "IpAddress", i.IpAddress)
			table.Add(i.InstanceId, "PrivateIpAddress", i.PrivateIpAddress)
			table.Add(i.InstanceId, "LaunchTime", i.LaunchTime.Format("2006-01-02T15:04:05"))
			table.Add(i.InstanceId, "VpcId", i.VpcId)
			table.Add(i.InstanceId, "MonitoringState", i.MonitoringState)
			table.Add(i.InstanceId, "SubnetId", i.SubnetId)
			for _, group := range i.SecurityGroups {
				table.Add(i.InstanceId, "SecurityGroup", group.GroupId)
			}
			for _, tag := range i.Tags {
				table.Add(i.InstanceId, "Tag", tag.Key, tag.Value)
			}
			fmt.Println(table)
		}
		return nil
	}
	table := gocli.NewTable()
	table.Add("id", "image", "name", "state", "type", "private_ip", "ip", "az", "launched")
	for _, i := range instances {
		sgs := []string{}
		if i.InstanceStateName != "running" {
			continue
		}
		for _, g := range i.SecurityGroups {
			sgs = append(sgs, g.GroupId)
		}
		table.Add(
			i.InstanceId,
			i.ImageId,
			i.Name(),
			i.InstanceStateName,
			i.InstanceType,
			i.PrivateIpAddress,
			i.IpAddress,
			i.PlacementAvailabilityZone,
			i.LaunchTime.Format("2006-01-02T15:04"),
		)
	}
	fmt.Println(table)
	return nil
}
<commit_msg>adapt for api change<commit_after>package ec2

import (
	"fmt"
	"io/ioutil"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/dynport/dgtk/cli"
	"github.com/dynport/gocli"
	"github.com/dynport/gocloud/aws/ec2"
)

const HOURS_PER_MONTH = 365 * 24.0 / 12.0

func Register(router *cli.Router) {
	router.Register("aws/ec2/instances/describe", &DescribeInstances{}, "Describe ec2 instances")
	router.Register("aws/ec2/instances/run", &RunInstances{}, "Run ec2 instances")
	router.Register("aws/ec2/images/create", &CreateImage{}, "Create image from instance")
	router.Register("aws/ec2/instances/terminate", &TerminateInstances{}, "Terminate ec2 instances")
	router.Register("aws/ec2/tags/create", &CreateTags{}, "Create Tags")
	router.RegisterFunc("aws/ec2/tags/describe", DescribeTags, "Describe Tags")
	router.Register("aws/ec2/images/describe", &DescribeImages{}, "Describe ec2 Images")
	router.RegisterFunc("aws/ec2/key-pairs/describe", DescribeKeyPairs, "Describe key pairs")
	router.RegisterFunc("aws/ec2/addresses/describe", DescribeAddresses, "Describe Addresses")
	router.RegisterFunc("aws/ec2/security-groups/describe", DescribeSecurityGroups, "Describe Security Groups")
	router.RegisterFunc("aws/ec2/spot-price-history/describe", DescribeSpotPriceHistory, "Describe Spot Price History")
	//router.Register("aws/ec2/prices", &Prices{Region: os.Getenv("AWS_DEFAULT_REGION")}, "EC2 Prices")
}

func client() *ec2.Client {
	return ec2.NewFromEnv()
}

// http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
var regionMapping = map[string]string{
	"eu-ireland": "eu-west-1",
	"eu-west":    "eu-west-1",
	"apac-tokyo": "ap-northeast-1",
	"apac-sin":   "ap-southeast-1",
	"apac-syd":   "ap-southeast-2",
}

// http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
var regionMappingForOd = map[string]string{
	"eu-west-1":      "eu-ireland",
	"us-east-1":      "us-east",
	"us-west-1":      "us-west",
	"ap-northeast-1": "apac-tokyo",
	"ap-southeast-1": "apac-sin",
	"ap-southeast-2": "apac-syd",
}

func normalizeRegionForOd(region string) string {
	normalized, ok := regionMappingForOd[region]
	if ok {
		return normalized
	}
	return region
}

func normalizeRegion(raw string) string {
	if v, ok := regionMapping[raw]; ok {
		return v
	}
	return raw
}
func monthlyPrice(price float64) string {
	return fmt.Sprintf("%.02f", price)
}

type DescribeImages struct {
	Canonical bool `cli:"type=opt long=canonical"`
	Self      bool `cli:"type=opt long=self"`
	Ubuntu    bool `cli:"type=opt long=ubuntu"`
	Raring    bool `cli:"type=opt long=raring"`
	Saucy     bool `cli:"type=opt long=saucy"`
}

func (a *DescribeImages) Run() error {
	log.Println("describing images")
	filter := &ec2.ImageFilter{}
	if a.Canonical {
		filter.Owner = ec2.CANONICAL_OWNER_ID
	} else if a.Self {
		filter.Owner = ec2.SELF_OWNER_ID
	}

	if a.Ubuntu {
		filter.Name = ec2.UBUNTU_PREFIX
	} else if a.Raring {
		filter.Name = ec2.UBUNTU_RARING_PREFIX
	} else if a.Saucy {
		filter.Name = ec2.UBUNTU_SAUCY_PREFIX
	}

	images, e := client().DescribeImagesWithFilter(filter)
	if e != nil {
		return e
	}
	sort.Sort(images)
	table := gocli.NewTable()
	for _, image := range images {
		table.Add(image.ImageId, image.Name, image.ImageState)
	}
	fmt.Println(table)
	return nil
}

func DescribeSpotPriceHistory() error {
	filter := &ec2.SpotPriceFilter{
		InstanceTypes:       []string{"c1.medium"},
		ProductDescriptions: []string{ec2.DESC_LINUX_UNIX},
		StartTime:           time.Now().Add(-7 * 24 * time.Hour),
	}
	prices, e := client().DescribeSpotPriceHistory(filter)
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, price := range prices {
		table.Add(price.InstanceType, price.ProductDescription, price.SpotPrice, price.Timestamp, price.AvailabilityZone)
	}
	fmt.Println(table)
	return nil
}

func DescribeSecurityGroups() error {
	groups, e := client().DescribeSecurityGroups(nil)
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, group := range groups {
		table.Add(group.GroupId, "", "", group.GroupName)
		for _, perm := range group.IpPermissions {
			ports := ""
			if perm.FromPort > 0 {
				if perm.FromPort == perm.ToPort {
					ports += fmt.Sprintf("%d", perm.FromPort)
				} else {
					ports += fmt.Sprintf("%d-%d", perm.FromPort, perm.ToPort)
				}
			}
			groups := []string{}
			for _, group := range perm.Groups {
				groups = append(groups, group.GroupId)
			}
			if len(groups) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(groups, ","))
			}

			if len(perm.IpRanges) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(perm.IpRanges, ","))
			}
		}
	}
	fmt.Print(table)
	return nil
}

func DescribeAddresses() error {
	addresses, e := client().DescribeAddresses()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, address := range addresses {
		table.Add(address.PublicIp, address.PrivateIpAddress, address.Domain, address.InstanceId)
	}
	fmt.Print(table)
	return nil
}

func DescribeKeyPairs() error {
	pairs, e := client().DescribeKeyPairs()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, pair := range pairs {
		table.Add(pair.KeyName, pair.KeyFingerprint)
	}
	fmt.Print(table)
	return nil
}

type CreateImage struct {
	ImageId string `cli:"type=arg required=true"`
}

func (a *CreateImage) Run() error {
	log.Printf("creating image of instance %s", a.ImageId)
	return fmt.Errorf("implement me")
}

type RunInstances struct {
	Name             string `cli:"type=opt long=name desc='Name of the Instanze'"`
	InstanceType     string `cli:"type=opt short=t desc='Instance Type' required=true"`
	ImageId          string `cli:"type=opt short=i desc='Image Id' required=true"`
	KeyName          string `cli:"type=opt short=k desc='SSH Key' required=true"`
	SecurityGroup    string `cli:"type=opt short=g desc='Security Group'"`
	SubnetId         string `cli:"type=opt long=subnet-id desc='Subnet Id'"`
	PublicIp         bool   `cli:"type=opt long=public-ip desc='Assign Public IP'"`
	AvailabilityZone string `cli:"type=opt long=availability-zone desc='Availability Zone'"`
	UserDataFile     string `cli:"type=opt long=userdata desc='Path to file with userdata'"`
}

func (a *RunInstances) Run() error {
	config := &ec2.RunInstancesConfig{
		ImageId:          a.ImageId,
		KeyName:          a.KeyName,
		InstanceType:     a.InstanceType,
		AvailabilityZone: a.AvailabilityZone,
		SubnetId:         a.SubnetId,
	}
	if a.UserDataFile != "" {
		b, e := ioutil.ReadFile(a.UserDataFile)
		if e != nil {
			return e
		}
		config.UserData = string(b)
	}
	if a.PublicIp {
		config.AddPublicIp()
	} else {
		if a.SecurityGroup != "" {
			config.SecurityGroups = []string{a.SecurityGroup}
		}
	}
	list, e := client().RunInstances(config)
	ids := []string{}
	for _, i := range list {
		ids = append(ids, i.InstanceId)
	}
	if a.Name != "" {
		log.Printf("tagging %v with %q", ids, a.Name)
		e := client().CreateTags(ids, map[string]string{"Name": a.Name})
		if e != nil {
			log.Printf("ERROR: " + e.Error())
		}
	}
	log.Printf("started instances %v", ids)
	return e
}

type TerminateInstances struct {
	InstanceIds []string `cli:"type=arg required=true"`
}

func (a *TerminateInstances) Run() error {
	_, e := client().TerminateInstances(a.InstanceIds)
	return e
}

type CreateTags struct {
	ResourceId string `cli:"type=arg required=true"`
	Key        string `cli:"type=arg required=true"`
	Value      string `cli:"type=arg required=true"`
}

func (r *CreateTags) Run() error {
	tags := map[string]string{
		r.Key: r.Value,
	}
	return client().CreateTags([]string{r.ResourceId}, tags)
}

func DescribeTags() error {
	tags, e := client().DescribeTags()
	if e != nil {
		return e
	}
	sort.Sort(tags)
	table := gocli.NewTable()
	for _, tag := range tags {
		table.Add(tag.ResourceType, tag.ResourceId, tag.Key, tag.Value)
	}
	fmt.Println(table)
	return nil
}

type DescribeInstances struct {
	Detailed bool `cli:"type=opt long=detailed"`
}

func (a *DescribeInstances) Run() error {
	log.Print("describing ec2 instances")
	instances, e := client().DescribeInstances()
	if e != nil {
		return e
	}
	if a.Detailed {
		for _, i := range instances {
			table := gocli.NewTable()
			table.Add(i.InstanceId, "Name", i.Name())
			table.Add(i.InstanceId, "ImageId", i.ImageId)
			table.Add(i.InstanceId, "InstanceType", i.InstanceType)
			table.Add(i.InstanceId, "InstanceStateName", i.InstanceStateName)
			table.Add(i.InstanceId, "Availability Zone", i.PlacementAvailabilityZone)
			table.Add(i.InstanceId, "KeyName", i.KeyName)
			table.Add(i.InstanceId, "IpAddress", i.IpAddress)
			table.Add(i.InstanceId, "PrivateIpAddress", i.PrivateIpAddress)
			table.Add(i.InstanceId, "LaunchTime", i.LaunchTime.Format("2006-01-02T15:04:05"))
			table.Add(i.InstanceId, "VpcId", i.VpcId)
			table.Add(i.InstanceId, "MonitoringState", i.MonitoringState)
			table.Add(i.InstanceId, "SubnetId", i.SubnetId)
			for _, group := range i.SecurityGroups {
				table.Add(i.InstanceId, "SecurityGroup", group.GroupId)
			}
			for _, tag := range i.Tags {
				table.Add(i.InstanceId, "Tag", tag.Key, tag.Value)
			}
			fmt.Println(table)
		}
		return nil
	}
	table := gocli.NewTable()
	table.Add("id", "image", "name", "state", "type", "private_ip", "ip", "az", "launched")
	for _, i := range instances {
		sgs := []string{}
		if i.InstanceStateName != "running" {
			continue
		}
		for _, g := range i.SecurityGroups {
			sgs = append(sgs, g.GroupId)
		}
		table.Add(
			i.InstanceId,
			i.ImageId,
			i.Name(),
			i.InstanceStateName,
			i.InstanceType,
			i.PrivateIpAddress,
			i.IpAddress,
			i.PlacementAvailabilityZone,
			i.LaunchTime.Format("2006-01-02T15:04"),
		)
	}
	fmt.Println(table)
	return nil
}
<|endoftext|>


<commit_before>package cli

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/drewsonne/go-gocd/gocd"
	"github.com/urfave/cli"
	"io/ioutil"
	"strings"
)

// List of command name and descriptions
const (
	ListEnvironmentsCommandName                = "list-environments"
	ListEnvironmentsCommandUsage               = "List all environments"
	GetEnvironmentCommandName                  = "get-environment"
	GetEnvironmentCommandUsage                 = "Get an environment by name"
	PatchEnvironmentCommandName                = "patch-environment"
	PatchEnvironmentCommandUsage               = "Patch an environment by name"
	AddPipelinesToEnvironmentCommandName       = "add-pipelines-to-environment"
	AddPipelinesToEnvironmentCommandUsage      = "Add one or more pipelines to an environment"
	RemovePipelinesFromEnvironmentCommandName  = "remove-pipelines-from-environment"
	RemovePipelinesFromEnvironmentCommandUsage = "Remove one or more pipelines from an environment"
)

// ListEnvironmentsAction handles the listing of environments
func listEnvironmentsAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	es, resp, err := client.Environments.List(context.Background())
	if err == nil {
		es.RemoveLinks()
	}
	return es, resp, err
}

// GetEnvironmentAction handles the retrieval of environments
func getEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var name string
	if name = c.String("name"); name == "" {
		return nil, nil, NewFlagError("name")
	}
	e, resp, err := client.Environments.Get(context.Background(), name)
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err
}

// patchEnvironmentAction handles the patching of an environment
func patchEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var name string

	if name = c.String("name"); name == "" {
		return nil, nil, NewFlagError("name")
	}

	patch := c.String("patch")
	patchFile := c.String("patch-file")
	if patch == "" && patchFile == "" {
		return nil, nil, errors.New("One of '--patch-file' or '--patch' must be specified")
	}

	if patch != "" && patchFile != "" {
		return nil, nil, errors.New("Only one of '--patch-file' or '--patch' can be specified")
	}

	var pf []byte
	if patchFile != "" {
		pf, err = ioutil.ReadFile(patchFile)
		if err != nil {
			return nil, nil, err
		}
	} else {
		pf = []byte(patch)
	}
	p := &gocd.EnvironmentPatchRequest{}

	err = json.Unmarshal(pf, &p)
	if err != nil {
		return nil, nil, err
	}

	return client.Environments.Patch(context.Background(), name, p)
}

// AddPipelinesToEnvironmentAction handles the adding of a pipeline to an environment
func addPipelinesToEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var environment, pipelines string

	if environment = c.String("environment-name"); environment == "" {
		return nil, nil, NewFlagError("environment-name")
	}
	if pipelines = c.String("pipeline-names"); pipelines == "" {
		return nil, nil, NewFlagError("pipeline-names")
	}

	e, resp, err := client.Environments.Patch(context.Background(), environment, &gocd.EnvironmentPatchRequest{
		Pipelines: &gocd.PatchStringAction{
			Add: strings.Split(pipelines, ","),
		},
	})
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err

}

// RemovePipelinesFromEnvironmentAction handles the removing of a pipeline from an environment
func removePipelinesFromEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var environment, pipelines string

	if environment = c.String("environment-name"); environment == "" {
		return nil, nil, NewFlagError("environment-name")
	}
	if pipelines = c.String("pipeline-names"); pipelines == "" {
		return nil, nil, NewFlagError("pipeline-names")
	}

	e, resp, err := client.Environments.Patch(context.Background(), environment, &gocd.EnvironmentPatchRequest{
		Pipelines: &gocd.PatchStringAction{
			Remove: strings.Split(pipelines, ","),
		},
	})
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err
}

// ListEnvironmentsCommand handles definition of cli command
func listEnvironmentsCommand() *cli.Command {
	return &cli.Command{
		Name:     ListEnvironmentsCommandName,
		Usage:    ListEnvironmentsCommandUsage,
		Action:   ActionWrapper(listEnvironmentsAction),
		Category: "Environments",
	}
}

// GetEnvironmentCommand handles definition of cli command
func getEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     GetEnvironmentCommandName,
		Usage:    GetEnvironmentCommandUsage,
		Action:   ActionWrapper(getEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name"},
		},
	}
}

// GetEnvironmentCommand handles definition of cli command
func patchEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     PatchEnvironmentCommandName,
		Usage:    PatchEnvironmentCommandUsage,
		Action:   ActionWrapper(patchEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name"},
			cli.StringFlag{Name: "patch"},
			cli.StringFlag{Name: "patch-file"},
		},
	}
}

// AddPipelinesToEnvironmentCommand handles definition of cli command
func addPipelinesToEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     AddPipelinesToEnvironmentCommandName,
		Usage:    AddPipelinesToEnvironmentCommandUsage,
		Action:   ActionWrapper(addPipelinesToEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "environment-name"},
			cli.StringFlag{
				Name:  "pipeline-names",
				Usage: "Comma seperated list of pipeline names to add.",
			},
		},
	}
}

// RemovePipelinesFromEnvironmentCommand handles definition of cli command
func removePipelinesFromEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     RemovePipelinesFromEnvironmentCommandName,
		Usage:    RemovePipelinesFromEnvironmentCommandUsage,
		Action:   ActionWrapper(removePipelinesFromEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name: "environment-name",
			},
			cli.StringFlag{
				Name:  "pipeline-names",
				Usage: "Comma seperated list of pipeline names to remove.",
			},
		},
	}
}
<commit_msg>Switching to json and json-file for flags<commit_after>package cli

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/drewsonne/go-gocd/gocd"
	"github.com/urfave/cli"
	"io/ioutil"
	"strings"
)

// List of command name and descriptions
const (
	ListEnvironmentsCommandName                = "list-environments"
	ListEnvironmentsCommandUsage               = "List all environments"
	GetEnvironmentCommandName                  = "get-environment"
	GetEnvironmentCommandUsage                 = "Get an environment by name"
	PatchEnvironmentCommandName                = "patch-environment"
	PatchEnvironmentCommandUsage               = "Patch an environment by name"
	AddPipelinesToEnvironmentCommandName       = "add-pipelines-to-environment"
	AddPipelinesToEnvironmentCommandUsage      = "Add one or more pipelines to an environment"
	RemovePipelinesFromEnvironmentCommandName  = "remove-pipelines-from-environment"
	RemovePipelinesFromEnvironmentCommandUsage = "Remove one or more pipelines from an environment"
)

// ListEnvironmentsAction handles the listing of environments
func listEnvironmentsAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	es, resp, err := client.Environments.List(context.Background())
	if err == nil {
		es.RemoveLinks()
	}
	return es, resp, err
}

// GetEnvironmentAction handles the retrieval of environments
func getEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var name string
	if name = c.String("name"); name == "" {
		return nil, nil, NewFlagError("name")
	}
	e, resp, err := client.Environments.Get(context.Background(), name)
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err
}

// patchEnvironmentAction handles the patching of an environment
func patchEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var name string

	if name = c.String("name"); name == "" {
		return nil, nil, NewFlagError("name")
	}

	jsonString := c.String("json")
	jsonFile := c.String("json-file")
	if jsonString == "" && jsonFile == "" {
		return nil, nil, errors.New("One of '--json-file' or '--json' must be specified")
	}

	if jsonString != "" && jsonFile != "" {
		return nil, nil, errors.New("Only one of '--json-file' or '--json' can be specified")
	}

	var pf []byte
	if jsonFile != "" {
		pf, err = ioutil.ReadFile(jsonFile)
		if err != nil {
			return nil, nil, err
		}
	} else {
		pf = []byte(jsonString)
	}
	p := &gocd.EnvironmentPatchRequest{}

	err = json.Unmarshal(pf, &p)
	if err != nil {
		return nil, nil, err
	}

	return client.Environments.Patch(context.Background(), name, p)
}

// AddPipelinesToEnvironmentAction handles the adding of a pipeline to an environment
func addPipelinesToEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var environment, pipelines string

	if environment = c.String("environment-name"); environment == "" {
		return nil, nil, NewFlagError("environment-name")
	}
	if pipelines = c.String("pipeline-names"); pipelines == "" {
		return nil, nil, NewFlagError("pipeline-names")
	}

	e, resp, err := client.Environments.Patch(context.Background(), environment, &gocd.EnvironmentPatchRequest{
		Pipelines: &gocd.PatchStringAction{
			Add: strings.Split(pipelines, ","),
		},
	})
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err

}

// RemovePipelinesFromEnvironmentAction handles the removing of a pipeline from an environment
func removePipelinesFromEnvironmentAction(client *gocd.Client, c *cli.Context) (r interface{}, resp *gocd.APIResponse, err error) {
	var environment, pipelines string

	if environment = c.String("environment-name"); environment == "" {
		return nil, nil, NewFlagError("environment-name")
	}
	if pipelines = c.String("pipeline-names"); pipelines == "" {
		return nil, nil, NewFlagError("pipeline-names")
	}

	e, resp, err := client.Environments.Patch(context.Background(), environment, &gocd.EnvironmentPatchRequest{
		Pipelines: &gocd.PatchStringAction{
			Remove: strings.Split(pipelines, ","),
		},
	})
	if err == nil {
		e.RemoveLinks()
	}
	return e, resp, err
}

// ListEnvironmentsCommand handles definition of cli command
func listEnvironmentsCommand() *cli.Command {
	return &cli.Command{
		Name:     ListEnvironmentsCommandName,
		Usage:    ListEnvironmentsCommandUsage,
		Action:   ActionWrapper(listEnvironmentsAction),
		Category: "Environments",
	}
}

// GetEnvironmentCommand handles definition of cli command
func getEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     GetEnvironmentCommandName,
		Usage:    GetEnvironmentCommandUsage,
		Action:   ActionWrapper(getEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name"},
		},
	}
}

// GetEnvironmentCommand handles definition of cli command
func patchEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     PatchEnvironmentCommandName,
		Usage:    PatchEnvironmentCommandUsage,
		Action:   ActionWrapper(patchEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name"},
			cli.StringFlag{Name: "json"},
			cli.StringFlag{Name: "json-file"},
		},
	}
}

// AddPipelinesToEnvironmentCommand handles definition of cli command
func addPipelinesToEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     AddPipelinesToEnvironmentCommandName,
		Usage:    AddPipelinesToEnvironmentCommandUsage,
		Action:   ActionWrapper(addPipelinesToEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "environment-name"},
			cli.StringFlag{
				Name:  "pipeline-names",
				Usage: "Comma seperated list of pipeline names to add.",
			},
		},
	}
}

// RemovePipelinesFromEnvironmentCommand handles definition of cli command
func removePipelinesFromEnvironmentCommand() *cli.Command {
	return &cli.Command{
		Name:     RemovePipelinesFromEnvironmentCommandName,
		Usage:    RemovePipelinesFromEnvironmentCommandUsage,
		Action:   ActionWrapper(removePipelinesFromEnvironmentAction),
		Category: "Environments",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name: "environment-name",
			},
			cli.StringFlag{
				Name:  "pipeline-names",
				Usage: "Comma seperated list of pipeline names to remove.",
			},
		},
	}
}
<|endoftext|>


<commit_before>package webrtc

import (
	"fmt"
	"strings"

	"net"

	"github.com/pions/webrtc/internal/sdp"
	"github.com/pkg/errors"
)

// RTCAnswerOptions describes the options used to control the answer creation process
type RTCAnswerOptions struct {
	VoiceActivityDetection bool
}

// RTCOfferOptions describes the options used to control the offer creation process
type RTCOfferOptions struct {
	VoiceActivityDetection bool
	ICERestart             bool
}

// RTCSignalingState indicates the state of the offer/answer process
type RTCSignalingState int

const (
	// RTCSignalingStateStable indicates there is no offeranswer exchange in progress.
	RTCSignalingStateStable RTCSignalingState = iota + 1

	// RTCSignalingStateHaveLocalOffer indicates A local description, of type "offer", has been successfully applied.
	RTCSignalingStateHaveLocalOffer

	// RTCSignalingStateHaveRemoteOffer indicates A remote description, of type "offer", has been successfully applied.
	RTCSignalingStateHaveRemoteOffer

	// RTCSignalingStateHaveLocalPranswer indicates A remote description of type "offer" has been successfully applied and a local description of type "pranswer" has been successfully applied.
	RTCSignalingStateHaveLocalPranswer

	// RTCSignalingStateHaveRemotePranswer indicates A local description of type "offer" has been successfully applied and a remote description of type "pranswer" has been successfully applied.
	RTCSignalingStateHaveRemotePranswer

	// RTCSignalingStateClosed indicates The RTCPeerConnection has been closed.
	RTCSignalingStateClosed
)

func (t RTCSignalingState) String() string {
	switch t {
	case RTCSignalingStateStable:
		return "stable"
	case RTCSignalingStateHaveLocalOffer:
		return "have-local-offer"
	case RTCSignalingStateHaveRemoteOffer:
		return "have-remote-offer"
	case RTCSignalingStateHaveLocalPranswer:
		return "have-local-pranswer"
	case RTCSignalingStateHaveRemotePranswer:
		return "have-remote-pranswer"
	case RTCSignalingStateClosed:
		return "closed"
	default:
		return "Unknown"
	}
}

// RTCSdpType describes the type of an RTCSessionDescription
type RTCSdpType int

const (
	// RTCSdpTypeOffer indicates that a description MUST be treated as an SDP offer.
	RTCSdpTypeOffer RTCSdpType = iota + 1

	// RTCSdpTypePranswer indicates that a description MUST be treated as an SDP answer, but not a final answer.
	RTCSdpTypePranswer

	// RTCSdpTypeAnswer indicates that a description MUST be treated as an SDP final answer, and the offer-answer exchange MUST be considered complete.
	RTCSdpTypeAnswer

	// RTCSdpTypeRollback indicates that a description MUST be treated as canceling the current SDP negotiation and moving the SDP offer and answer back to what it was in the previous stable state.
	RTCSdpTypeRollback
)

func (t RTCSdpType) String() string {
	switch t {
	case RTCSdpTypeOffer:
		return "offer"
	case RTCSdpTypePranswer:
		return "pranswer"
	case RTCSdpTypeAnswer:
		return "answer"
	case RTCSdpTypeRollback:
		return "rollback"
	default:
		return "Unknown"
	}
}

// RTCSessionDescription is used to expose local and remote session descriptions.
type RTCSessionDescription struct {
	Type RTCSdpType
	Sdp  string

	// This will never be initialized by callers, internal use only
	parsed *sdp.SessionDescription
}

// SetRemoteDescription sets the SessionDescription of the remote peer
func (r *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) error {
	if r.CurrentRemoteDescription != nil {
		return errors.Errorf("remoteDescription is already defined, SetRemoteDescription can only be called once")
	}

	weOffer := true
	remoteUfrag := ""
	remotePwd := ""
	if desc.Type == RTCSdpTypeOffer {
		weOffer = false
	}

	r.CurrentRemoteDescription = &desc
	r.CurrentRemoteDescription.parsed = &sdp.SessionDescription{}
	if err := r.CurrentRemoteDescription.parsed.Unmarshal(r.CurrentRemoteDescription.Sdp); err != nil {
		return err
	}

	for _, m := range r.CurrentRemoteDescription.parsed.MediaDescriptions {
		for _, a := range m.Attributes {
			if strings.HasPrefix(*a.String(), "candidate") {
				if c := sdp.ICECandidateUnmarshal(*a.String()); c != nil {
					r.networkManager.IceAgent.AddRemoteCandidate(c)
				} else {
					fmt.Printf("Tried to parse ICE candidate, but failed %s ", a)
				}
			} else if strings.HasPrefix(*a.String(), "ice-ufrag") {
				remoteUfrag = (*a.String())[len("ice-ufrag:"):]
			} else if strings.HasPrefix(*a.String(), "ice-pwd") {
				remotePwd = (*a.String())[len("ice-pwd:"):]
			}
		}
	}
	return r.networkManager.Start(weOffer, remoteUfrag, remotePwd)
}

func (r *RTCPeerConnection) generateLocalCandidates() []string {
	r.networkManager.IceAgent.RLock()
	defer r.networkManager.IceAgent.RUnlock()

	candidates := make([]string, 0)
	for _, c := range r.networkManager.IceAgent.LocalCandidates {
		candidates = append(candidates, sdp.ICECandidateMarshal(c)...)
	}
	return candidates
}

// CreateOffer starts the RTCPeerConnection and generates the localDescription
func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDescription, error) {
	useIdentity := r.idpLoginURL != nil
	if options != nil {
		return RTCSessionDescription{}, errors.Errorf("TODO handle options")
	} else if useIdentity {
		return RTCSessionDescription{}, errors.Errorf("TODO handle identity provider")
	} else if r.IsClosed {
		return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed}
	}

	d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)
	candidates := r.generateLocalCandidates()

	r.addRTPMediaSection(d, RTCRtpCodecTypeAudio, "audio", candidates)
	r.addRTPMediaSection(d, RTCRtpCodecTypeVideo, "video", candidates)
	r.addDataMediaSection(d, "data", candidates)
	d = d.WithValueAttribute(sdp.AttrKeyGroup, "BUNDLE audio video data")

	for _, m := range d.MediaDescriptions {
		m.WithPropertyAttribute("setup:actpass")
	}

	r.CurrentLocalDescription = &RTCSessionDescription{
		Type:   RTCSdpTypeOffer,
		Sdp:    d.Marshal(),
		parsed: d,
	}

	return *r.CurrentLocalDescription, nil
}

// CreateAnswer starts the RTCPeerConnection and generates the localDescription
func (r *RTCPeerConnection) CreateAnswer(options *RTCAnswerOptions) (RTCSessionDescription, error) {
	useIdentity := r.idpLoginURL != nil
	if options != nil {
		return RTCSessionDescription{}, errors.Errorf("TODO handle options")
	} else if useIdentity {
		return RTCSessionDescription{}, errors.Errorf("TODO handle identity provider")
	} else if r.IsClosed {
		return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed}
	}

	candidates := r.generateLocalCandidates()
	d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)

	bundleValue := "BUNDLE"
	for _, remoteMedia := range r.CurrentRemoteDescription.parsed.MediaDescriptions {
		// TODO @trivigy better SDP parser
		midValue := ""
		for _, a := range remoteMedia.Attributes {
			if strings.HasPrefix(*a.String(), "mid") {
				midValue = (*a.String())[len("mid:"):]
			}
		}
		bundleValue += " " + midValue

		if strings.HasPrefix(*remoteMedia.MediaName.String(), "audio") {
			r.addRTPMediaSection(d, RTCRtpCodecTypeAudio, midValue, candidates)
		} else if strings.HasPrefix(*remoteMedia.MediaName.String(), "video") {
			r.addRTPMediaSection(d, RTCRtpCodecTypeVideo, midValue, candidates)
		} else if strings.HasPrefix(*remoteMedia.MediaName.String(), "application") {
			r.addDataMediaSection(d, midValue, candidates)
		}
	}

	d = d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue)

	r.CurrentLocalDescription = &RTCSessionDescription{
		Type:   RTCSdpTypeAnswer,
		Sdp:    d.Marshal(),
		parsed: d,
	}
	return *r.CurrentLocalDescription, nil
}

func (r *RTCPeerConnection) addRTPMediaSection(d *sdp.SessionDescription, codecType RTCRtpCodecType, midValue string, candidates []string) {
	media := sdp.NewJSEPMediaDescription(codecType.String(), []string{}).
		WithValueAttribute(sdp.AttrKeyConnectionSetup, sdp.ConnectionRoleActive.String()). // TODO: Support other connection types
		WithValueAttribute(sdp.AttrKeyMID, midValue).
		WithPropertyAttribute(RTCRtpTransceiverDirectionSendrecv.String()).
		WithICECredentials(r.networkManager.IceAgent.LocalUfrag, r.networkManager.IceAgent.LocalPwd).
		WithPropertyAttribute(sdp.AttrKeyRtcpMux).  // TODO: support RTCP fallback
		WithPropertyAttribute(sdp.AttrKeyRtcpRsize) // TODO: Support Reduced-Size RTCP?

	for _, codec := range r.mediaEngine.getCodecsByKind(codecType) {
		media.WithCodec(codec.PayloadType, codec.Name, codec.ClockRate, codec.Channels, codec.SdpFmtpLine)
	}

	for _, transceiver := range r.rtpTransceivers {
		if transceiver.Sender == nil ||
			transceiver.Sender.Track == nil ||
			transceiver.Sender.Track.Kind != codecType {
			continue
		}
		track := transceiver.Sender.Track
		media = media.WithMediaSource(track.Ssrc, track.Label /* cname */, track.Label /* streamLabel */, track.Label)
	}

	for _, c := range candidates {
		media.WithCandidate(c)
	}
	media.WithPropertyAttribute("end-of-candidates")
	d.WithMedia(media)
}

func (r *RTCPeerConnection) addDataMediaSection(d *sdp.SessionDescription, midValue string, candidates []string) {
	media := (&sdp.MediaDescription{
		MediaName: sdp.MediaName{
			Media:   "application",
			Port:    sdp.RangedPort{Value: 9},
			Protos:  []string{"DTLS", "SCTP"},
			Formats: []int{5000},
		},
		ConnectionInformation: &sdp.ConnectionInformation{
			NetworkType: "IN",
			AddressType: "IP4",
			Address: &sdp.Address{
				IP: net.ParseIP("0.0.0.0"),
			},
		},
	}).
		WithValueAttribute(sdp.AttrKeyConnectionSetup, sdp.ConnectionRoleActive.String()). // TODO: Support other connection types
		WithValueAttribute(sdp.AttrKeyMID, midValue).
		WithValueAttribute("sctpmap:5000", "webrtc-datachannel 1024").
		WithICECredentials(r.networkManager.IceAgent.LocalUfrag, r.networkManager.IceAgent.LocalPwd)

	for _, c := range candidates {
		media.WithCandidate(c)
	}
	media.WithPropertyAttribute("end-of-candidates")

	d.WithMedia(media)
}
<commit_msg>Finish FireFox support<commit_after>package webrtc

import (
	"fmt"
	"strings"

	"net"

	"github.com/pions/webrtc/internal/sdp"
	"github.com/pkg/errors"
)

// RTCAnswerOptions describes the options used to control the answer creation process
type RTCAnswerOptions struct {
	VoiceActivityDetection bool
}

// RTCOfferOptions describes the options used to control the offer creation process
type RTCOfferOptions struct {
	VoiceActivityDetection bool
	ICERestart             bool
}

// RTCSignalingState indicates the state of the offer/answer process
type RTCSignalingState int

const (
	// RTCSignalingStateStable indicates there is no offeranswer exchange in progress.
	RTCSignalingStateStable RTCSignalingState = iota + 1

	// RTCSignalingStateHaveLocalOffer indicates A local description, of type "offer", has been successfully applied.
	RTCSignalingStateHaveLocalOffer

	// RTCSignalingStateHaveRemoteOffer indicates A remote description, of type "offer", has been successfully applied.
	RTCSignalingStateHaveRemoteOffer

	// RTCSignalingStateHaveLocalPranswer indicates A remote description of type "offer" has been successfully applied and a local description of type "pranswer" has been successfully applied.
	RTCSignalingStateHaveLocalPranswer

	// RTCSignalingStateHaveRemotePranswer indicates A local description of type "offer" has been successfully applied and a remote description of type "pranswer" has been successfully applied.
	RTCSignalingStateHaveRemotePranswer

	// RTCSignalingStateClosed indicates The RTCPeerConnection has been closed.
	RTCSignalingStateClosed
)

func (t RTCSignalingState) String() string {
	switch t {
	case RTCSignalingStateStable:
		return "stable"
	case RTCSignalingStateHaveLocalOffer:
		return "have-local-offer"
	case RTCSignalingStateHaveRemoteOffer:
		return "have-remote-offer"
	case RTCSignalingStateHaveLocalPranswer:
		return "have-local-pranswer"
	case RTCSignalingStateHaveRemotePranswer:
		return "have-remote-pranswer"
	case RTCSignalingStateClosed:
		return "closed"
	default:
		return "Unknown"
	}
}

// RTCSdpType describes the type of an RTCSessionDescription
type RTCSdpType int

const (
	// RTCSdpTypeOffer indicates that a description MUST be treated as an SDP offer.
	RTCSdpTypeOffer RTCSdpType = iota + 1

	// RTCSdpTypePranswer indicates that a description MUST be treated as an SDP answer, but not a final answer.
	RTCSdpTypePranswer

	// RTCSdpTypeAnswer indicates that a description MUST be treated as an SDP final answer, and the offer-answer exchange MUST be considered complete.
	RTCSdpTypeAnswer

	// RTCSdpTypeRollback indicates that a description MUST be treated as canceling the current SDP negotiation and moving the SDP offer and answer back to what it was in the previous stable state.
	RTCSdpTypeRollback
)

func (t RTCSdpType) String() string {
	switch t {
	case RTCSdpTypeOffer:
		return "offer"
	case RTCSdpTypePranswer:
		return "pranswer"
	case RTCSdpTypeAnswer:
		return "answer"
	case RTCSdpTypeRollback:
		return "rollback"
	default:
		return "Unknown"
	}
}

// RTCSessionDescription is used to expose local and remote session descriptions.
type RTCSessionDescription struct {
	Type RTCSdpType
	Sdp  string

	// This will never be initialized by callers, internal use only
	parsed *sdp.SessionDescription
}

// SetRemoteDescription sets the SessionDescription of the remote peer
func (r *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) error {
	if r.CurrentRemoteDescription != nil {
		return errors.Errorf("remoteDescription is already defined, SetRemoteDescription can only be called once")
	}

	weOffer := true
	remoteUfrag := ""
	remotePwd := ""
	if desc.Type == RTCSdpTypeOffer {
		weOffer = false
	}

	r.CurrentRemoteDescription = &desc
	r.CurrentRemoteDescription.parsed = &sdp.SessionDescription{}
	if err := r.CurrentRemoteDescription.parsed.Unmarshal(r.CurrentRemoteDescription.Sdp); err != nil {
		return err
	}

	for _, m := range r.CurrentRemoteDescription.parsed.MediaDescriptions {
		for _, a := range m.Attributes {
			if strings.HasPrefix(*a.String(), "candidate") {
				if c := sdp.ICECandidateUnmarshal(*a.String()); c != nil {
					r.networkManager.IceAgent.AddRemoteCandidate(c)
				} else {
					fmt.Printf("Tried to parse ICE candidate, but failed %s ", a)
				}
			} else if strings.HasPrefix(*a.String(), "ice-ufrag") {
				remoteUfrag = (*a.String())[len("ice-ufrag:"):]
			} else if strings.HasPrefix(*a.String(), "ice-pwd") {
				remotePwd = (*a.String())[len("ice-pwd:"):]
			}
		}
	}
	return r.networkManager.Start(weOffer, remoteUfrag, remotePwd)
}

func (r *RTCPeerConnection) generateLocalCandidates() []string {
	r.networkManager.IceAgent.RLock()
	defer r.networkManager.IceAgent.RUnlock()

	candidates := make([]string, 0)
	for _, c := range r.networkManager.IceAgent.LocalCandidates {
		candidates = append(candidates, sdp.ICECandidateMarshal(c)...)
	}
	return candidates
}

// CreateOffer starts the RTCPeerConnection and generates the localDescription
func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDescription, error) {
	useIdentity := r.idpLoginURL != nil
	if options != nil {
		return RTCSessionDescription{}, errors.Errorf("TODO handle options")
	} else if useIdentity {
		return RTCSessionDescription{}, errors.Errorf("TODO handle identity provider")
	} else if r.IsClosed {
		return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed}
	}

	d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)
	candidates := r.generateLocalCandidates()

	r.addRTPMediaSection(d, RTCRtpCodecTypeAudio, "audio", RTCRtpTransceiverDirectionSendrecv, candidates)
	r.addRTPMediaSection(d, RTCRtpCodecTypeVideo, "video", RTCRtpTransceiverDirectionSendrecv, candidates)
	r.addDataMediaSection(d, "data", candidates)
	d = d.WithValueAttribute(sdp.AttrKeyGroup, "BUNDLE audio video data")

	for _, m := range d.MediaDescriptions {
		m.WithPropertyAttribute("setup:actpass")
	}

	r.CurrentLocalDescription = &RTCSessionDescription{
		Type:   RTCSdpTypeOffer,
		Sdp:    d.Marshal(),
		parsed: d,
	}

	return *r.CurrentLocalDescription, nil
}

// CreateAnswer starts the RTCPeerConnection and generates the localDescription
func (r *RTCPeerConnection) CreateAnswer(options *RTCAnswerOptions) (RTCSessionDescription, error) {
	useIdentity := r.idpLoginURL != nil
	if options != nil {
		return RTCSessionDescription{}, errors.Errorf("TODO handle options")
	} else if useIdentity {
		return RTCSessionDescription{}, errors.Errorf("TODO handle identity provider")
	} else if r.IsClosed {
		return RTCSessionDescription{}, &InvalidStateError{Err: ErrConnectionClosed}
	}

	candidates := r.generateLocalCandidates()
	d := sdp.NewJSEPSessionDescription(r.networkManager.DTLSFingerprint(), useIdentity)

	bundleValue := "BUNDLE"
	for _, remoteMedia := range r.CurrentRemoteDescription.parsed.MediaDescriptions {
		// TODO @trivigy better SDP parser
		var peerDirection RTCRtpTransceiverDirection
		midValue := ""

		for _, a := range remoteMedia.Attributes {
			if strings.HasPrefix(*a.String(), "mid") {
				midValue = (*a.String())[len("mid:"):]
			} else if strings.HasPrefix(*a.String(), "sendrecv") {
				peerDirection = RTCRtpTransceiverDirectionSendrecv
			} else if strings.HasPrefix(*a.String(), "sendonly") {
				peerDirection = RTCRtpTransceiverDirectionSendonly
			} else if strings.HasPrefix(*a.String(), "recvonly") {
				peerDirection = RTCRtpTransceiverDirectionRecvonly
			}
		}
		bundleValue += " " + midValue

		if strings.HasPrefix(*remoteMedia.MediaName.String(), "audio") {
			r.addRTPMediaSection(d, RTCRtpCodecTypeAudio, midValue, peerDirection, candidates)
		} else if strings.HasPrefix(*remoteMedia.MediaName.String(), "video") {
			r.addRTPMediaSection(d, RTCRtpCodecTypeVideo, midValue, peerDirection, candidates)
		} else if strings.HasPrefix(*remoteMedia.MediaName.String(), "application") {
			r.addDataMediaSection(d, midValue, candidates)
		}
	}

	d = d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue)

	r.CurrentLocalDescription = &RTCSessionDescription{
		Type:   RTCSdpTypeAnswer,
		Sdp:    d.Marshal(),
		parsed: d,
	}
	return *r.CurrentLocalDescription, nil
}

func localDirection(weSend bool, peerDirection RTCRtpTransceiverDirection) RTCRtpTransceiverDirection {
	theySend := (peerDirection == RTCRtpTransceiverDirectionSendrecv || peerDirection == RTCRtpTransceiverDirectionSendonly)
	if weSend && theySend {
		return RTCRtpTransceiverDirectionSendrecv
	} else if weSend && !theySend {
		return RTCRtpTransceiverDirectionSendonly
	} else if !weSend && theySend {
		return RTCRtpTransceiverDirectionRecvonly
	}

	return RTCRtpTransceiverDirectionInactive
}

func (r *RTCPeerConnection) addRTPMediaSection(d *sdp.SessionDescription, codecType RTCRtpCodecType, midValue string, peerDirection RTCRtpTransceiverDirection, candidates []string) {

	media := sdp.NewJSEPMediaDescription(codecType.String(), []string{}).
		WithValueAttribute(sdp.AttrKeyConnectionSetup, sdp.ConnectionRoleActive.String()). // TODO: Support other connection types
		WithValueAttribute(sdp.AttrKeyMID, midValue).
		WithICECredentials(r.networkManager.IceAgent.LocalUfrag, r.networkManager.IceAgent.LocalPwd).
		WithPropertyAttribute(sdp.AttrKeyRtcpMux).  // TODO: support RTCP fallback
		WithPropertyAttribute(sdp.AttrKeyRtcpRsize) // TODO: Support Reduced-Size RTCP?

	for _, codec := range r.mediaEngine.getCodecsByKind(codecType) {
		media.WithCodec(codec.PayloadType, codec.Name, codec.ClockRate, codec.Channels, codec.SdpFmtpLine)
	}

	weSend := false
	for _, transceiver := range r.rtpTransceivers {
		if transceiver.Sender == nil ||
			transceiver.Sender.Track == nil ||
			transceiver.Sender.Track.Kind != codecType {
			continue
		}
		weSend = true
		track := transceiver.Sender.Track
		media = media.WithMediaSource(track.Ssrc, track.Label /* cname */, track.Label /* streamLabel */, track.Label)
	}
	media = media.WithPropertyAttribute(localDirection(weSend, peerDirection).String())

	for _, c := range candidates {
		media.WithCandidate(c)
	}
	media.WithPropertyAttribute("end-of-candidates")
	d.WithMedia(media)
}

func (r *RTCPeerConnection) addDataMediaSection(d *sdp.SessionDescription, midValue string, candidates []string) {
	media := (&sdp.MediaDescription{
		MediaName: sdp.MediaName{
			Media:   "application",
			Port:    sdp.RangedPort{Value: 9},
			Protos:  []string{"DTLS", "SCTP"},
			Formats: []int{5000},
		},
		ConnectionInformation: &sdp.ConnectionInformation{
			NetworkType: "IN",
			AddressType: "IP4",
			Address: &sdp.Address{
				IP: net.ParseIP("0.0.0.0"),
			},
		},
	}).
		WithValueAttribute(sdp.AttrKeyConnectionSetup, sdp.ConnectionRoleActive.String()). // TODO: Support other connection types
		WithValueAttribute(sdp.AttrKeyMID, midValue).
		WithPropertyAttribute(RTCRtpTransceiverDirectionSendrecv.String()).
		WithPropertyAttribute("sctpmap:5000 webrtc-datachannel 1024").
		WithICECredentials(r.networkManager.IceAgent.LocalUfrag, r.networkManager.IceAgent.LocalPwd)

	for _, c := range candidates {
		media.WithCandidate(c)
	}
	media.WithPropertyAttribute("end-of-candidates")

	d.WithMedia(media)
}
<|endoftext|>


<commit_before>package flagutil_test

import (
	"flag"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/vrischmann/flagutil"
)

func TestNetworkAddresses(t *testing.T) {
	var addrs flagutil.NetworkAddresses
	fs := flag.NewFlagSet("default", flag.ContinueOnError)
	fs.Var(&addrs, "H", "Addresses")

	s := []string{"-H", "a:4000,b:5000"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 2, len(addrs))
	require.Equal(t, "a:4000", addrs[0])
	require.Equal(t, "b:5000", addrs[1])
	require.Equal(t, "a:4000,b:5000", addrs.String())
	require.Equal(t, []string{"a:4000", "b:5000"}, addrs.StringSlice())
}

func TestStrings(t *testing.T) {
	var strings flagutil.Strings
	fs := flag.NewFlagSet("default", flag.ContinueOnError)
	fs.Var(&strings, "s", "Strings")

	s := []string{"-s", "foo,bar,baz"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 3, len(strings))
	require.Equal(t, "foo", strings[0])
	require.Equal(t, "bar", strings[1])
	require.Equal(t, "baz", strings[2])
	require.Equal(t, "foo,bar,baz", strings.String())
}

func TestURL(t *testing.T) {
	var url flagutil.URL
	fs := flag.NewFlagSet("default", flag.ContinueOnError)
	fs.Var(&url, "u", "URL")

	s := []string{"-u", "https://google.com"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.True(t, url.IsValid())
	require.Equal(t, "google.com", url.URL.Host)
	require.Equal(t, "https", url.URL.Scheme)
	require.Equal(t, "https://google.com", url.String())
}

func TestURLs(t *testing.T) {
	var urls flagutil.URLs
	fs := flag.NewFlagSet("default", flag.ContinueOnError)
	fs.Var(&urls, "u", "URLs")

	s := []string{"-u", "https://google.com,https://google.de"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 2, len(urls))
	require.Equal(t, "https://google.com", urls[0].String())
	require.Equal(t, "https://google.de", urls[1].String())
}
<commit_msg>Add more tests<commit_after>package flagutil_test

import (
	"flag"
	"io/ioutil"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/vrischmann/flagutil"
)

var (
	fs = flag.NewFlagSet("default", flag.ContinueOnError)
)

func init() {
	fs.SetOutput(ioutil.Discard)
}

func TestNetworkAddresses(t *testing.T) {
	var addrs flagutil.NetworkAddresses
	fs.Var(&addrs, "H", "Addresses")

	s := []string{"-H", "a:4000,b:5000"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 2, len(addrs))
	require.Equal(t, "a:4000", addrs[0])
	require.Equal(t, "b:5000", addrs[1])
	require.Equal(t, "a:4000,b:5000", addrs.String())
	require.Equal(t, []string{"a:4000", "b:5000"}, addrs.StringSlice())

	s = []string{"-H", "foo,bar"}
	err = fs.Parse(s)
	require.NotNil(t, err)
}

func TestStrings(t *testing.T) {
	var strings flagutil.Strings
	fs.Var(&strings, "s", "Strings")

	s := []string{"-s", "foo,bar,baz"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 3, len(strings))
	require.Equal(t, "foo", strings[0])
	require.Equal(t, "bar", strings[1])
	require.Equal(t, "baz", strings[2])
	require.Equal(t, "foo,bar,baz", strings.String())
}

func TestURL(t *testing.T) {
	var url flagutil.URL
	fs.Var(&url, "u", "URL")

	s := []string{"-u", "https://google.com"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.True(t, url.IsValid())
	require.Equal(t, "google.com", url.URL.Host)
	require.Equal(t, "https", url.URL.Scheme)
	require.Equal(t, "https://google.com", url.String())

	s = []string{"-u", "://foobar"}
	err = fs.Parse(s)
	require.NotNil(t, err)
}

func TestURLs(t *testing.T) {
	var urls flagutil.URLs
	fs.Var(&urls, "U", "URLs")

	s := []string{"-U", "https://google.com,https://google.de"}

	err := fs.Parse(s)
	require.Nil(t, err)
	require.Equal(t, 2, len(urls))
	require.Equal(t, "https://google.com", urls[0].String())
	require.Equal(t, "https://google.de", urls[1].String())
	require.Equal(t, "https://google.com,https://google.de", urls.String())

	s = []string{"-U", "://foobar"}
	err = fs.Parse(s)
	require.NotNil(t, err)
}
<|endoftext|>


<commit_before>package consumer

import (
	"encoding/json"
	"fmt"
	"github.com/blackbeans/redigo/redis"
	"log"
	"math/rand"
	_ "os"
	"strconv"
	"time"
)

// 用于向flume中作为sink 通过thrift客户端写入日志

type SinkServer struct {
	redisPool    map[string][]*redis.Pool
	flumeClients []*flumeClient
	isStop       bool
}

func NewSinkServer(option *Option) (server *SinkServer) {

	redisPool := make(map[string][]*redis.Pool, 0)

	//创建redis的消费连接
	for _, v := range option.queueHostPorts {

		pool := redis.NewPool(func() (conn redis.Conn, err error) {

			conn, err = redis.DialTimeout("tcp", v.Host+":"+strconv.Itoa(v.Port),
				time.Duration(v.Timeout)*time.Second,
				time.Duration(v.Timeout)*time.Second,
				time.Duration(v.Timeout)*time.Second)

			return
		}, time.Duration(v.Timeout*2)*time.Second, v.Maxconn/2, v.Maxconn)

		// if nil != err {
		// 	log.Printf("open redis %s:%d fail!  %s\n", v.Host, v.Port, err.Error())
		// 	os.Exit(-1)
		// }

		pools, ok := redisPool[v.QueueName]
		if !ok {
			pools = make([]*redis.Pool, 0)
			redisPool[v.QueueName] = pools
		}

		redisPool[v.QueueName] = append(pools, pool)

	}

	flumeClients := make([]*flumeClient, 0)
	//创建flume的client
	for _, v := range option.flumeAgents {
		client := newFlumeClient(v.Host, v.Port)
		client.connect()
		flumeClients = append(flumeClients, client)
	}

	sinkserver := &SinkServer{redisPool: redisPool, flumeClients: flumeClients}

	return sinkserver
}

//启动pop
func (self *SinkServer) Start() {

	self.isStop = false
	ch := make(chan int, 1)
	var count = 0
	for k, v := range self.redisPool {

		log.Println("start redis queueserver succ " + k)
		for _, pool := range v {
			count++
			defer pool.Close()
			go func(queuename string, pool *redis.Pool, end chan int) {
				conn := pool.Get()
				defer pool.Release(conn)
				for !self.isStop {

					// log.Println("pool active count :", strconv.Itoa(pool.ActiveCount()))
					reply, err := conn.Do("LPOP", queuename)
					if nil != err || nil == reply {
						if nil != err {
							log.Printf("LPOP|FAIL|%s", err)
							conn.Close()
							conn = pool.Get()
						} else {
							time.Sleep(100 * time.Millisecond)
						}

						continue
					}

					resp := reply.([]byte)
					var cmd command
					err = json.Unmarshal(resp, &cmd)

					if nil != err {
						log.Printf("command unmarshal fail ! %s | error:%s\n", resp, err.Error())
						continue
					} else if rand.Int()%10 == 0 {
						log.Println("trace|command|%s", cmd)
					}

					//
					momoid := cmd.Params["momoid"].(string)

					businessName := cmd.Params["businessName"].(string)

					action := cmd.Params["type"].(string)

					bodyContent := cmd.Params["body"]

					body, err := json.Marshal(bodyContent)

					if nil != err {
						log.Printf("marshal log body fail %s", err.Error())
						continue
					}

					//这里需要优化一下body,需要采用其他的方式定义Body格式，写入

					log.Printf("%s,%s,%s,%s", momoid, businessName, action, string(body))

					//启动处理任务
					go func(momoid, businessName, action string, body string) {

						for i := 0; i < 3; i++ {
							client := self.getFlumeClient(businessName, action)
							//拼装头部信息
							header := make(map[string]string, 1)
							header["businessName"] = businessName
							header["type"] = action

							//拼Body
							flumeBody := fmt.Sprintf("%s\t%s\t%s", momoid, action, body)
							err := client.append(header, []byte(flumeBody))

							if nil != err {
								log.Printf("send 2 flume fail %s \t err:%s\n", body, err.Error())
							} else {
								log.Printf("send 2 flume succ %s\n", body)
								break
							}
						}

					}(momoid, businessName, action, string(body))

				}
				end <- -1
			}(k, pool, ch)
		}
	}

	for {
		count += <-ch
		if count <= 0 {
			log.Printf("redis conn  close %d", count)
			break
		}
	}

}

func (self *SinkServer) Stop() {
	self.isStop = true

	for _, v := range self.flumeClients {
		v.destory()
	}

	for _, v := range self.redisPool {
		for _, p := range v {
			p.Close()
		}
	}
}

func (self *SinkServer) getFlumeClient(businessName, action string) *flumeClient {

	return self.flumeClients[0]
}
<commit_msg>增加发送失败后重新初始化连接 	modified:   ../consumer/log_sink.go<commit_after>package consumer

import (
	"encoding/json"
	"fmt"
	"github.com/blackbeans/redigo/redis"
	"log"
	"math/rand"
	_ "os"
	"strconv"
	"time"
)

// 用于向flume中作为sink 通过thrift客户端写入日志

type SinkServer struct {
	redisPool    map[string][]*redis.Pool
	flumeClients []*flumeClient
	isStop       bool
}

func NewSinkServer(option *Option) (server *SinkServer) {

	redisPool := make(map[string][]*redis.Pool, 0)

	//创建redis的消费连接
	for _, v := range option.queueHostPorts {

		pool := redis.NewPool(func() (conn redis.Conn, err error) {

			conn, err = redis.DialTimeout("tcp", v.Host+":"+strconv.Itoa(v.Port),
				time.Duration(v.Timeout)*time.Second,
				time.Duration(v.Timeout)*time.Second,
				time.Duration(v.Timeout)*time.Second)

			return
		}, time.Duration(v.Timeout*2)*time.Second, v.Maxconn/2, v.Maxconn)

		// if nil != err {
		// 	log.Printf("open redis %s:%d fail!  %s\n", v.Host, v.Port, err.Error())
		// 	os.Exit(-1)
		// }

		pools, ok := redisPool[v.QueueName]
		if !ok {
			pools = make([]*redis.Pool, 0)
			redisPool[v.QueueName] = pools
		}

		redisPool[v.QueueName] = append(pools, pool)

	}

	flumeClients := make([]*flumeClient, 0)
	//创建flume的client
	for _, v := range option.flumeAgents {
		client := newFlumeClient(v.Host, v.Port)
		client.connect()
		flumeClients = append(flumeClients, client)
	}

	sinkserver := &SinkServer{redisPool: redisPool, flumeClients: flumeClients}

	return sinkserver
}

//启动pop
func (self *SinkServer) Start() {

	self.isStop = false
	ch := make(chan int, 1)
	var count = 0
	for k, v := range self.redisPool {

		log.Println("start redis queueserver succ " + k)
		for _, pool := range v {
			count++
			defer pool.Close()
			go func(queuename string, pool *redis.Pool, end chan int) {
				conn := pool.Get()
				defer pool.Release(conn)
				for !self.isStop {

					// log.Println("pool active count :", strconv.Itoa(pool.ActiveCount()))
					reply, err := conn.Do("LPOP", queuename)
					if nil != err || nil == reply {
						if nil != err {
							log.Printf("LPOP|FAIL|%s", err)
							conn.Close()
							conn = pool.Get()
						} else {
							time.Sleep(100 * time.Millisecond)
						}

						continue
					}

					resp := reply.([]byte)
					var cmd command
					err = json.Unmarshal(resp, &cmd)

					if nil != err {
						log.Printf("command unmarshal fail ! %s | error:%s\n", resp, err.Error())
						continue
					} else if rand.Int()%10 == 0 {
						log.Println("trace|command|%s", cmd)
					}

					//
					momoid := cmd.Params["momoid"].(string)

					businessName := cmd.Params["businessName"].(string)

					action := cmd.Params["type"].(string)

					bodyContent := cmd.Params["body"]

					body, err := json.Marshal(bodyContent)

					if nil != err {
						log.Printf("marshal log body fail %s", err.Error())
						continue
					}

					//这里需要优化一下body,需要采用其他的方式定义Body格式，写入

					log.Printf("%s,%s,%s,%s", momoid, businessName, action, string(body))

					//启动处理任务
					go func(momoid, businessName, action string, body string) {

						for i := 0; i < 3; i++ {
							client := self.getFlumeClient(businessName, action)
							//拼装头部信息
							header := make(map[string]string, 1)
							header["businessName"] = businessName
							header["type"] = action

							//拼Body
							flumeBody := fmt.Sprintf("%s\t%s\t%s", momoid, action, body)
							err := client.append(header, []byte(flumeBody))

							if nil != err {
								log.Printf("send 2 flume fail %s \t err:%s\n", body, err.Error())
								client.destory()
								client.connect()
							} else {
								log.Printf("send 2 flume succ %s\n", body)
								break
							}
						}

					}(momoid, businessName, action, string(body))

				}
				end <- -1
			}(k, pool, ch)
		}
	}

	for {
		count += <-ch
		if count <= 0 {
			log.Printf("redis conn  close %d", count)
			break
		}
	}

}

func (self *SinkServer) Stop() {
	self.isStop = true

	for _, v := range self.flumeClients {
		v.destory()
	}

	for _, v := range self.redisPool {
		for _, p := range v {
			p.Close()
		}
	}
}

func (self *SinkServer) getFlumeClient(businessName, action string) *flumeClient {

	return self.flumeClients[0]
}
<|endoftext|>


<commit_before>package nx

import (
	"github.com/edsrzf/mmap-go"
	"os"
)

type File struct {
	Fn     string
	header Header
	raw    mmap.MMap
}

func NewFile(fn string, p bool) (*File, error) {
	f, err := os.Open(fn)
	defer f.Close()
	if err != nil {
		return nil, err
	}

	buf, err := mmap.Map(f, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	nxf := new(File)
	nxf.Fn = fn
	nxf.raw = buf

	if p {
		err = nxf.Parse()
	}

	return nxf, err
}

func (nxf *File) Parse() error {
	nxh, err := nxf.Header()
	if err != nil {
		return err
	}
	nxf.header = nxh
	return nil
}
<commit_msg>Defer after error is handled f might be nil if the file doesn't exist<commit_after>package nx

import (
	"github.com/edsrzf/mmap-go"
	"os"
)

type File struct {
	Fn     string
	header Header
	raw    mmap.MMap
}

func NewFile(fn string, p bool) (*File, error) {
	f, err := os.Open(fn)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	buf, err := mmap.Map(f, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	nxf := new(File)
	nxf.Fn = fn
	nxf.raw = buf

	if p {
		err = nxf.Parse()
	}

	return nxf, err
}

func (nxf *File) Parse() error {
	nxh, err := nxf.Header()
	if err != nil {
		return err
	}
	nxf.header = nxh
	return nil
}
<|endoftext|>


<commit_before>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type FlickrClient struct {
	ApiKey      string
	ApiSecret   string
	HTTPClient  *http.Client
	EndpointUrl string
	Method      string
	Args        url.Values
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		Method:     "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", getSignature(c, tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func (rt *RequestToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))
	rt.OauthCallbackConfirmed = confirmed
	rt.OauthToken = val.Get("oauth_token")
	rt.OauthTokenSecret = val.Get("oauth_token_secret")

	return nil
}

func getSigningBaseString(client *FlickrClient) string {
	request_url := url.QueryEscape(client.EndpointUrl)
	query := url.QueryEscape(client.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", client.Method, request_url, query)
}

func getSignature(client *FlickrClient, token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(client.ApiSecret), url.QueryEscape(token_secret))
	base_string := getSigningBaseString(client)

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	token := RequestToken{}
	token.Parse(string(body))

	return &token, nil
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)

	return client.GetUrl(), nil
}
<commit_msg>require delete permission<commit_after>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type FlickrClient struct {
	ApiKey      string
	ApiSecret   string
	HTTPClient  *http.Client
	EndpointUrl string
	Method      string
	Args        url.Values
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		Method:     "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", getSignature(c, tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func (rt *RequestToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))
	rt.OauthCallbackConfirmed = confirmed
	rt.OauthToken = val.Get("oauth_token")
	rt.OauthTokenSecret = val.Get("oauth_token_secret")

	return nil
}

func getSigningBaseString(client *FlickrClient) string {
	request_url := url.QueryEscape(client.EndpointUrl)
	query := url.QueryEscape(client.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", client.Method, request_url, query)
}

func getSignature(client *FlickrClient, token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(client.ApiSecret), url.QueryEscape(token_secret))
	base_string := getSigningBaseString(client)

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	token := RequestToken{}
	token.Parse(string(body))

	return &token, nil
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Args.Set("perms", "delete")

	return client.GetUrl(), nil
}
<|endoftext|>


<commit_before>package bfs

import (
	"fmt"
	"testing"

	"github.com/gyuho/goraph/graph/gs"
)

// Order changes different every time it runs.

func TestBFS(t *testing.T) {
	g4 := gs.FromJSON("../../files/testgraph.json", "testgraph.004")
	g4s := BFS(g4, g4.FindVertexByID("S"))
	/*
		g4c1 := "S → B → A → D → E → T → F → C"
		g4c2 := "S → B → D → E → A → T → F → C"
		g4c3 := "S → B → E → A → D → C → F → T"
		if g4s != g4c1 && g4s != g4c2 && g4s != g4c3 {
			t.Errorf("Should be same but\n%v\n%v\n%v", g4s, g4c1, g4c2)
		}
	*/

	allvisited4 := true
	g4vts := g4.GetVertices()
	for _, vtx := range *g4vts {
		if "black" != fmt.Sprintf("%v", vtx.(*gs.Vertex).Color) {
			allvisited4 = false
		}
	}
	if !allvisited4 {
		t.Errorf("All vertices should be marked black")
	}

	g5 := gs.FromJSON("../../files/testgraph.json", "testgraph.005")
	g5s := BFS(g5, g5.FindVertexByID("A"))
	/*
		g5c1 := "A → C → F → B → D → E"
		g5c2 := "A → B → C → F → D → E"
		if g5s != g5c1 && g5s != g5c2 {
			t.Errorf("Should be same but\n%v\n%v\n%v", g5s, g5c1, g5c2)
		}
	*/

	allvisited5 := true
	g5vts := g5.GetVertices()
	for _, vtx := range *g5vts {
		if "black" != fmt.Sprintf("%v", vtx.(*gs.Vertex).Color) {
			allvisited5 = false
		}
	}
	if !allvisited5 {
		t.Errorf("All vertices should be marked black")
	}
}

func TestPath(t *testing.T) {
	g4 := gs.FromJSON("../../files/testgraph.json", "testgraph.004")
	rb4 := Path(g4, g4.FindVertexByID("S"), g4.FindVertexByID("F"))
	if !rb4 {
		t.Errorf("Should return true but %+v\n", rb4)
	}

	g16 := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16 := Path(g16, g16.FindVertexByID("C"), g16.FindVertexByID("B"))
	if rb16 {
		t.Errorf("Should return false but %+v\n", rb16)
	}

	g16i := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16i := Path(g16i, g16i.FindVertexByID("I"), g16i.FindVertexByID("J"))
	if !rb16i {
		t.Errorf("Should return true but %+v\n", rb16i)
	}

	g16j := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16j := Path(g16j, g16j.FindVertexByID("J"), g16j.FindVertexByID("I"))
	if rb16j {
		t.Errorf("Should return false but %+v\n", rb16j)
	}

	g16d := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16d := Path(g16d, g16d.FindVertexByID("D"), g16d.FindVertexByID("E"))
	if !rb16d {
		t.Errorf("Should return true but %+v\n", rb16d)
	}
}
<commit_msg>Update testing<commit_after>package bfs

import (
	"fmt"
	"testing"

	"github.com/gyuho/goraph/graph/gs"
)

// Order changes different every time it runs.

func TestBFS(t *testing.T) {
	g4 := gs.FromJSON("../../files/testgraph.json", "testgraph.004")
	_ = BFS(g4, g4.FindVertexByID("S"))
	/*
		g4c1 := "S → B → A → D → E → T → F → C"
		g4c2 := "S → B → D → E → A → T → F → C"
		g4c3 := "S → B → E → A → D → C → F → T"
		if g4s != g4c1 && g4s != g4c2 && g4s != g4c3 {
			t.Errorf("Should be same but\n%v\n%v\n%v", g4s, g4c1, g4c2)
		}
	*/

	allvisited4 := true
	g4vts := g4.GetVertices()
	for _, vtx := range *g4vts {
		if "black" != fmt.Sprintf("%v", vtx.(*gs.Vertex).Color) {
			allvisited4 = false
		}
	}
	if !allvisited4 {
		t.Errorf("All vertices should be marked black")
	}

	g5 := gs.FromJSON("../../files/testgraph.json", "testgraph.005")
	_ = BFS(g5, g5.FindVertexByID("A"))
	/*
		g5c1 := "A → C → F → B → D → E"
		g5c2 := "A → B → C → F → D → E"
		if g5s != g5c1 && g5s != g5c2 {
			t.Errorf("Should be same but\n%v\n%v\n%v", g5s, g5c1, g5c2)
		}
	*/

	allvisited5 := true
	g5vts := g5.GetVertices()
	for _, vtx := range *g5vts {
		if "black" != fmt.Sprintf("%v", vtx.(*gs.Vertex).Color) {
			allvisited5 = false
		}
	}
	if !allvisited5 {
		t.Errorf("All vertices should be marked black")
	}
}

func TestPath(t *testing.T) {
	g4 := gs.FromJSON("../../files/testgraph.json", "testgraph.004")
	rb4 := Path(g4, g4.FindVertexByID("S"), g4.FindVertexByID("F"))
	if !rb4 {
		t.Errorf("Should return true but %+v\n", rb4)
	}

	g16 := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16 := Path(g16, g16.FindVertexByID("C"), g16.FindVertexByID("B"))
	if rb16 {
		t.Errorf("Should return false but %+v\n", rb16)
	}

	g16i := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16i := Path(g16i, g16i.FindVertexByID("I"), g16i.FindVertexByID("J"))
	if !rb16i {
		t.Errorf("Should return true but %+v\n", rb16i)
	}

	g16j := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16j := Path(g16j, g16j.FindVertexByID("J"), g16j.FindVertexByID("I"))
	if rb16j {
		t.Errorf("Should return false but %+v\n", rb16j)
	}

	g16d := gs.FromJSON("../../files/testgraph.json", "testgraph.016")
	rb16d := Path(g16d, g16d.FindVertexByID("D"), g16d.FindVertexByID("E"))
	if !rb16d {
		t.Errorf("Should return true but %+v\n", rb16d)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"strings"
	"encoding/gob"
	"fmt"
	"bufio"
	"io"
	"log"
	"net"
	"os"

	"github.com/flynn/go-discover/discover"
	"github.com/flynn/lorne/types"
	"github.com/titanous/go-dockerclient"
	"github.com/flynn/sampi/types"
	sc "github.com/flynn/sampi/client"
	lc "github.com/flynn/lorne/client"
)

// WARNING: assumes one host at the moment (firstHost will always be the same)

var sd *discover.Client
var sched *sc.Client
var host *lc.Client
var hostid string

func init() {
	var err error
	sd, err = discover.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	sched, err = sc.New()
	if err != nil {
		log.Fatal(err)
	}

	hostid = findHost()
	host, err = lc.New(hostid)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	root := "/var/lib/demo/apps"
	hostname := shell("curl -s icanhazip.com")

	set, _ := sd.Services("shelf")
	addrs := set.OnlineAddrs()
	if len(addrs) < 1 {
		panic("Shelf is not discoverable")
	}
	shelfHost := addrs[0]

	app := os.Args[2]
	os.MkdirAll(root+"/"+app, 0755)

	fmt.Printf("-----> Building %s on %s ...\n", app, hostname)

	scheduleAndAttach(app + ".build", docker.Config{
		Image:        "flynn/slugbuilder",
		Cmd:          []string{"http://" + shelfHost + "/" + app + ".tgz"},
		Tty:          false,
		AttachStdin:  true,
		AttachStdout: true,
		AttachStderr: true,
		OpenStdin:    true,
		StdinOnce:    true,
	})

	fmt.Printf("-----> Deploying %s ...\n", app)

	jobid := app + ".web"

	stopIfExists(jobid)
	scheduleWithTcpPort(jobid, docker.Config{
		Image:        "flynn/slugrunner",
		Cmd:          []string{"start", "web"},
		Tty:          false,
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
		OpenStdin:    false,
		StdinOnce:    false,
		Env: []string{
			"SLUG_URL=http://" + shelfHost + "/" + app + ".tgz",
		},
	})

	fmt.Printf("=====> Application deployed:\n")
	fmt.Printf("       http://%s:%s\n", hostname, getPort(jobid))
	fmt.Println("")

}

func shell(cmdline string) string {
        out, err := exec.Command("bash", "-c", cmdline).Output()
        if err != nil {
                panic(err)
        }
        return strings.Trim(string(out), " \n")
}

func stopIfExists(jobid string) {
	_, err := host.GetJob(jobid)
	if err != nil {
		return
	}
	if err := host.StopJob(jobid); err != nil {
		return
	}
}

func scheduleWithTcpPort(jobid string, config docker.Config) {

	schedReq := &sampi.ScheduleReq{
		Incremental: true,
		HostJobs:    map[string][]*sampi.Job{hostid: {{ID: jobid, Config: &config, TCPPorts: 1}}},
	}
	if _, err := sched.Schedule(schedReq); err != nil {
		log.Fatal(err)
	}
}

func getPort(jobid string) string {
	if job, err := host.GetJob(jobid); err != nil {
		log.Fatal(err)
	}
	return job.Job.Config.PortSpecs[0]
}

func findHost() string {
	state, err := sched.State()
	if err != nil {
		log.Fatal(err)
	}

	var firstHost string
	for k := range state {
		firstHost = k
		break
	}
	if firstHost == "" {
		log.Fatal("no hosts")
	}
	return firstHost
}

func scheduleAndAttach(jobid string, config docker.Config) {

	services, err := sd.Services("flynn-lorne-attach." + hostid)
	if err != nil {
		log.Fatal(err)
	}
	conn, err := net.Dial("tcp", services.OnlineAddrs()[0])
	if err != nil {
		log.Fatal(err)
	}
	err = gob.NewEncoder(conn).Encode(&lorne.AttachReq{
		JobID: jobid,
		Flags: lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagStdin | lorne.AttachFlagStream,
	})
	if err != nil {
		log.Fatal(err)
	}
	attachState := make([]byte, 1)
	if _, err := conn.Read(attachState); err != nil {
		log.Fatal(err)
	}
	switch attachState[0] {
	case lorne.AttachError:
		log.Fatal("attach error")
	}

	schedReq := &sampi.ScheduleReq{
		Incremental: true,
		HostJobs:    map[string][]*sampi.Job{hostid: {{ID: jobid, Config: &config}}},
	}
	if _, err := sched.Schedule(schedReq); err != nil {
		log.Fatal(err)
	}

	if _, err := conn.Read(attachState); err != nil {
		log.Fatal(err)
	}

	go func() {
		io.Copy(conn, os.Stdin)
		conn.(*net.TCPConn).CloseWrite()
	}()
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		fmt.Fprintln(os.Stdout, scanner.Text()[8:])
	}
	conn.Close()
}
<commit_msg>demo: scoping<commit_after>package main

import (
	"os/exec"
	"strings"
	"encoding/gob"
	"fmt"
	"bufio"
	"io"
	"log"
	"net"
	"os"

	"github.com/flynn/go-discover/discover"
	"github.com/flynn/lorne/types"
	"github.com/titanous/go-dockerclient"
	"github.com/flynn/sampi/types"
	sc "github.com/flynn/sampi/client"
	lc "github.com/flynn/lorne/client"
)

// WARNING: assumes one host at the moment (firstHost will always be the same)

var sd *discover.Client
var sched *sc.Client
var host *lc.Client
var hostid string

func init() {
	var err error
	sd, err = discover.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	sched, err = sc.New()
	if err != nil {
		log.Fatal(err)
	}

	hostid = findHost()
	host, err = lc.New(hostid)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	root := "/var/lib/demo/apps"
	hostname := shell("curl -s icanhazip.com")

	set, _ := sd.Services("shelf")
	addrs := set.OnlineAddrs()
	if len(addrs) < 1 {
		panic("Shelf is not discoverable")
	}
	shelfHost := addrs[0]

	app := os.Args[2]
	os.MkdirAll(root+"/"+app, 0755)

	fmt.Printf("-----> Building %s on %s ...\n", app, hostname)

	scheduleAndAttach(app + ".build", docker.Config{
		Image:        "flynn/slugbuilder",
		Cmd:          []string{"http://" + shelfHost + "/" + app + ".tgz"},
		Tty:          false,
		AttachStdin:  true,
		AttachStdout: true,
		AttachStderr: true,
		OpenStdin:    true,
		StdinOnce:    true,
	})

	fmt.Printf("-----> Deploying %s ...\n", app)

	jobid := app + ".web"

	stopIfExists(jobid)
	scheduleWithTcpPort(jobid, docker.Config{
		Image:        "flynn/slugrunner",
		Cmd:          []string{"start", "web"},
		Tty:          false,
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
		OpenStdin:    false,
		StdinOnce:    false,
		Env: []string{
			"SLUG_URL=http://" + shelfHost + "/" + app + ".tgz",
		},
	})

	fmt.Printf("=====> Application deployed:\n")
	fmt.Printf("       http://%s:%s\n", hostname, getPort(jobid))
	fmt.Println("")

}

func shell(cmdline string) string {
        out, err := exec.Command("bash", "-c", cmdline).Output()
        if err != nil {
                panic(err)
        }
        return strings.Trim(string(out), " \n")
}

func stopIfExists(jobid string) {
	_, err := host.GetJob(jobid)
	if err != nil {
		return
	}
	if err := host.StopJob(jobid); err != nil {
		return
	}
}

func scheduleWithTcpPort(jobid string, config docker.Config) {

	schedReq := &sampi.ScheduleReq{
		Incremental: true,
		HostJobs:    map[string][]*sampi.Job{hostid: {{ID: jobid, Config: &config, TCPPorts: 1}}},
	}
	if _, err := sched.Schedule(schedReq); err != nil {
		log.Fatal(err)
	}
}

func getPort(jobid string) string {
	job, err := host.GetJob(jobid)
	if err != nil {
		log.Fatal(err)
	}
	return job.Job.Config.PortSpecs[0]
}

func findHost() string {
	state, err := sched.State()
	if err != nil {
		log.Fatal(err)
	}

	var firstHost string
	for k := range state {
		firstHost = k
		break
	}
	if firstHost == "" {
		log.Fatal("no hosts")
	}
	return firstHost
}

func scheduleAndAttach(jobid string, config docker.Config) {

	services, err := sd.Services("flynn-lorne-attach." + hostid)
	if err != nil {
		log.Fatal(err)
	}
	conn, err := net.Dial("tcp", services.OnlineAddrs()[0])
	if err != nil {
		log.Fatal(err)
	}
	err = gob.NewEncoder(conn).Encode(&lorne.AttachReq{
		JobID: jobid,
		Flags: lorne.AttachFlagStdout | lorne.AttachFlagStderr | lorne.AttachFlagStdin | lorne.AttachFlagStream,
	})
	if err != nil {
		log.Fatal(err)
	}
	attachState := make([]byte, 1)
	if _, err := conn.Read(attachState); err != nil {
		log.Fatal(err)
	}
	switch attachState[0] {
	case lorne.AttachError:
		log.Fatal("attach error")
	}

	schedReq := &sampi.ScheduleReq{
		Incremental: true,
		HostJobs:    map[string][]*sampi.Job{hostid: {{ID: jobid, Config: &config}}},
	}
	if _, err := sched.Schedule(schedReq); err != nil {
		log.Fatal(err)
	}

	if _, err := conn.Read(attachState); err != nil {
		log.Fatal(err)
	}

	go func() {
		io.Copy(conn, os.Stdin)
		conn.(*net.TCPConn).CloseWrite()
	}()
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		fmt.Fprintln(os.Stdout, scanner.Text()[8:])
	}
	conn.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/flynn/flynn-controller/client"
	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/cluster"
	"github.com/flynn/go-flynn/exec"
)

var clusterc *cluster.Client

func init() {
	log.SetFlags(0)

	var err error
	clusterc, err = cluster.NewClient()
	if err != nil {
		log.Fatalln("Error connecting to cluster leader:", err)
	}
}

var typesPattern = regexp.MustCompile("types.* -> (.+)\n")

func main() {
	client, err := controller.NewClient("", os.Getenv("CONTROLLER_AUTH_KEY"))
	if err != nil {
		log.Fatalln("Unable to connect to controller:", err)
	}
	// TODO: use discoverd http dialer here?
	services, err := discoverd.Services("shelf", discoverd.DefaultTimeout)
	if err != nil || len(services) < 1 {
		log.Fatalf("Unable to discover shelf %q", err)
	}
	shelfHost := services[0].Addr

	app := os.Args[1]
	commit := os.Args[2]

	_, err = client.GetApp(app)
	if err == controller.ErrNotFound {
		log.Fatalf("Unknown app %q", app)
	} else if err != nil {
		log.Fatalln("Error retrieving app:", err)
	}
	prevRelease, err := client.GetAppRelease(app)
	if err == controller.ErrNotFound {
		prevRelease = &ct.Release{}
	} else if err != nil {
		log.Fatalln("Error creating getting current app release:", err)
	}

	fmt.Printf("-----> Building %s...\n", app)

	var output bytes.Buffer
	slugURL := fmt.Sprintf("http://%s/%s.tgz", shelfHost, commit)
	cmd := exec.Command("flynn/slugbuilder", slugURL)
	cmd.Stdout = io.MultiWriter(os.Stdout, &output)
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	cmd.Env = prevRelease.Env

	if err := cmd.Run(); err != nil {
		log.Fatalln("Build failed:", err)
	}

	var types []string
	if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
		types = strings.Split(string(match[1]), ", ")
	}

	fmt.Printf("-----> Creating release...\n")

	artifact := &ct.Artifact{URI: "docker://flynn/slugrunner"}
	if err := client.CreateArtifact(artifact); err != nil {
		log.Fatalln("Error creating artifact:", err)
	}

	release := &ct.Release{
		ArtifactID: artifact.ID,
		Env:        prevRelease.Env,
	}
	procs := make(map[string]ct.ProcessType)
	for _, t := range types {
		proc := prevRelease.Processes[t]
		proc.Cmd = []string{"start", t}
		if t == "web" {
			proc.Ports.TCP = 1
			if proc.Env == nil {
				proc.Env = make(map[string]string)
			}
			proc.Env["SD_NAME"] = app + "-web"
		}
		procs[t] = proc
	}
	release.Processes = procs
	if release.Env == nil {
		release.Env = make(map[string]string)
	}
	release.Env["SLUG_URL"] = slugURL

	if err := client.CreateRelease(release); err != nil {
		log.Fatalln("Error creating release:", err)
	}
	if err := client.SetAppRelease(app, release.ID); err != nil {
		log.Fatalln("Error setting app release:", err)
	}

	fmt.Println("=====> Application deployed")
}
<commit_msg>receiver: Only send BUILDPACK_URL env var to slugbuilder<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/flynn/flynn-controller/client"
	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/cluster"
	"github.com/flynn/go-flynn/exec"
)

var clusterc *cluster.Client

func init() {
	log.SetFlags(0)

	var err error
	clusterc, err = cluster.NewClient()
	if err != nil {
		log.Fatalln("Error connecting to cluster leader:", err)
	}
}

var typesPattern = regexp.MustCompile("types.* -> (.+)\n")

func main() {
	client, err := controller.NewClient("", os.Getenv("CONTROLLER_AUTH_KEY"))
	if err != nil {
		log.Fatalln("Unable to connect to controller:", err)
	}
	// TODO: use discoverd http dialer here?
	services, err := discoverd.Services("shelf", discoverd.DefaultTimeout)
	if err != nil || len(services) < 1 {
		log.Fatalf("Unable to discover shelf %q", err)
	}
	shelfHost := services[0].Addr

	app := os.Args[1]
	commit := os.Args[2]

	_, err = client.GetApp(app)
	if err == controller.ErrNotFound {
		log.Fatalf("Unknown app %q", app)
	} else if err != nil {
		log.Fatalln("Error retrieving app:", err)
	}
	prevRelease, err := client.GetAppRelease(app)
	if err == controller.ErrNotFound {
		prevRelease = &ct.Release{}
	} else if err != nil {
		log.Fatalln("Error creating getting current app release:", err)
	}

	fmt.Printf("-----> Building %s...\n", app)

	var output bytes.Buffer
	slugURL := fmt.Sprintf("http://%s/%s.tgz", shelfHost, commit)
	cmd := exec.Command("flynn/slugbuilder", slugURL)
	cmd.Stdout = io.MultiWriter(os.Stdout, &output)
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	if buildpackURL, ok := prevRelease.Env["BUILDPACK_URL"]; ok {
		cmd.Env = map[string]string{"BUILDPACK_URL": buildpackURL}
	}

	if err := cmd.Run(); err != nil {
		log.Fatalln("Build failed:", err)
	}

	var types []string
	if match := typesPattern.FindSubmatch(output.Bytes()); match != nil {
		types = strings.Split(string(match[1]), ", ")
	}

	fmt.Printf("-----> Creating release...\n")

	artifact := &ct.Artifact{URI: "docker://flynn/slugrunner"}
	if err := client.CreateArtifact(artifact); err != nil {
		log.Fatalln("Error creating artifact:", err)
	}

	release := &ct.Release{
		ArtifactID: artifact.ID,
		Env:        prevRelease.Env,
	}
	procs := make(map[string]ct.ProcessType)
	for _, t := range types {
		proc := prevRelease.Processes[t]
		proc.Cmd = []string{"start", t}
		if t == "web" {
			proc.Ports.TCP = 1
			if proc.Env == nil {
				proc.Env = make(map[string]string)
			}
			proc.Env["SD_NAME"] = app + "-web"
		}
		procs[t] = proc
	}
	release.Processes = procs
	if release.Env == nil {
		release.Env = make(map[string]string)
	}
	release.Env["SLUG_URL"] = slugURL

	if err := client.CreateRelease(release); err != nil {
		log.Fatalln("Error creating release:", err)
	}
	if err := client.SetAppRelease(app, release.ID); err != nil {
		log.Fatalln("Error setting app release:", err)
	}

	fmt.Println("=====> Application deployed")
}
<|endoftext|>


<commit_before>package url

import (
	"errors"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"io/ioutil"
	"net/http"
	"regexp"
)

const (
	urlRegex = `^(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*$`
)

type Module struct {
	// TODO
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links"
}

func (m *Module) Load(client *irc.Client) error {
	regex := regexp.MustCompile(urlRegex)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		if !regex.MatchString(msg.Data) {
			return nil
		}

		title, err := m.extractTitle(msg.Data)
		if err == nil {
			c.Write("NOTICE %s :Page title: %q", msg.Receiver, title)
		}

		return nil
	})

	return nil
}

func (m *Module) extractTitle(uri string) (title string, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	regex := regexp.MustCompile("<title>(.*)</title>")
	match := regex.FindStringSubmatch(string(body))

	if len(match) <= 0 {
		err = errors.New("Couldn't extract title")
	}

	title = html.UnescapeString(match[1])
	return
}
<commit_msg>Punctuation<commit_after>package url

import (
	"errors"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"io/ioutil"
	"net/http"
	"regexp"
)

const (
	urlRegex = `^(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*$`
)

type Module struct {
	// TODO
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links."
}

func (m *Module) Load(client *irc.Client) error {
	regex := regexp.MustCompile(urlRegex)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		if !regex.MatchString(msg.Data) {
			return nil
		}

		title, err := m.extractTitle(msg.Data)
		if err == nil {
			c.Write("NOTICE %s :Page title: %q", msg.Receiver, title)
		}

		return nil
	})

	return nil
}

func (m *Module) extractTitle(uri string) (title string, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	regex := regexp.MustCompile("<title>(.*)</title>")
	match := regex.FindStringSubmatch(string(body))

	if len(match) <= 0 {
		err = errors.New("Couldn't extract title")
	}

	title = html.UnescapeString(match[1])
	return
}
<|endoftext|>


<commit_before>// Copyright 2014 Brian J. Downs
//
// 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 openweathermap

import (
	"testing"
)

func TestNewForecast(t *testing.T) {
	f, err := NewForecast("imperial")
	if err != nil {
		t.Error(err)
	}
	if !ValidDataUnit(f.Units) {
		t.Error("Failed creating instance of HistoricalWeatherData")
	}
}
<commit_msg>forecast by name test<commit_after>// Copyright 2014 Brian J. Downs
//
// 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 openweathermap

import (
	"reflect"
	"testing"
)

func TestNewForecast(t *testing.T) {
	t.Parallel()
	for _, u := range dataUnits {
		t.Logf("Data unit: %s", u)
		if ValidDataUnit(u) {
			c, err := NewForecast(u)
			if err != nil {
				t.Error(err)
			}
			if reflect.TypeOf(c).String() != "*openweathermap.ForecastWeatherData" {
				t.Error("ERROR: incorrect data type returned")
			}
		} else {
			t.Errorf("ERROR: unusable data unit - %s", u)
		}
	}
}

func TestDailyByName(t *testing.T) {
	f, err := NewForecast("imperial")
	if err != nil {
		t.Error("")
	}
	f.DailyByName("Dubai", 3)
}

func TestDailyByCoordinates(t *testing.T) {}
func TestDailyByID(t *testing.T)          {}
<|endoftext|>