<commit_before>package services

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"

	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

type Plan struct {
	Name string `json:"name"`
	ID   string `json:"id"`
}

type ServiceBroker struct {
	Name    string
	Path    string
	context helpers.SuiteContext
	Service struct {
		Name            string `json:"name"`
		ID              string `json:"id"`
		DashboardClient struct {
			ID          string `json:"id"`
			Secret      string `json:"secret"`
			RedirectUri string `json:"redirect_uri"`
		}
	}
	SyncPlans  []Plan
	AsyncPlans []Plan
}

type ServicesResponse struct {
	Resources []ServiceResponse
}

type ServiceResponse struct {
	Entity struct {
		Label        string
		ServicePlans []ServicePlanResponse `json:"service_plans"`
	}
}

type ServicePlanResponse struct {
	Entity struct {
		Name   string
		Public bool
	}
	Metadata struct {
		Url  string
		Guid string
	}
}

type ServiceInstance struct {
	Metadata struct {
		Guid string `json:"guid"`
	}
}

type ServiceInstanceResponse struct {
	Resources []ServiceInstance
}

type SpaceJson struct {
	Resources []struct {
		Metadata struct {
			Guid string
		}
	}
}

func NewServiceBroker(name string, path string, context helpers.SuiteContext) ServiceBroker {
	b := ServiceBroker{}
	b.Path = path
	b.Name = name
	b.Service.Name = generator.RandomName()
	b.Service.ID = generator.RandomName()
	b.SyncPlans = []Plan{
		{Name: generator.RandomName(), ID: generator.RandomName()},
		{Name: generator.RandomName(), ID: generator.RandomName()},
	}
	b.AsyncPlans = []Plan{
		{Name: generator.RandomName(), ID: generator.RandomName()},
		{Name: generator.RandomName(), ID: generator.RandomName()},
	}
	b.Service.DashboardClient.ID = generator.RandomName()
	b.Service.DashboardClient.Secret = generator.RandomName()
	b.Service.DashboardClient.RedirectUri = generator.RandomName()
	b.context = context
	return b
}

func (b ServiceBroker) Push() {
	Expect(cf.Cf("push", b.Name, "-p", b.Path).Wait(BROKER_START_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Configure() {
	Expect(runner.Curl(helpers.AppUri(b.Name, "/config"), "-d", b.ToJSON()).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Restart() {
	Expect(cf.Cf("restart", b.Name).Wait(BROKER_START_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Create() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("create-service-broker", b.Name, "username", "password", helpers.AppUri(b.Name, "")).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("service-brokers").Wait(DEFAULT_TIMEOUT)).To(Say(b.Name))
	})
}

func (b ServiceBroker) Update() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("update-service-broker", b.Name, "username", "password", helpers.AppUri(b.Name, "")).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
}

func (b ServiceBroker) Delete() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("delete-service-broker", b.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))

		brokers := cf.Cf("service-brokers").Wait(DEFAULT_TIMEOUT)
		Expect(brokers).To(Exit(0))
		Expect(brokers.Out.Contents()).ToNot(ContainSubstring(b.Name))
	})
}

func (b ServiceBroker) Destroy() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("purge-service-offering", b.Service.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
	b.Delete()
	Expect(cf.Cf("delete", b.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) ToJSON() string {
	bytes, err := ioutil.ReadFile(assets.NewAssets().ServiceBroker + "/cats.json")
	Expect(err).To(BeNil())

	replacer := strings.NewReplacer(
		"<fake-service>", b.Service.Name,
		"<fake-service-guid>", b.Service.ID,
		"<sso-test>", b.Service.DashboardClient.ID,
		"<sso-secret>", b.Service.DashboardClient.Secret,
		"<sso-redirect-uri>", b.Service.DashboardClient.RedirectUri,
		"<fake-plan>", b.SyncPlans[0].Name,
		"<fake-plan-guid>", b.SyncPlans[0].ID,
		"<fake-plan-2>", b.SyncPlans[1].Name,
		"<fake-plan-2-guid>", b.SyncPlans[1].ID,
		"<fake-async-plan>", b.AsyncPlans[0].Name,
		"<fake-async-plan-guid>", b.AsyncPlans[0].ID,
		"<fake-async-plan-2>", b.AsyncPlans[1].Name,
		"<fake-async-plan-2-guid>", b.AsyncPlans[1].ID,
	)

	return replacer.Replace(string(bytes))
}

func (b ServiceBroker) PublicizePlans() {
	url := fmt.Sprintf("/v2/services?inline-relations-depth=1&q=label:%s", b.Service.Name)
	var session *Session
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		session = cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
		Expect(session).To(Exit(0))
	})
	structure := ServicesResponse{}
	json.Unmarshal(session.Out.Contents(), &structure)

	for _, service := range structure.Resources {
		if service.Entity.Label == b.Service.Name {
			for _, plan := range service.Entity.ServicePlans {
				if b.HasPlan(plan.Entity.Name) {
					b.PublicizePlan(plan.Metadata.Url)
				}
			}
		}
	}
}

func (b ServiceBroker) HasPlan(planName string) bool {
	for _, plan := range b.Plans() {
		if plan.Name == planName {
			return true
		}
	}
	return false
}

func (b ServiceBroker) PublicizePlan(url string) {
	jsonMap := make(map[string]bool)
	jsonMap["public"] = true
	planJson, _ := json.Marshal(jsonMap)
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("curl", url, "-X", "PUT", "-d", string(planJson)).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
}

func (b ServiceBroker) CreateServiceInstance(instanceName string) string {
	Expect(cf.Cf("create-service", b.Service.Name, b.SyncPlans[0].Name, instanceName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	url := fmt.Sprintf("/v2/service_instances?q=name:%s", instanceName)
	serviceInstance := ServiceInstanceResponse{}
	curl := cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
	json.Unmarshal(curl.Out.Contents(), &serviceInstance)
	return serviceInstance.Resources[0].Metadata.Guid
}

func (b ServiceBroker) GetSpaceGuid() string {
	url := fmt.Sprintf("/v2/spaces?q=name%%3A%s", b.context.RegularUserContext().Space)
	jsonResults := SpaceJson{}
	curl := cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
	json.Unmarshal(curl.Out.Contents(), &jsonResults)
	return jsonResults.Resources[0].Metadata.Guid
}

func (b ServiceBroker) Plans() []Plan {
	plans := make([]Plan, 0)
	plans = append(plans, b.SyncPlans...)
	plans = append(plans, b.AsyncPlans...)
	return plans
}
<commit_msg>Services tests can use diego when available<commit_after>package services

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"

	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

type Plan struct {
	Name string `json:"name"`
	ID   string `json:"id"`
}

type ServiceBroker struct {
	Name    string
	Path    string
	context helpers.SuiteContext
	Service struct {
		Name            string `json:"name"`
		ID              string `json:"id"`
		DashboardClient struct {
			ID          string `json:"id"`
			Secret      string `json:"secret"`
			RedirectUri string `json:"redirect_uri"`
		}
	}
	SyncPlans  []Plan
	AsyncPlans []Plan
}

type ServicesResponse struct {
	Resources []ServiceResponse
}

type ServiceResponse struct {
	Entity struct {
		Label        string
		ServicePlans []ServicePlanResponse `json:"service_plans"`
	}
}

type ServicePlanResponse struct {
	Entity struct {
		Name   string
		Public bool
	}
	Metadata struct {
		Url  string
		Guid string
	}
}

type ServiceInstance struct {
	Metadata struct {
		Guid string `json:"guid"`
	}
}

type ServiceInstanceResponse struct {
	Resources []ServiceInstance
}

type SpaceJson struct {
	Resources []struct {
		Metadata struct {
			Guid string
		}
	}
}

func NewServiceBroker(name string, path string, context helpers.SuiteContext) ServiceBroker {
	b := ServiceBroker{}
	b.Path = path
	b.Name = name
	b.Service.Name = generator.RandomName()
	b.Service.ID = generator.RandomName()
	b.SyncPlans = []Plan{
		{Name: generator.RandomName(), ID: generator.RandomName()},
		{Name: generator.RandomName(), ID: generator.RandomName()},
	}
	b.AsyncPlans = []Plan{
		{Name: generator.RandomName(), ID: generator.RandomName()},
		{Name: generator.RandomName(), ID: generator.RandomName()},
	}
	b.Service.DashboardClient.ID = generator.RandomName()
	b.Service.DashboardClient.Secret = generator.RandomName()
	b.Service.DashboardClient.RedirectUri = generator.RandomName()
	b.context = context
	return b
}

func (b ServiceBroker) Push() {
	Expect(cf.Cf("push", b.Name, "-p", b.Path, "--no-start").Wait(BROKER_START_TIMEOUT)).To(Exit(0))
	if helpers.LoadConfig().UseDiego {
		appGuid := strings.TrimSpace(string(cf.Cf("app", b.Name, "--guid").Wait(DEFAULT_TIMEOUT).Out.Contents()))
		cf.Cf("curl",
			fmt.Sprintf("/v2/apps/%s", appGuid),
			"-X", "PUT",
			"-d", "{\"diego\": true}",
		).Wait(DEFAULT_TIMEOUT)
	}
	Expect(cf.Cf("start", b.Name).Wait(BROKER_START_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Configure() {
	Expect(runner.Curl(helpers.AppUri(b.Name, "/config"), "-d", b.ToJSON()).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Restart() {
	Expect(cf.Cf("restart", b.Name).Wait(BROKER_START_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) Create() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("create-service-broker", b.Name, "username", "password", helpers.AppUri(b.Name, "")).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("service-brokers").Wait(DEFAULT_TIMEOUT)).To(Say(b.Name))
	})
}

func (b ServiceBroker) Update() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("update-service-broker", b.Name, "username", "password", helpers.AppUri(b.Name, "")).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
}

func (b ServiceBroker) Delete() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("delete-service-broker", b.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))

		brokers := cf.Cf("service-brokers").Wait(DEFAULT_TIMEOUT)
		Expect(brokers).To(Exit(0))
		Expect(brokers.Out.Contents()).ToNot(ContainSubstring(b.Name))
	})
}

func (b ServiceBroker) Destroy() {
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("purge-service-offering", b.Service.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
	b.Delete()
	Expect(cf.Cf("delete", b.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
}

func (b ServiceBroker) ToJSON() string {
	bytes, err := ioutil.ReadFile(assets.NewAssets().ServiceBroker + "/cats.json")
	Expect(err).To(BeNil())

	replacer := strings.NewReplacer(
		"<fake-service>", b.Service.Name,
		"<fake-service-guid>", b.Service.ID,
		"<sso-test>", b.Service.DashboardClient.ID,
		"<sso-secret>", b.Service.DashboardClient.Secret,
		"<sso-redirect-uri>", b.Service.DashboardClient.RedirectUri,
		"<fake-plan>", b.SyncPlans[0].Name,
		"<fake-plan-guid>", b.SyncPlans[0].ID,
		"<fake-plan-2>", b.SyncPlans[1].Name,
		"<fake-plan-2-guid>", b.SyncPlans[1].ID,
		"<fake-async-plan>", b.AsyncPlans[0].Name,
		"<fake-async-plan-guid>", b.AsyncPlans[0].ID,
		"<fake-async-plan-2>", b.AsyncPlans[1].Name,
		"<fake-async-plan-2-guid>", b.AsyncPlans[1].ID,
	)

	return replacer.Replace(string(bytes))
}

func (b ServiceBroker) PublicizePlans() {
	url := fmt.Sprintf("/v2/services?inline-relations-depth=1&q=label:%s", b.Service.Name)
	var session *Session
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		session = cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
		Expect(session).To(Exit(0))
	})
	structure := ServicesResponse{}
	json.Unmarshal(session.Out.Contents(), &structure)

	for _, service := range structure.Resources {
		if service.Entity.Label == b.Service.Name {
			for _, plan := range service.Entity.ServicePlans {
				if b.HasPlan(plan.Entity.Name) {
					b.PublicizePlan(plan.Metadata.Url)
				}
			}
		}
	}
}

func (b ServiceBroker) HasPlan(planName string) bool {
	for _, plan := range b.Plans() {
		if plan.Name == planName {
			return true
		}
	}
	return false
}

func (b ServiceBroker) PublicizePlan(url string) {
	jsonMap := make(map[string]bool)
	jsonMap["public"] = true
	planJson, _ := json.Marshal(jsonMap)
	cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("curl", url, "-X", "PUT", "-d", string(planJson)).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})
}

func (b ServiceBroker) CreateServiceInstance(instanceName string) string {
	Expect(cf.Cf("create-service", b.Service.Name, b.SyncPlans[0].Name, instanceName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	url := fmt.Sprintf("/v2/service_instances?q=name:%s", instanceName)
	serviceInstance := ServiceInstanceResponse{}
	curl := cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
	json.Unmarshal(curl.Out.Contents(), &serviceInstance)
	return serviceInstance.Resources[0].Metadata.Guid
}

func (b ServiceBroker) GetSpaceGuid() string {
	url := fmt.Sprintf("/v2/spaces?q=name%%3A%s", b.context.RegularUserContext().Space)
	jsonResults := SpaceJson{}
	curl := cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT)
	Expect(curl).To(Exit(0))
	json.Unmarshal(curl.Out.Contents(), &jsonResults)
	return jsonResults.Resources[0].Metadata.Guid
}

func (b ServiceBroker) Plans() []Plan {
	plans := make([]Plan, 0)
	plans = append(plans, b.SyncPlans...)
	plans = append(plans, b.AsyncPlans...)
	return plans
}
<|endoftext|>


<commit_before>package eyego

import (
	"io"
	"encoding/hex"
	"fmt"
	"crypto/md5"
)

type ChecksumReader struct {
	delegate io.Reader
	buf [/*512*/]byte
	ptr int
	checksums []uint16
	self *ChecksumReader
}

func NewChecksumReader(r io.Reader) ChecksumReader {
	cr := ChecksumReader {
		delegate: r,
		ptr: 0,
		buf: make([]byte, 512),
		checksums: make([]uint16, 0, 16)}
	cr.self = &cr
	return cr
}

func (cr ChecksumReader) Read(p []byte) (n int, err error){
	n, err = cr.delegate.Read(p)

	if err == nil {
		cr.appendBytes(p, n)
	}

	return n, nil
}

func (cr ChecksumReader) Checksum(uploadKey string) string {

	b, _ := hex.DecodeString(uploadKey)

	if len(b) % 2 != 0 { panic("Bad upload key")}

	h := md5.New()

	for i := 0; i < len(cr.checksums); i++ {
		h.Write([]byte{
			byte(cr.checksums[i]),
			byte(cr.checksums[i] >> 8)})
	}

	h.Write(b)

	return fmt.Sprintf("%x", h.Sum(nil))
}

func (cr ChecksumReader) appendBytes(b []byte, len int) {

	cr = *cr.self
	if cr.ptr + len >= 512 {
		copy(cr.buf[cr.ptr:512], b[0:512-cr.ptr]) //copy bytes to fill temp buffer
		cr.checksums = append(cr.checksums, tcp_checksum(cr.buf))
		cr.buf = cr.buf[:0]
		copy(cr.buf, b[512-cr.ptr:len]) //copy remaining bytes
		cr.ptr = len - (512 - cr.ptr)
	} else { //
		copy(cr.buf[cr.ptr:cr.ptr+len], b[0:len])
		cr.ptr += len
	}
}

func tcp_checksum(b []byte) uint16 {
	if len(b) % 2 != 0 { panic(fmt.Sprintf("tcp checksum bad length: %d", len(b))) }

	var sum uint32 = 0
	var tmp uint16

	for c := 0; c < len(b); c = c + 2 {
		tmp = uint16(b[c]) | uint16(b[c+1]) << 8
		sum += uint32(tmp)
	}

	sum = (sum >> 16) + (sum & 0xffff)
	sum += (sum >> 16)
	return uint16(^sum)
}
<commit_msg>fixed err return<commit_after>package eyego

import (
	"io"
	"encoding/hex"
	"fmt"
	"crypto/md5"
)

type ChecksumReader struct {
	delegate io.Reader
	buf [/*512*/]byte
	ptr int
	checksums []uint16
	self *ChecksumReader
}

func NewChecksumReader(r io.Reader) ChecksumReader {
	cr := ChecksumReader {
		delegate: r,
		ptr: 0,
		buf: make([]byte, 512),
		checksums: make([]uint16, 0, 16)}
	cr.self = &cr
	return cr
}

func (cr ChecksumReader) Read(p []byte) (n int, err error){
	n, err = cr.delegate.Read(p)

	if err == nil {
		cr.appendBytes(p, n)
	}

	return n, err
}

func (cr ChecksumReader) Checksum(uploadKey string) string {

	b, _ := hex.DecodeString(uploadKey)

	if len(b) % 2 != 0 { panic("Bad upload key")}

	h := md5.New()

	for i := 0; i < len(cr.checksums); i++ {
		h.Write([]byte{
			byte(cr.checksums[i]),
			byte(cr.checksums[i] >> 8)})
	}

	h.Write(b)

	return fmt.Sprintf("%x", h.Sum(nil))
}

func (cr ChecksumReader) appendBytes(b []byte, len int) {

	cr = *cr.self
	if cr.ptr + len >= 512 {
		copy(cr.buf[cr.ptr:512], b[0:512-cr.ptr]) //copy bytes to fill temp buffer
		cr.checksums = append(cr.checksums, tcp_checksum(cr.buf))
		cr.buf = cr.buf[:0]
		copy(cr.buf, b[512-cr.ptr:len]) //copy remaining bytes
		cr.ptr = len - (512 - cr.ptr)
	} else { //
		copy(cr.buf[cr.ptr:cr.ptr+len], b[0:len])
		cr.ptr += len
	}
}

func tcp_checksum(b []byte) uint16 {
	if len(b) % 2 != 0 { panic(fmt.Sprintf("tcp checksum bad length: %d", len(b))) }

	var sum uint32 = 0
	var tmp uint16

	for c := 0; c < len(b); c = c + 2 {
		tmp = uint16(b[c]) | uint16(b[c+1]) << 8
		sum += uint32(tmp)
	}

	sum = (sum >> 16) + (sum & 0xffff)
	sum += (sum >> 16)
	return uint16(^sum)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/PreetamJinka/ethernetdecode"
	"github.com/PreetamJinka/sflow-go"

	"fmt"
	"net"
)

func main() {
	opened := 0
	closed := 0

	udpAddr, _ := net.ResolveUDPAddr("udp", ":6343")
	conn, err := net.ListenUDP("udp", udpAddr)

	fmt.Println(err)

	buf := make([]byte, 65535)

	for {
		n, _, err := conn.ReadFromUDP(buf)
		if err == nil {
			datagram := sflow.Decode(buf[0:n])
			for _, sample := range datagram.Samples {
				switch sample.SampleType() {
				case sflow.TypeFlowSample:
					fs := sample.(sflow.FlowSample)
					for _, record := range fs.Records {
						if record.RecordType() == sflow.TypeRawPacketFlow {
							r := record.(sflow.RawPacketFlowRecord)
							_, ipHdr, protoHdr := ethernetdecode.Decode(r.Header)
							if ipHdr != nil && ipHdr.IpVersion() == 4 {
								ipv4 := ipHdr.(ethernetdecode.Ipv4Header)
								switch protoHdr.Protocol() {
								case ethernetdecode.ProtocolTcp:
									tcp := protoHdr.(ethernetdecode.TcpHeader)

									// SYN+ACK flags
									if tcp.Flags&18 != 0 {
										opened++
									}

									// FIN+ACK flags
									if tcp.Flags&17 != 0 {
										closed++
									}
								case ethernetdecode.ProtocolUdp:

								}
								fmt.Printf("src: %v => dst: %v\n", net.IP(ipv4.Source[:]), net.IP(ipv4.Destination[:]))
								fmt.Printf("TCP connections opened: %d, closed: %d\n", opened, closed)
							}
						}
					}
				default:
				}
			}
		} else {
			fmt.Println(err)
		}
	}
}
<commit_msg>Fix connection open check<commit_after>package main

import (
	"github.com/PreetamJinka/ethernetdecode"
	"github.com/PreetamJinka/sflow-go"

	"fmt"
	"net"
)

func main() {
	opened := 0
	closed := 0

	udpAddr, _ := net.ResolveUDPAddr("udp", ":6343")
	conn, err := net.ListenUDP("udp", udpAddr)

	fmt.Println(err)

	buf := make([]byte, 65535)

	for {
		n, _, err := conn.ReadFromUDP(buf)
		if err == nil {
			datagram := sflow.Decode(buf[0:n])
			for _, sample := range datagram.Samples {
				switch sample.SampleType() {
				case sflow.TypeFlowSample:
					fs := sample.(sflow.FlowSample)
					for _, record := range fs.Records {
						if record.RecordType() == sflow.TypeRawPacketFlow {
							r := record.(sflow.RawPacketFlowRecord)
							_, ipHdr, protoHdr := ethernetdecode.Decode(r.Header)
							if ipHdr != nil && ipHdr.IpVersion() == 4 {
								ipv4 := ipHdr.(ethernetdecode.Ipv4Header)
								switch protoHdr.Protocol() {
								case ethernetdecode.ProtocolTcp:
									tcp := protoHdr.(ethernetdecode.TcpHeader)

									// SYN+ACK flags
									if tcp.Flags&3 == 2 {
										opened++
									}

									// FIN+ACK flags
									if tcp.Flags&17 != 0 {
										closed++
									}
								case ethernetdecode.ProtocolUdp:

								}
								fmt.Printf("src: %v => dst: %v\n", net.IP(ipv4.Source[:]), net.IP(ipv4.Destination[:]))
								fmt.Printf("TCP connections opened: %d, closed: %d\n", opened, closed)
							}
						}
					}
				default:
				}
			}
		} else {
			fmt.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 The SurgeMQ Authors. All rights reserved.
//
// 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 session

import (
	"crypto/rand"
	"encoding/base64"
	"errors"
	"github.com/troian/surgemq"
	"github.com/troian/surgemq/message"
	persistenceTypes "github.com/troian/surgemq/persistence/types"
	"github.com/troian/surgemq/systree"
	"github.com/troian/surgemq/topics"
	"github.com/troian/surgemq/types"
	"io"
	"net"
	"sync"
)

var (
	// ErrNotAccepted new connection does not meet requirements
	ErrNotAccepted = errors.New("Connection not accepted")

	// ErrDupNotAllowed case when new client with existing ID connected
	ErrDupNotAllowed = errors.New("duplicate not allowed")
)

// Config manager configuration
type Config struct {
	// Topics manager for all the client subscriptions
	TopicsMgr *topics.Manager

	// The number of seconds to wait for the CONNACK message before disconnecting.
	// If not set then default to 2 seconds.
	ConnectTimeout int

	// The number of seconds to wait for any ACK messages before failing.
	// If not set then default to 20 seconds.
	AckTimeout int

	// The number of times to retry sending a packet if ACK is not received.
	// If no set then default to 3 retries.
	TimeoutRetries int

	Metric struct {
		Packets  systree.PacketsMetric
		Sessions systree.SessionsStat
		Session  systree.SessionStat
	}

	OnDup types.DuplicateConfig

	Persist persistenceTypes.Sessions
}

type sessionsList struct {
	list  map[string]*Type
	lock  sync.RWMutex
	count sync.WaitGroup
}

// Manager interface
type Manager struct {
	config   Config
	sessions struct {
		active    sessionsList
		suspended sessionsList
	}
	lock sync.Mutex
	quit chan struct{}
}

// NewManager alloc new
func NewManager(cfg Config) (*Manager, error) {
	//if config.Stat == nil {
	//	return nil, errors.New("No stat provider")
	//}

	if cfg.Persist == nil {
		return nil, errors.New("No persist provider")
	}

	m := &Manager{
		config: cfg,
		quit:   make(chan struct{}),
	}

	m.sessions.active.list = make(map[string]*Type)
	m.sessions.suspended.list = make(map[string]*Type)

	// 1. load persisted sessions
	persistedSessions, err := m.config.Persist.GetAll()
	if err == nil {
		for _, s := range persistedSessions {
			// 2. restore only those having persisted subscriptions
			if subscriptions, err := s.Subscriptions().Get(); err == nil && len(subscriptions) > 0 {
				sCfg := config{
					topicsMgr:      m.config.TopicsMgr,
					connectTimeout: m.config.ConnectTimeout,
					ackTimeout:     m.config.AckTimeout,
					timeoutRetries: m.config.TimeoutRetries,
					subscriptions:  subscriptions,
					id:             s.ID(),
					callbacks: managerCallbacks{
						onDisconnect: m.onDisconnect,
						onClose:      m.onClose,
						onPublish:    m.onPublish,
					},
				}

				sCfg.metric.session = m.config.Metric.Session
				sCfg.metric.packets = m.config.Metric.Packets

				if ses, err := newSession(sCfg); err != nil {
					appLog.Errorf("Couldn't start persisted session [%s]: %s", s.ID(), err.Error())
				} else {
					m.sessions.suspended.list[s.ID()] = ses
					m.sessions.suspended.count.Add(1)
					if err = s.Subscriptions().Delete(); err != nil {
						appLog.Errorf("Couldn't wipe subscriptions after restore [%s]: %s", s.ID(), err.Error())
					}
				}
			}
		}
	}

	return m, nil
}

// Start try start new session
func (m *Manager) Start(msg *message.ConnectMessage, resp *message.ConnAckMessage, conn io.Closer) error {
	var err error
	var ses *Type
	present := false

	defer func() {
		resp.SetSessionPresent(present)

		if err = m.writeMessage(conn, resp); err != nil {
			appLog.Errorf("Couldn't write CONNACK: %s", err.Error())
		}
		if err == nil {
			if ses != nil {
				// try start session
				if err = ses.start(msg, conn); err != nil {
					// should never get into this section.
					// if so this code does not work as expected :)
					appLog.Errorf("Something really bad happened: %s", err.Error())
				}
			}
		}
	}()

	select {
	case <-m.quit:
		resp.SetReturnCode(message.ErrServerUnavailable)
		return errors.New("Not running")
	default:
	}

	if resp.ReturnCode() != message.ConnectionAccepted {
		return ErrNotAccepted
	}

	// serialize access to multiple starts
	defer m.lock.Unlock()
	m.lock.Lock()

	id := string(msg.ClientID())
	if len(id) == 0 {
		id = m.genSessionID()
	}

	m.sessions.active.lock.Lock()
	ses = m.sessions.active.list[id]

	// there is no such active session
	// proceed to either persisted or new one
	if ses == nil {
		ses, present, err = m.allocSession(id, msg, resp)
	} else {
		replaced := true
		// session already exists thus duplicate case happened
		if !m.config.OnDup.Replace {
			// duplicate prohibited. send identifier rejected
			resp.SetReturnCode(message.ErrIdentifierRejected)
			err = ErrDupNotAllowed
			replaced = false
		} else {
			// duplicate allowed stop current session
			m.sessions.active.lock.Unlock()
			ses.stop()
			m.sessions.active.lock.Lock()

			// previous session stopped
			// lets create new one
			ses, present, err = m.allocSession(id, msg, resp)
		}

		// notify subscriber about dup attempt
		if m.config.OnDup.OnAttempt != nil {
			m.config.OnDup.OnAttempt(id, replaced)
		}
	}

	m.sessions.active.lock.Unlock()

	return nil
}

// Shutdown manager
func (m *Manager) Shutdown() error {
	defer m.lock.Unlock()
	m.lock.Lock()

	select {
	case <-m.quit:
		return errors.New("already stopped")
	default:
	}

	close(m.quit)

	// 1. Now signal all active sessions to finish
	m.sessions.active.lock.Lock()
	for _, s := range m.sessions.active.list {
		s.stop()
	}
	m.sessions.active.lock.Unlock()

	// 2. Wait until all active sessions stopped
	m.sessions.active.count.Wait()

	// 3. wipe list
	m.sessions.active.list = make(map[string]*Type)

	// 4. Signal suspended sessions to exit
	for _, s := range m.sessions.suspended.list {
		s.stop()
	}

	// 2. Wait until suspended sessions stopped
	m.sessions.suspended.count.Wait()

	// 4. wipe list
	m.sessions.suspended.list = make(map[string]*Type)

	return nil
}

func (m *Manager) genSessionID() string {
	b := make([]byte, 15)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}

	return base64.URLEncoding.EncodeToString(b)
}

func (m *Manager) allocSession(id string, msg *message.ConnectMessage, resp *message.ConnAckMessage) (*Type, bool, error) {
	var ses *Type
	present := false
	var err error

	sConfig := config{
		topicsMgr:      m.config.TopicsMgr,
		connectTimeout: m.config.ConnectTimeout,
		ackTimeout:     m.config.AckTimeout,
		timeoutRetries: m.config.TimeoutRetries,
		subscriptions:  make(message.TopicsQoS),
		id:             id,
		callbacks: managerCallbacks{
			onDisconnect: m.onDisconnect,
			onClose:      m.onClose,
			onPublish:    m.onPublish,
		},
	}

	sConfig.metric.session = m.config.Metric.Session
	sConfig.metric.packets = m.config.Metric.Packets

	var pSes persistenceTypes.Session

	// if session is non-clean look for persistence
	if !msg.CleanSession() {
		// 1. search over suspended sessions with active subscriptions
		m.sessions.suspended.lock.Lock()
		if s, ok := m.sessions.suspended.list[id]; ok {
			// session exists. acquire it
			delete(m.sessions.suspended.list, id)
			m.sessions.suspended.count.Done()

			ses = s
			present = true

			// do not check error here.
			// if session has not been found there is no any persisted messages for it
			pSes, _ = m.config.Persist.Get(id)
		} else {
			// no such session in persisted list. It might be shutdown
			if pSes, err = m.config.Persist.Get(id); err != nil {
				// No such session exists at all. Just create new
				appLog.Debugf("Create new persist entry for [%s]", id)
				if _, err = m.config.Persist.New(id); err != nil {
					appLog.Errorf("Couldn't create persis object for session [%s]: %s", id, err.Error())
				}
			} else {
				// Session exists and is in shutdown state
				appLog.Debugf("Restore session [%s] from shutdown", id)
				present = true
			}
		}

		m.sessions.suspended.lock.Unlock()
	} else {
		// Session might change from non-clean to clean state
		// if so make sure it does not exists in persistence db
		// check if it was suspended
		m.sessions.suspended.lock.Lock()
		if suspended, ok := m.sessions.suspended.list[id]; ok {
			suspended.stop()
			delete(m.sessions.suspended.list, id)
		}
		m.sessions.suspended.lock.Unlock()
		if err = m.config.Persist.Delete(id); err != nil {
			appLog.Tracef("Couldn't wipe session after restore [%s]: %s", id, err.Error())
		}
	}

	if ses == nil {
		if ses, err = newSession(sConfig); err != nil {
			ses = nil
			resp.SetReturnCode(message.ErrServerUnavailable)
			if !msg.CleanSession() {
				if err = m.config.Persist.Delete(id); err != nil {
					appLog.Errorf("Couldn't wipe session after restore [%s]: %s", id, err.Error())
				}
			}
		}
	}

	if ses != nil {
		// restore messages if it was shutdown non-clean session
		if pSes != nil {
			if msg, err := pSes.Messages().Load(); err == nil {
				ses.restore(&msg)
				if err = pSes.Messages().Delete(); err != nil {
					appLog.Errorf("Couldn't wipe messages after restore [%s]: %s", id, err.Error())
				}
			}
		}

		m.sessions.active.list[id] = ses
		m.sessions.active.count.Add(1)
	}

	return ses, present, err
}

// close is only invoked for non-clean session
func (m *Manager) onClose(id string, s message.TopicsQoS) {
	defer m.sessions.suspended.count.Done()

	ses, err := m.config.Persist.Get(id)
	if err != nil {
		appLog.Errorf("Trying to persist session that has not been initiated for persistence [%s]: %s", id, err.Error())
	} else {
		if err = ses.Subscriptions().Add(s); err != nil {
			appLog.Errorf("Couldn't persist subscriptions [%s]: %s", id, err.Error())
		}
	}
}

func (m *Manager) onPublish(id string, msg *message.PublishMessage) {
	if ses, err := m.config.Persist.Get(id); err == nil {
		if err = ses.Messages().Store("out", []message.Provider{msg}); err != nil {
			appLog.Errorf("Couldn't store messages [%s]: %s", id, err.Error())
		}
	} else {
		appLog.Errorf("Couldn't persist message for shutdown session [%s]: %s", id, err.Error())
	}
}

func (m *Manager) onDisconnect(id string, messages *persistenceTypes.SessionMessages, shutdown bool) {
	defer m.sessions.active.count.Done()

	if messages != nil {
		if ses, err := m.config.Persist.Get(id); err != nil {
			appLog.Errorf("Trying to persist session that has not been initiated for persistence [%s]: %s", id, err.Error())
		} else {
			if len(messages.Out.Messages) > 0 {
				if err = ses.Messages().Store("out", messages.Out.Messages); err != nil {
					appLog.Errorf("Couldn't persist messages [%s]: %s", id, err.Error())
				}
			}

			if len(messages.In.Messages) > 0 {
				if err = ses.Messages().Store("in", messages.In.Messages); err != nil {
					appLog.Errorf("Couldn't persist messages [%s]: %s", id, err.Error())
				}
			}
		}

		if !shutdown {
			// copy session to persisted list
			m.sessions.suspended.lock.Lock()
			m.sessions.active.lock.Lock()
			m.sessions.suspended.list[id] = m.sessions.active.list[id]
			m.sessions.active.lock.Unlock()
			m.sessions.suspended.lock.Unlock()
			m.sessions.suspended.count.Add(1)
		}
	}

	select {
	case <-m.quit:
		// if manager is about to shutdown do nothing
	default:
		m.sessions.active.lock.Lock()
		delete(m.sessions.active.list, id)
		m.sessions.active.lock.Unlock()
	}
}

// WriteMessage into connection
func (m *Manager) writeMessage(conn io.Closer, msg message.Provider) error {
	buf := make([]byte, msg.Len())
	_, err := msg.Encode(buf)
	if err != nil {
		appLog.Debugf("Write error: %v", err)
		return err
	}
	appLog.Debugf("Writing: %s", msg)

	return m.writeMessageBuffer(conn, buf)
}

func (m *Manager) writeMessageBuffer(c io.Closer, b []byte) error {
	if c == nil {
		return surgemq.ErrInvalidConnectionType
	}

	conn, ok := c.(net.Conn)
	if !ok {
		return surgemq.ErrInvalidConnectionType
	}

	_, err := conn.Write(b)
	return err
}
<commit_msg>Fix var shadow<commit_after>// Copyright (c) 2014 The SurgeMQ Authors. All rights reserved.
//
// 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 session

import (
	"crypto/rand"
	"encoding/base64"
	"errors"
	"github.com/troian/surgemq"
	"github.com/troian/surgemq/message"
	persistenceTypes "github.com/troian/surgemq/persistence/types"
	"github.com/troian/surgemq/systree"
	"github.com/troian/surgemq/topics"
	"github.com/troian/surgemq/types"
	"io"
	"net"
	"sync"
)

var (
	// ErrNotAccepted new connection does not meet requirements
	ErrNotAccepted = errors.New("Connection not accepted")

	// ErrDupNotAllowed case when new client with existing ID connected
	ErrDupNotAllowed = errors.New("duplicate not allowed")
)

// Config manager configuration
type Config struct {
	// Topics manager for all the client subscriptions
	TopicsMgr *topics.Manager

	// The number of seconds to wait for the CONNACK message before disconnecting.
	// If not set then default to 2 seconds.
	ConnectTimeout int

	// The number of seconds to wait for any ACK messages before failing.
	// If not set then default to 20 seconds.
	AckTimeout int

	// The number of times to retry sending a packet if ACK is not received.
	// If no set then default to 3 retries.
	TimeoutRetries int

	Metric struct {
		Packets  systree.PacketsMetric
		Sessions systree.SessionsStat
		Session  systree.SessionStat
	}

	OnDup types.DuplicateConfig

	Persist persistenceTypes.Sessions
}

type sessionsList struct {
	list  map[string]*Type
	lock  sync.RWMutex
	count sync.WaitGroup
}

// Manager interface
type Manager struct {
	config   Config
	sessions struct {
		active    sessionsList
		suspended sessionsList
	}
	lock sync.Mutex
	quit chan struct{}
}

// NewManager alloc new
func NewManager(cfg Config) (*Manager, error) {
	//if config.Stat == nil {
	//	return nil, errors.New("No stat provider")
	//}

	if cfg.Persist == nil {
		return nil, errors.New("No persist provider")
	}

	m := &Manager{
		config: cfg,
		quit:   make(chan struct{}),
	}

	m.sessions.active.list = make(map[string]*Type)
	m.sessions.suspended.list = make(map[string]*Type)

	// 1. load persisted sessions
	persistedSessions, err := m.config.Persist.GetAll()
	if err == nil {
		for _, s := range persistedSessions {
			// 2. restore only those having persisted subscriptions
			if subscriptions, err := s.Subscriptions().Get(); err == nil && len(subscriptions) > 0 {
				sCfg := config{
					topicsMgr:      m.config.TopicsMgr,
					connectTimeout: m.config.ConnectTimeout,
					ackTimeout:     m.config.AckTimeout,
					timeoutRetries: m.config.TimeoutRetries,
					subscriptions:  subscriptions,
					id:             s.ID(),
					callbacks: managerCallbacks{
						onDisconnect: m.onDisconnect,
						onClose:      m.onClose,
						onPublish:    m.onPublish,
					},
				}

				sCfg.metric.session = m.config.Metric.Session
				sCfg.metric.packets = m.config.Metric.Packets

				if ses, err := newSession(sCfg); err != nil {
					appLog.Errorf("Couldn't start persisted session [%s]: %s", s.ID(), err.Error())
				} else {
					m.sessions.suspended.list[s.ID()] = ses
					m.sessions.suspended.count.Add(1)
					if err = s.Subscriptions().Delete(); err != nil {
						appLog.Errorf("Couldn't wipe subscriptions after restore [%s]: %s", s.ID(), err.Error())
					}
				}
			}
		}
	}

	return m, nil
}

// Start try start new session
func (m *Manager) Start(msg *message.ConnectMessage, resp *message.ConnAckMessage, conn io.Closer) error {
	var err error
	var ses *Type
	present := false

	defer func() {
		resp.SetSessionPresent(present)

		if err = m.writeMessage(conn, resp); err != nil {
			appLog.Errorf("Couldn't write CONNACK: %s", err.Error())
		}
		if err == nil {
			if ses != nil {
				// try start session
				if err = ses.start(msg, conn); err != nil {
					// should never get into this section.
					// if so this code does not work as expected :)
					appLog.Errorf("Something really bad happened: %s", err.Error())
				}
			}
		}
	}()

	select {
	case <-m.quit:
		resp.SetReturnCode(message.ErrServerUnavailable)
		return errors.New("Not running")
	default:
	}

	if resp.ReturnCode() != message.ConnectionAccepted {
		return ErrNotAccepted
	}

	// serialize access to multiple starts
	defer m.lock.Unlock()
	m.lock.Lock()

	id := string(msg.ClientID())
	if len(id) == 0 {
		id = m.genSessionID()
	}

	m.sessions.active.lock.Lock()
	ses = m.sessions.active.list[id]

	// there is no such active session
	// proceed to either persisted or new one
	if ses == nil {
		ses, present, err = m.allocSession(id, msg, resp)
	} else {
		replaced := true
		// session already exists thus duplicate case happened
		if !m.config.OnDup.Replace {
			// duplicate prohibited. send identifier rejected
			resp.SetReturnCode(message.ErrIdentifierRejected)
			err = ErrDupNotAllowed
			replaced = false
		} else {
			// duplicate allowed stop current session
			m.sessions.active.lock.Unlock()
			ses.stop()
			m.sessions.active.lock.Lock()

			// previous session stopped
			// lets create new one
			ses, present, err = m.allocSession(id, msg, resp)
		}

		// notify subscriber about dup attempt
		if m.config.OnDup.OnAttempt != nil {
			m.config.OnDup.OnAttempt(id, replaced)
		}
	}

	m.sessions.active.lock.Unlock()

	return nil
}

// Shutdown manager
func (m *Manager) Shutdown() error {
	defer m.lock.Unlock()
	m.lock.Lock()

	select {
	case <-m.quit:
		return errors.New("already stopped")
	default:
	}

	close(m.quit)

	// 1. Now signal all active sessions to finish
	m.sessions.active.lock.Lock()
	for _, s := range m.sessions.active.list {
		s.stop()
	}
	m.sessions.active.lock.Unlock()

	// 2. Wait until all active sessions stopped
	m.sessions.active.count.Wait()

	// 3. wipe list
	m.sessions.active.list = make(map[string]*Type)

	// 4. Signal suspended sessions to exit
	for _, s := range m.sessions.suspended.list {
		s.stop()
	}

	// 2. Wait until suspended sessions stopped
	m.sessions.suspended.count.Wait()

	// 4. wipe list
	m.sessions.suspended.list = make(map[string]*Type)

	return nil
}

func (m *Manager) genSessionID() string {
	b := make([]byte, 15)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}

	return base64.URLEncoding.EncodeToString(b)
}

func (m *Manager) allocSession(id string, msg *message.ConnectMessage, resp *message.ConnAckMessage) (*Type, bool, error) {
	var ses *Type
	present := false
	var err error

	sConfig := config{
		topicsMgr:      m.config.TopicsMgr,
		connectTimeout: m.config.ConnectTimeout,
		ackTimeout:     m.config.AckTimeout,
		timeoutRetries: m.config.TimeoutRetries,
		subscriptions:  make(message.TopicsQoS),
		id:             id,
		callbacks: managerCallbacks{
			onDisconnect: m.onDisconnect,
			onClose:      m.onClose,
			onPublish:    m.onPublish,
		},
	}

	sConfig.metric.session = m.config.Metric.Session
	sConfig.metric.packets = m.config.Metric.Packets

	var pSes persistenceTypes.Session

	// if session is non-clean look for persistence
	if !msg.CleanSession() {
		// 1. search over suspended sessions with active subscriptions
		m.sessions.suspended.lock.Lock()
		if s, ok := m.sessions.suspended.list[id]; ok {
			// session exists. acquire it
			delete(m.sessions.suspended.list, id)
			m.sessions.suspended.count.Done()

			ses = s
			present = true

			// do not check error here.
			// if session has not been found there is no any persisted messages for it
			pSes, _ = m.config.Persist.Get(id)
		} else {
			// no such session in persisted list. It might be shutdown
			if pSes, err = m.config.Persist.Get(id); err != nil {
				// No such session exists at all. Just create new
				appLog.Debugf("Create new persist entry for [%s]", id)
				if _, err = m.config.Persist.New(id); err != nil {
					appLog.Errorf("Couldn't create persis object for session [%s]: %s", id, err.Error())
				}
			} else {
				// Session exists and is in shutdown state
				appLog.Debugf("Restore session [%s] from shutdown", id)
				present = true
			}
		}

		m.sessions.suspended.lock.Unlock()
	} else {
		// Session might change from non-clean to clean state
		// if so make sure it does not exists in persistence db
		// check if it was suspended
		m.sessions.suspended.lock.Lock()
		if suspended, ok := m.sessions.suspended.list[id]; ok {
			suspended.stop()
			delete(m.sessions.suspended.list, id)
		}
		m.sessions.suspended.lock.Unlock()
		if err = m.config.Persist.Delete(id); err != nil {
			appLog.Tracef("Couldn't wipe session after restore [%s]: %s", id, err.Error())
		}
	}

	if ses == nil {
		if ses, err = newSession(sConfig); err != nil {
			ses = nil
			resp.SetReturnCode(message.ErrServerUnavailable)
			if !msg.CleanSession() {
				if err = m.config.Persist.Delete(id); err != nil {
					appLog.Errorf("Couldn't wipe session after restore [%s]: %s", id, err.Error())
				}
			}
		}
	}

	if ses != nil {
		// restore messages if it was shutdown non-clean session
		if pSes != nil {
			var storedMessages persistenceTypes.SessionMessages
			if storedMessages, err = pSes.Messages().Load(); err == nil {
				ses.restore(&storedMessages)
				if err = pSes.Messages().Delete(); err != nil {
					appLog.Errorf("Couldn't wipe messages after restore [%s]: %s", id, err.Error())
				}
			}
		}

		m.sessions.active.list[id] = ses
		m.sessions.active.count.Add(1)
	}

	return ses, present, err
}

// close is only invoked for non-clean session
func (m *Manager) onClose(id string, s message.TopicsQoS) {
	defer m.sessions.suspended.count.Done()

	ses, err := m.config.Persist.Get(id)
	if err != nil {
		appLog.Errorf("Trying to persist session that has not been initiated for persistence [%s]: %s", id, err.Error())
	} else {
		if err = ses.Subscriptions().Add(s); err != nil {
			appLog.Errorf("Couldn't persist subscriptions [%s]: %s", id, err.Error())
		}
	}
}

func (m *Manager) onPublish(id string, msg *message.PublishMessage) {
	if ses, err := m.config.Persist.Get(id); err == nil {
		if err = ses.Messages().Store("out", []message.Provider{msg}); err != nil {
			appLog.Errorf("Couldn't store messages [%s]: %s", id, err.Error())
		}
	} else {
		appLog.Errorf("Couldn't persist message for shutdown session [%s]: %s", id, err.Error())
	}
}

func (m *Manager) onDisconnect(id string, messages *persistenceTypes.SessionMessages, shutdown bool) {
	defer m.sessions.active.count.Done()

	if messages != nil {
		if ses, err := m.config.Persist.Get(id); err != nil {
			appLog.Errorf("Trying to persist session that has not been initiated for persistence [%s]: %s", id, err.Error())
		} else {
			if len(messages.Out.Messages) > 0 {
				if err = ses.Messages().Store("out", messages.Out.Messages); err != nil {
					appLog.Errorf("Couldn't persist messages [%s]: %s", id, err.Error())
				}
			}

			if len(messages.In.Messages) > 0 {
				if err = ses.Messages().Store("in", messages.In.Messages); err != nil {
					appLog.Errorf("Couldn't persist messages [%s]: %s", id, err.Error())
				}
			}
		}

		if !shutdown {
			// copy session to persisted list
			m.sessions.suspended.lock.Lock()
			m.sessions.active.lock.Lock()
			m.sessions.suspended.list[id] = m.sessions.active.list[id]
			m.sessions.active.lock.Unlock()
			m.sessions.suspended.lock.Unlock()
			m.sessions.suspended.count.Add(1)
		}
	}

	select {
	case <-m.quit:
		// if manager is about to shutdown do nothing
	default:
		m.sessions.active.lock.Lock()
		delete(m.sessions.active.list, id)
		m.sessions.active.lock.Unlock()
	}
}

// WriteMessage into connection
func (m *Manager) writeMessage(conn io.Closer, msg message.Provider) error {
	buf := make([]byte, msg.Len())
	_, err := msg.Encode(buf)
	if err != nil {
		appLog.Debugf("Write error: %v", err)
		return err
	}
	appLog.Debugf("Writing: %s", msg)

	return m.writeMessageBuffer(conn, buf)
}

func (m *Manager) writeMessageBuffer(c io.Closer, b []byte) error {
	if c == nil {
		return surgemq.ErrInvalidConnectionType
	}

	conn, ok := c.(net.Conn)
	if !ok {
		return surgemq.ErrInvalidConnectionType
	}

	_, err := conn.Write(b)
	return err
}
<|endoftext|>


<commit_before>package ssh

import (
	"fmt"
	"regexp"
	"time"

	"github.com/blacknon/lssh/conf"
	"github.com/shavac/gexpect"
)

// OS ssh command Rapper
func ConnectSsh(connectServer string, serverList conf.Config) {
	connectUser := serverList.Server[connectServer].User
	connectAddr := serverList.Server[connectServer].Addr
	var connectPort string
	if serverList.Server[connectServer].Port == "" {
		connectPort = "22"
	} else {
		connectPort = serverList.Server[connectServer].Port
	}
	connectPass := serverList.Server[connectServer].Pass
	connectKey := serverList.Server[connectServer].Key

	connectHost := connectUser + "@" + connectAddr

	if connectKey != "" {
		//child, _ := gexpect.NewSubProcess("/usr/bin/ssh", "-i", connectKey, connectHost, "-p", connectPort)
		child, _ := gexpect.NewSubProcess("/usr/bin/ssh", "-o", "StrictHostKeyChecking=no", "-i", connectKey, connectHost, "-p", connectPort)
		if err := child.Start(); err != nil {
			fmt.Println(err)
		}
		defer child.Close()

		child.InteractTimeout(86400 * time.Second)
	} else {
		//child, _ := gexpect.NewSubProcess("/usr/bin/ssh", connectHost, "-p", connectPort)
		child, _ := gexpect.NewSubProcess("/usr/bin/ssh", "-o", "StrictHostKeyChecking=no", connectHost, "-p", connectPort)
		if err := child.Start(); err != nil {
			fmt.Println(err)
		}
		defer child.Close()
		if connectPass != "" {
			if idx, _ := child.ExpectTimeout(20*time.Second, regexp.MustCompile("word:")); idx >= 0 {
				child.SendLine(connectPass)
			}
		}
		child.InteractTimeout(86400 * time.Second)
	}
}
<commit_msg>ssh command refact<commit_after>package ssh

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/blacknon/lssh/conf"
	"github.com/shavac/gexpect"
)

// OS ssh command Rapper
func ConnectSsh(connectServer string, serverList conf.Config) {
	connectUser := serverList.Server[connectServer].User
	connectAddr := serverList.Server[connectServer].Addr
	var connectPort string
	if serverList.Server[connectServer].Port == "" {
		connectPort = "22"
	} else {
		connectPort = serverList.Server[connectServer].Port
	}
	connectPass := serverList.Server[connectServer].Pass
	connectKey := serverList.Server[connectServer].Key
	connectHost := connectUser + "@" + connectAddr

	// ssh command Args
	connectArgStr := ""
	if connectKey != "" {
		connectArgStr = "-i " + connectKey + " " + connectHost + " -p " + connectPort
	} else {
		connectArgStr = connectHost + " -p " + connectPort
	}
	connectArgMap := strings.Split(connectArgStr, " ")

	// exec ssh command
	child, _ := gexpect.NewSubProcess("/usr/bin/ssh", connectArgMap...)
	if err := child.Start(); err != nil {
		fmt.Println(err)
	}
	defer child.Close()

	// Password Input
	if connectPass != "" {
		if idx, _ := child.ExpectTimeout(20*time.Second, regexp.MustCompile("word:")); idx >= 0 {
			child.SendLine(connectPass)
		}
	}

	// timeout
	child.InteractTimeout(86400 * time.Second)

}
<|endoftext|>


<commit_before>// Copyright (c) nano Author. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package session

import (
	"errors"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/lonnng/nano/service"
)

//  NetworkEntity represent low-level network instance
type NetworkEntity interface {
	Push(route string, v interface{}) error
	Response(v interface{}) error
	Close() error
	RemoteAddr() net.Addr
}

var (
	//ErrIllegalUID represents a invalid uid
	ErrIllegalUID = errors.New("illegal uid")
)

// Session represents a client session which could storage temp data during low-level
// keep connected, all data will be released when the low-level connection was broken.
// Session instance related to the client will be passed to Handler method as the first
// parameter.
type Session struct {
	sync.RWMutex                        // protect data
	id           int64                  // session global unique id
	uid          int64                  // binding user id
	LastRID      uint                   // last request id
	lastTime     int64                  // last heartbeat time
	entity       NetworkEntity          // low-level network entity
	data         map[string]interface{} // session data store
}

// New returns a new session instance
// a NetworkEntity represent low-level network instance
func New(entity NetworkEntity) *Session {
	return &Session{
		id:       service.Connections.SessionID(),
		entity:   entity,
		data:     make(map[string]interface{}),
		lastTime: time.Now().Unix(),
	}
}

// Push message to client
func (s *Session) Push(route string, v interface{}) error {
	return s.entity.Push(route, v)
}

// Response message to client
func (s *Session) Response(v interface{}) error {
	return s.entity.Response(v)
}

// ID returns the session id
func (s *Session) ID() int64 {
	return s.id
}

// Uid returns UID that bind to current session
func (s *Session) Uid() int64 {
	return atomic.LoadInt64(&s.uid)
}

// Bind bind UID to current session
func (s *Session) Bind(uid int64) error {
	if uid < 1 {
		return ErrIllegalUID
	}

	atomic.StoreInt64(&s.uid, uid)
	return nil
}

// Close terminate current session, session related data will not be released,
// all related data should be Clear explicitly in Session closed callback
func (s *Session) Close() {
	s.entity.Close()
}

// RemoteAddr returns the remote network address.
func (s *Session) RemoteAddr() net.Addr {
	return s.entity.RemoteAddr()
}

// Remove delete data associated with the key from session storage
func (s *Session) Remove(key string) {
	s.Lock()
	defer s.Unlock()

	delete(s.data, key)
}

// Set associates value with the key in session storage
func (s *Session) Set(key string, value interface{}) {
	s.Lock()
	defer s.Unlock()

	s.data[key] = value
}

// HasKey decides whether a key has associated value
func (s *Session) HasKey(key string) bool {
	s.RLock()
	defer s.RUnlock()

	_, has := s.data[key]
	return has
}

// Int returns the value associated with the key as a int.
func (s *Session) Int(key string) int {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int)
	if !ok {
		return 0
	}
	return value
}

// Int8 returns the value associated with the key as a int8.
func (s *Session) Int8(key string) int8 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int8)
	if !ok {
		return 0
	}
	return value
}

// Int16 returns the value associated with the key as a int16.
func (s *Session) Int16(key string) int16 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int16)
	if !ok {
		return 0
	}
	return value
}

// Int32 returns the value associated with the key as a int32.
func (s *Session) Int32(key string) int32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int32)
	if !ok {
		return 0
	}
	return value
}

// Int64 returns the value associated with the key as a int64.
func (s *Session) Int64(key string) int64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int64)
	if !ok {
		return 0
	}
	return value
}

// Uint returns the value associated with the key as a uint.
func (s *Session) Uint(key string) uint {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint)
	if !ok {
		return 0
	}
	return value
}

// Uint8 returns the value associated with the key as a uint8.
func (s *Session) Uint8(key string) uint8 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint8)
	if !ok {
		return 0
	}
	return value
}

// Uint16 returns the value associated with the key as a uint16.
func (s *Session) Uint16(key string) uint16 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint16)
	if !ok {
		return 0
	}
	return value
}

// Uint32 returns the value associated with the key as a uint32.
func (s *Session) Uint32(key string) uint32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint32)
	if !ok {
		return 0
	}
	return value
}

// Uint64 returns the value associated with the key as a uint64.
func (s *Session) Uint64(key string) uint64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint64)
	if !ok {
		return 0
	}
	return value
}

// Float32 returns the value associated with the key as a float32.
func (s *Session) Float32(key string) float32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(float32)
	if !ok {
		return 0
	}
	return value
}

// Float64 returns the value associated with the key as a float64.
func (s *Session) Float64(key string) float64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(float64)
	if !ok {
		return 0
	}
	return value
}

// String returns the value associated with the key as a string.
func (s *Session) String(key string) string {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return ""
	}

	value, ok := v.(string)
	if !ok {
		return ""
	}
	return value
}

// String returns the value associated with the key as a interface{}.
func (s *Session) Value(key string) interface{} {
	s.RLock()
	defer s.RUnlock()

	return s.data[key]
}

// State returns all session state
func (s *Session) State() map[string]interface{} {
	s.RLock()
	defer s.RUnlock()

	return s.data
}

// Restore session state after reconnect
func (s *Session) Restore(data map[string]interface{}) {
	s.data = data
}

// Clear releases all data related to current session
func (s *Session) Clear() {
	s.Lock()
	defer s.Unlock()

	s.uid = 0
	s.data = map[string]interface{}{}
}
<commit_msg>more comments<commit_after>// Copyright (c) nano Author. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package session

import (
	"errors"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/lonnng/nano/service"
)

// NetworkEntity represent low-level network instance
type NetworkEntity interface {
	Push(route string, v interface{}) error
	Response(v interface{}) error
	Close() error
	RemoteAddr() net.Addr
}

var (
	//ErrIllegalUID represents a invalid uid
	ErrIllegalUID = errors.New("illegal uid")
)

// Session represents a client session which could storage temp data during low-level
// keep connected, all data will be released when the low-level connection was broken.
// Session instance related to the client will be passed to Handler method as the first
// parameter.
type Session struct {
	sync.RWMutex                        // protect data
	id           int64                  // session global unique id
	uid          int64                  // binding user id
	LastRID      uint                   // last request id
	lastTime     int64                  // last heartbeat time
	entity       NetworkEntity          // low-level network entity
	data         map[string]interface{} // session data store
}

// New returns a new session instance
// a NetworkEntity represent low-level network instance
func New(entity NetworkEntity) *Session {
	return &Session{
		id:       service.Connections.SessionID(),
		entity:   entity,
		data:     make(map[string]interface{}),
		lastTime: time.Now().Unix(),
	}
}

// Push message to client
func (s *Session) Push(route string, v interface{}) error {
	return s.entity.Push(route, v)
}

// Response message to client
func (s *Session) Response(v interface{}) error {
	return s.entity.Response(v)
}

// ID returns the session id
func (s *Session) ID() int64 {
	return s.id
}

// Uid returns UID that bind to current session
func (s *Session) Uid() int64 {
	return atomic.LoadInt64(&s.uid)
}

// Bind bind UID to current session
func (s *Session) Bind(uid int64) error {
	if uid < 1 {
		return ErrIllegalUID
	}

	atomic.StoreInt64(&s.uid, uid)
	return nil
}

// Close terminate current session, session related data will not be released,
// all related data should be Clear explicitly in Session closed callback
func (s *Session) Close() {
	s.entity.Close()
}

// RemoteAddr returns the remote network address.
func (s *Session) RemoteAddr() net.Addr {
	return s.entity.RemoteAddr()
}

// Remove delete data associated with the key from session storage
func (s *Session) Remove(key string) {
	s.Lock()
	defer s.Unlock()

	delete(s.data, key)
}

// Set associates value with the key in session storage
func (s *Session) Set(key string, value interface{}) {
	s.Lock()
	defer s.Unlock()

	s.data[key] = value
}

// HasKey decides whether a key has associated value
func (s *Session) HasKey(key string) bool {
	s.RLock()
	defer s.RUnlock()

	_, has := s.data[key]
	return has
}

// Int returns the value associated with the key as a int.
func (s *Session) Int(key string) int {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int)
	if !ok {
		return 0
	}
	return value
}

// Int8 returns the value associated with the key as a int8.
func (s *Session) Int8(key string) int8 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int8)
	if !ok {
		return 0
	}
	return value
}

// Int16 returns the value associated with the key as a int16.
func (s *Session) Int16(key string) int16 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int16)
	if !ok {
		return 0
	}
	return value
}

// Int32 returns the value associated with the key as a int32.
func (s *Session) Int32(key string) int32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int32)
	if !ok {
		return 0
	}
	return value
}

// Int64 returns the value associated with the key as a int64.
func (s *Session) Int64(key string) int64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(int64)
	if !ok {
		return 0
	}
	return value
}

// Uint returns the value associated with the key as a uint.
func (s *Session) Uint(key string) uint {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint)
	if !ok {
		return 0
	}
	return value
}

// Uint8 returns the value associated with the key as a uint8.
func (s *Session) Uint8(key string) uint8 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint8)
	if !ok {
		return 0
	}
	return value
}

// Uint16 returns the value associated with the key as a uint16.
func (s *Session) Uint16(key string) uint16 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint16)
	if !ok {
		return 0
	}
	return value
}

// Uint32 returns the value associated with the key as a uint32.
func (s *Session) Uint32(key string) uint32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint32)
	if !ok {
		return 0
	}
	return value
}

// Uint64 returns the value associated with the key as a uint64.
func (s *Session) Uint64(key string) uint64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(uint64)
	if !ok {
		return 0
	}
	return value
}

// Float32 returns the value associated with the key as a float32.
func (s *Session) Float32(key string) float32 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(float32)
	if !ok {
		return 0
	}
	return value
}

// Float64 returns the value associated with the key as a float64.
func (s *Session) Float64(key string) float64 {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return 0
	}

	value, ok := v.(float64)
	if !ok {
		return 0
	}
	return value
}

// String returns the value associated with the key as a string.
func (s *Session) String(key string) string {
	s.RLock()
	defer s.RUnlock()

	v, ok := s.data[key]
	if !ok {
		return ""
	}

	value, ok := v.(string)
	if !ok {
		return ""
	}
	return value
}

// Value returns the value associated with the key as a interface{}.
func (s *Session) Value(key string) interface{} {
	s.RLock()
	defer s.RUnlock()

	return s.data[key]
}

// State returns all session state
func (s *Session) State() map[string]interface{} {
	s.RLock()
	defer s.RUnlock()

	return s.data
}

// Restore session state after reconnect
func (s *Session) Restore(data map[string]interface{}) {
	s.data = data
}

// Clear releases all data related to current session
func (s *Session) Clear() {
	s.Lock()
	defer s.Unlock()

	s.uid = 0
	s.data = map[string]interface{}{}
}
<|endoftext|>


<commit_before>package server

import (
	"bytes"
	"fmt"
	"github.com/heroku/busl/broker"
	"github.com/heroku/busl/util"
	. "gopkg.in/check.v1"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

type HttpServerSuite struct{}

var _ = Suite(&HttpServerSuite{})
var sf = fmt.Sprintf

func newRequest(method, url, body string) *http.Request {
	return newRequestFromReader(method, url, bytes.NewBufferString(body))
}

func newRequestFromReader(method, url string, reader io.Reader) *http.Request {
	request, _ := http.NewRequest(method, url, reader)
	urlParts := strings.Split(url, "/")
	if method == "POST" {
		request.TransferEncoding = []string{"chunked"}
		request.Header.Add("Transfer-Encoding", "chunked")
	}
	if len(urlParts) == 3 {
		streamId := urlParts[2]
		setStreamId(request, streamId)
	}
	return request
}

func setStreamId(req *http.Request, streamId string) {
	req.URL.RawQuery = "%3Auuid=" + streamId + "&"
}

func (s *HttpServerSuite) TestMkstream(c *C) {
	request := newRequest("POST", "/streams", "")
	response := httptest.NewRecorder()

	mkstream(response, request)

	c.Assert(response.Code, Equals, 200)
	c.Assert(response.Body.String(), HasLen, 32)
}

func (s *HttpServerSuite) Test410(c *C) {
	streamId, _ := util.NewUUID()
	request := newRequest("GET", "/streams/"+string(streamId), "")
	response := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	sub(response, request)

	c.Assert(response.Code, Equals, http.StatusNotFound)
	c.Assert(response.Body.String(), Equals, "Channel is not registered.\n")
}

func (s *HttpServerSuite) TestPubNotRegistered(c *C) {
	streamId, _ := util.NewUUID()
	request := newRequest("POST", "/streams/"+string(streamId), "")
	response := httptest.NewRecorder()

	pub(response, request)

	c.Assert(response.Code, Equals, http.StatusNotFound)
}

func (s *HttpServerSuite) TestPubWithoutTransferEncoding(c *C) {
	request, _ := http.NewRequest("POST", "/streams/1234", nil)
	setStreamId(request, "1234")
	response := httptest.NewRecorder()

	pub(response, request)

	c.Assert(response.Code, Equals, http.StatusBadRequest)
	c.Assert(response.Body.String(), Equals, "A chunked Transfer-Encoding header is required.\n")
}

func (s *HttpServerSuite) TestSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)
	writer, _ := broker.NewWriter(streamId)

	request := newRequest("GET", sf("/streams/%s", streamId), "")
	response := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	waiter := util.TimeoutFunc(time.Millisecond*5, func() {
		sub(response, request)
	})

	writer.Write([]byte("busl1"))
	writer.Close()
	<-waiter

	c.Assert(response.Code, Equals, http.StatusOK)
	c.Assert(response.Body.String(), Equals, "busl1")
}

func (s *HttpServerSuite) TestPubSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)

	body := new(bytes.Buffer)
	bodyCloser := ioutil.NopCloser(body)

	pubRequest := newRequestFromReader("POST", sf("/streams/%s", streamId), bodyCloser)
	pubResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	pubBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		pub(pubResponse, pubRequest)
	})

	subRequest := newRequest("GET", sf("/streams/%s", streamId), "")
	subResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	subBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		sub(subResponse, subRequest)
	})

	for _, m := range []string{"first", " ", "second", " ", "third"} {
		body.Write([]byte(m))
	}

	bodyCloser.Close()
	<-pubBlocker
	<-subBlocker

	c.Assert(subResponse.Code, Equals, http.StatusOK)
	c.Assert(subResponse.Body.String(), Equals, "first second third")
}

func (s *HttpServerSuite) TestBinaryPubSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)

	body := new(bytes.Buffer)
	bodyCloser := ioutil.NopCloser(body)

	pubRequest := newRequestFromReader("POST", sf("/streams/%s", streamId), bodyCloser)
	pubResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	pubBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		pub(pubResponse, pubRequest)
	})

	subRequest := newRequest("GET", sf("/streams/%s", streamId), "")
	subResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	subBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		sub(subResponse, subRequest)
	})

	expected := []byte{0x1f, 0x8b, 0x08, 0x00, 0x3f, 0x6b, 0xe1, 0x53, 0x00, 0x03, 0xed, 0xce, 0xb1, 0x0a, 0xc2, 0x30}
	for _, m := range expected {
		body.Write([]byte{m})
	}

	bodyCloser.Close()
	<-pubBlocker
	<-subBlocker

	c.Assert(subResponse.Code, Equals, http.StatusOK)
	c.Assert(subResponse.Body.Bytes(), DeepEquals, expected)
}

func (s *HttpServerSuite) TestSubWaitingPub(c *C) {
	// Start the server in a randomly assigned port
	server := httptest.NewServer(app())
	defer server.Close()

	// uuid = curl -XPOST <url>/streams
	resp, err := http.Post(server.URL+"/streams", "", nil)
	defer resp.Body.Close()
	c.Assert(err, Equals, nil)

	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, Equals, nil)

	// uuid extracted
	uuid := string(body)
	c.Assert(len(uuid), Equals, 32)

	done := make(chan bool)

	go func() {
		// curl <url>/streams/<uuid>
		// -- waiting for publish to arrive
		resp, err = http.Get(server.URL + "/streams/" + uuid)
		defer resp.Body.Close()
		c.Assert(err, IsNil)

		body, _ = ioutil.ReadAll(resp.Body)
		c.Assert(string(body), Equals, "Hello")

		done <- true
	}()

	transport := &http.Transport{}
	client := &http.Client{Transport: transport}

	// curl -XPOST -H "Transfer-Encoding: chunked" -d "hello" <url>/streams/<uuid>
	req := newRequestFromReader("POST", server.URL+"/streams/"+uuid, strings.NewReader("Hello"))
	r, err := client.Do(req)
	r.Body.Close()
	c.Assert(err, IsNil)

	<-done
}

func (s *HttpServerSuite) TestAuthentication(c *C) {
	*util.Creds = "u:pass1|u:pass2"
	defer func() {
		*util.Creds = ""
	}()

	// Start the server in a randomly assigned port
	server := httptest.NewServer(app())
	defer server.Close()

	transport := &http.Transport{}
	client := &http.Client{Transport: transport}

	// Validate that we return 401 for empty and invalid tokens
	for _, token := range []string{"", "invalid"} {
		request := newRequest("POST", server.URL+"/streams", "")
		if token != "" {
			request.SetBasicAuth("", token)
		}
		resp, err := client.Do(request)
		defer resp.Body.Close()
		c.Assert(err, Equals, nil)
		c.Assert(resp.Status, Equals, "401 Unauthorized")
	}

	// Validate that all the colon separated token values are
	// accepted
	for _, token := range []string{"pass1", "pass2"} {
		request := newRequest("POST", server.URL+"/streams", "")
		request.SetBasicAuth("u", token)
		resp, err := client.Do(request)
		defer resp.Body.Close()
		c.Assert(err, Equals, nil)
		c.Assert(resp.Status, Equals, "200 OK")
	}
}

type CloseNotifierRecorder struct {
	*httptest.ResponseRecorder
	closed chan bool
}

func (cnr CloseNotifierRecorder) close() {
	cnr.closed <- true
}

func (cnr CloseNotifierRecorder) CloseNotify() <-chan bool {
	return cnr.closed
}
<commit_msg>Make the test less flappy<commit_after>package server

import (
	"bytes"
	"fmt"
	"github.com/heroku/busl/broker"
	"github.com/heroku/busl/util"
	. "gopkg.in/check.v1"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

type HttpServerSuite struct{}

var _ = Suite(&HttpServerSuite{})
var sf = fmt.Sprintf

func newRequest(method, url, body string) *http.Request {
	return newRequestFromReader(method, url, bytes.NewBufferString(body))
}

func newRequestFromReader(method, url string, reader io.Reader) *http.Request {
	request, _ := http.NewRequest(method, url, reader)
	urlParts := strings.Split(url, "/")
	if method == "POST" {
		request.TransferEncoding = []string{"chunked"}
		request.Header.Add("Transfer-Encoding", "chunked")
	}
	if len(urlParts) == 3 {
		streamId := urlParts[2]
		setStreamId(request, streamId)
	}
	return request
}

func setStreamId(req *http.Request, streamId string) {
	req.URL.RawQuery = "%3Auuid=" + streamId + "&"
}

func (s *HttpServerSuite) TestMkstream(c *C) {
	request := newRequest("POST", "/streams", "")
	response := httptest.NewRecorder()

	mkstream(response, request)

	c.Assert(response.Code, Equals, 200)
	c.Assert(response.Body.String(), HasLen, 32)
}

func (s *HttpServerSuite) Test410(c *C) {
	streamId, _ := util.NewUUID()
	request := newRequest("GET", "/streams/"+string(streamId), "")
	response := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	sub(response, request)

	c.Assert(response.Code, Equals, http.StatusNotFound)
	c.Assert(response.Body.String(), Equals, "Channel is not registered.\n")
}

func (s *HttpServerSuite) TestPubNotRegistered(c *C) {
	streamId, _ := util.NewUUID()
	request := newRequest("POST", "/streams/"+string(streamId), "")
	response := httptest.NewRecorder()

	pub(response, request)

	c.Assert(response.Code, Equals, http.StatusNotFound)
}

func (s *HttpServerSuite) TestPubWithoutTransferEncoding(c *C) {
	request, _ := http.NewRequest("POST", "/streams/1234", nil)
	setStreamId(request, "1234")
	response := httptest.NewRecorder()

	pub(response, request)

	c.Assert(response.Code, Equals, http.StatusBadRequest)
	c.Assert(response.Body.String(), Equals, "A chunked Transfer-Encoding header is required.\n")
}

func (s *HttpServerSuite) TestSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)
	writer, _ := broker.NewWriter(streamId)

	request := newRequest("GET", sf("/streams/%s", streamId), "")
	response := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	waiter := util.TimeoutFunc(time.Millisecond*5, func() {
		sub(response, request)
	})

	writer.Write([]byte("busl1"))
	writer.Close()
	<-waiter

	c.Assert(response.Code, Equals, http.StatusOK)
	c.Assert(response.Body.String(), Equals, "busl1")
}

func (s *HttpServerSuite) TestPubSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)

	body := new(bytes.Buffer)
	bodyCloser := ioutil.NopCloser(body)

	pubRequest := newRequestFromReader("POST", sf("/streams/%s", streamId), bodyCloser)
	pubResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	pubBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		pub(pubResponse, pubRequest)
	})

	subRequest := newRequest("GET", sf("/streams/%s", streamId), "")
	subResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	subBlocker := util.TimeoutFunc(time.Millisecond*5, func() {
		sub(subResponse, subRequest)
	})

	for _, m := range []string{"first", " ", "second", " ", "third"} {
		body.Write([]byte(m))
	}

	bodyCloser.Close()
	<-pubBlocker
	<-subBlocker

	c.Assert(subResponse.Code, Equals, http.StatusOK)
	c.Assert(subResponse.Body.String(), Equals, "first second third")
}

func (s *HttpServerSuite) TestBinaryPubSub(c *C) {
	streamId, _ := util.NewUUID()
	registrar := broker.NewRedisRegistrar()
	registrar.Register(streamId)

	body := new(bytes.Buffer)
	bodyCloser := ioutil.NopCloser(body)

	pubRequest := newRequestFromReader("POST", sf("/streams/%s", streamId), bodyCloser)
	pubResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	pubDone := make(chan bool)
	subDone := make(chan bool)

	go func() {
		pub(pubResponse, pubRequest)
		pubDone <- true
	}()

	subRequest := newRequest("GET", sf("/streams/%s", streamId), "")
	subResponse := CloseNotifierRecorder{httptest.NewRecorder(), make(chan bool, 1)}

	go func() {
		sub(subResponse, subRequest)
		subDone <- true
	}()

	expected := []byte{0x1f, 0x8b, 0x08, 0x00, 0x3f, 0x6b, 0xe1, 0x53, 0x00, 0x03, 0xed, 0xce, 0xb1, 0x0a, 0xc2, 0x30}
	for _, m := range expected {
		body.Write([]byte{m})
	}

	bodyCloser.Close()
	<-pubDone
	<-subDone

	c.Assert(subResponse.Code, Equals, http.StatusOK)
	c.Assert(subResponse.Body.Bytes(), DeepEquals, expected)
}

func (s *HttpServerSuite) TestSubWaitingPub(c *C) {
	// Start the server in a randomly assigned port
	server := httptest.NewServer(app())
	defer server.Close()

	// uuid = curl -XPOST <url>/streams
	resp, err := http.Post(server.URL+"/streams", "", nil)
	defer resp.Body.Close()
	c.Assert(err, Equals, nil)

	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, Equals, nil)

	// uuid extracted
	uuid := string(body)
	c.Assert(len(uuid), Equals, 32)

	done := make(chan bool)

	go func() {
		// curl <url>/streams/<uuid>
		// -- waiting for publish to arrive
		resp, err = http.Get(server.URL + "/streams/" + uuid)
		defer resp.Body.Close()
		c.Assert(err, IsNil)

		body, _ = ioutil.ReadAll(resp.Body)
		c.Assert(string(body), Equals, "Hello")

		done <- true
	}()

	transport := &http.Transport{}
	client := &http.Client{Transport: transport}

	// curl -XPOST -H "Transfer-Encoding: chunked" -d "hello" <url>/streams/<uuid>
	req := newRequestFromReader("POST", server.URL+"/streams/"+uuid, strings.NewReader("Hello"))
	r, err := client.Do(req)
	r.Body.Close()
	c.Assert(err, IsNil)

	<-done
}

func (s *HttpServerSuite) TestAuthentication(c *C) {
	*util.Creds = "u:pass1|u:pass2"
	defer func() {
		*util.Creds = ""
	}()

	// Start the server in a randomly assigned port
	server := httptest.NewServer(app())
	defer server.Close()

	transport := &http.Transport{}
	client := &http.Client{Transport: transport}

	// Validate that we return 401 for empty and invalid tokens
	for _, token := range []string{"", "invalid"} {
		request := newRequest("POST", server.URL+"/streams", "")
		if token != "" {
			request.SetBasicAuth("", token)
		}
		resp, err := client.Do(request)
		defer resp.Body.Close()
		c.Assert(err, Equals, nil)
		c.Assert(resp.Status, Equals, "401 Unauthorized")
	}

	// Validate that all the colon separated token values are
	// accepted
	for _, token := range []string{"pass1", "pass2"} {
		request := newRequest("POST", server.URL+"/streams", "")
		request.SetBasicAuth("u", token)
		resp, err := client.Do(request)
		defer resp.Body.Close()
		c.Assert(err, Equals, nil)
		c.Assert(resp.Status, Equals, "200 OK")
	}
}

type CloseNotifierRecorder struct {
	*httptest.ResponseRecorder
	closed chan bool
}

func (cnr CloseNotifierRecorder) close() {
	cnr.closed <- true
}

func (cnr CloseNotifierRecorder) CloseNotify() <-chan bool {
	return cnr.closed
}
<|endoftext|>


<commit_before>package server

import (
	"io/ioutil"
	"strings"
	"testing"
	"net/http"
	"net/http/httptest"
	"encoding/json"
)

type domainsResult struct {
	Result []string      `json:"result"`
	Error  error       `json:"error"`
}

func request(s *Server, t *testing.T, method string, domain string, body string) *httptest.ResponseRecorder {
	reqBody := strings.NewReader(body)
	req, err := http.NewRequest(method, "http://counters.io/" + domain, reqBody)
	if err != nil {
		t.Fatalf("%s", err)
	}
	respw := httptest.NewRecorder()
	s.ServeHTTP(respw, req)
	return respw
}

func unmarschal(resp *httptest.ResponseRecorder) domainsResult {
	body, _ := ioutil.ReadAll(resp.Body)
	var r domainsResult
	json.Unmarshal(body, &r)
	return r
}

func TestDomainsInitiallyEmpty(t *testing.T) {
	s := New()
	resp := request(s, t, "GET", "", "{}")
	if resp.Code != 200 {
		t.Fatalf("Invalid Response Code %d - %s", resp.Code, resp.Body.String())
		return
	}
	result := unmarschal(resp)
	if len(result.Result) != 0 {
		t.Fatalf("Initial resultCount != 0. Got %s", result)
	}
}

func TestBadRequest(t *testing.T) {
	s := New()
	var resp *httptest.ResponseRecorder
	resp = request(s, t, "GET", "", `{"invalid": "request"}`)
	if resp.Code != 400 {
		t.Fatalf("Invalid Response Code %d - Expected 400", resp.Code)
		return
	}
	resp = request(s, t, "POST", "marvel", "{}")
	if resp.Code != 400 {
		t.Fatalf("Invalid Response Code %d - Expected 400", resp.Code)
		return
	}
}

func TestCreateDomain(t *testing.T) {
	s := New()
	resp := request(s, t, "POST", "marvel", `{
		"domain": "marvel",
		"domainType": "mutable",
		"capacity": 100000,
		"values": []
	}`)

	if resp.Code != 200 {
		t.Fatalf("Invalid Response Code %d - %s", resp.Code, resp.Body.String())
		return
	}

	result := unmarschal(resp)
	if len(result.Result) != 1 {
		t.Fatalf("after add resultCount != 1. Got %s", result.Result)
	}
}
<commit_msg>bugfix<commit_after>package server

import (
	"io/ioutil"
	"strings"
	"testing"
	"net/http"
	"net/http/httptest"
	"encoding/json"
)

type domainsResult struct {
	Result []string      `json:"result"`
	Error  error       `json:"error"`
}

func request(s *Server, t *testing.T, method string, domain string, body string) *httptest.ResponseRecorder {
	reqBody := strings.NewReader(body)
	req, err := http.NewRequest(method, "http://counters.io/" + domain, reqBody)
	if err != nil {
		t.Fatalf("%s", err)
	}
	respw := httptest.NewRecorder()
	s.ServeHTTP(respw, req)
	return respw
}

func unmarschal(resp *httptest.ResponseRecorder) domainsResult {
	body, _ := ioutil.ReadAll(resp.Body)
	var r domainsResult
	json.Unmarshal(body, &r)
	return r
}

func TestDomainsInitiallyEmpty(t *testing.T) {
	s := New()
	resp := request(s, t, "GET", "", "{}")
	if resp.Code != 200 {
		t.Fatalf("Invalid Response Code %d - %s", resp.Code, resp.Body.String())
		return
	}
	result := unmarschal(resp)
	if len(result.Result) != 0 {
		t.Fatalf("Initial resultCount != 0. Got %s", result)
	}
}

func TestBadRequest(t *testing.T) {
	s := New()
	var resp *httptest.ResponseRecorder
	resp = request(s, t, "GET", "", `{"invalid": "request"}`)
	if resp.Code != 400 {
		t.Fatalf("Invalid Response Code %d - Expected 400", resp.Code)
		return
	}
	resp = request(s, t, "POST", "marvel", "{}")
	if resp.Code != 400 {
		t.Fatalf("Invalid Response Code %d - Expected 400", resp.Code)
		return
	}
}

func TestCreateDomain(t *testing.T) {
	s := New()
	resp := request(s, t, "POST", "marvel", `{
		"domain": "marvel",
		"domainType": "mutable",
		"capacity": 100000,
		"values": []
	}`)

	if resp.Code != 200 {
		t.Fatalf("Invalid Response Code %d - %s", resp.Code, resp.Body.String())
		return
	}

	result := unmarschal(resp)
	if len(result.Result) != 1 {
		t.Fatalf("after add resultCount != 1. Got %s", len(result.Result))
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/deis/deis/pkg/prettyprint"

	"github.com/deis/deis/client/controller/api"
	"github.com/deis/deis/client/controller/client"
	"github.com/deis/deis/client/controller/models/apps"
	"github.com/deis/deis/client/controller/models/config"
	"github.com/deis/deis/client/pkg/git"
	"github.com/deis/deis/client/pkg/webbrowser"
)

// AppCreate creates an app.
func AppCreate(id string, buildpack string, remote string, noRemote bool) error {
	c, err := client.New()

	fmt.Print("Creating Application... ")
	quit := progress()
	app, err := apps.New(c, id)

	quit <- true
	<-quit

	if err != nil {
		return err
	}

	fmt.Printf("done, created %s\n", app.ID)

	if buildpack != "" {
		configValues := api.Config{
			Values: map[string]interface{}{
				"BUILDPACK_URL": buildpack,
			},
		}
		if _, err = config.Set(c, app.ID, configValues); err != nil {
			return err
		}
	}

	if !noRemote {
		return git.CreateRemote(c.ControllerURL.Host, remote, app.ID)
	}

	fmt.Println("remote available at", git.RemoteURL(c.ControllerURL.Host, app.ID))

	return nil
}

// AppsList lists apps on the Deis controller.
func AppsList(results int) error {
	c, err := client.New()

	if err != nil {
		return err
	}

	if results == defaultLimit {
		results = c.ResponseLimit
	}

	apps, count, err := apps.List(c, results)

	if err != nil {
		return err
	}

	fmt.Printf("=== Apps%s", limitCount(len(apps), count))

	for _, app := range apps {
		fmt.Println(app.ID)
	}
	return nil
}

// AppInfo prints info about app.
func AppInfo(appID string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	app, err := apps.Get(c, appID)

	if err != nil {
		return err
	}

	fmt.Printf("=== %s Application\n", app.ID)
	fmt.Println("updated: ", app.Updated)
	fmt.Println("uuid:    ", app.UUID)
	fmt.Println("created: ", app.Created)
	fmt.Println("url:     ", app.URL)
	fmt.Println("owner:   ", app.Owner)
	fmt.Println("id:      ", app.ID)

	fmt.Println()
	// print the app processes
	if err = PsList(app.ID, defaultLimit); err != nil {
		return err
	}

	fmt.Println()
	// print the app domains
	if err = DomainsList(app.ID, defaultLimit); err != nil {
		return err
	}

	fmt.Println()

	return nil
}

// AppOpen opens an app in the default webbrowser.
func AppOpen(appID string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	app, err := apps.Get(c, appID)

	if err != nil {
		return err
	}

	u, err := url.Parse(app.URL)

	if err != nil {
		return err
	}

	u.Scheme = "http"

	return webbrowser.Webbrowser(u.String())
}

// AppLogs returns the logs from an app.
func AppLogs(appID string, lines int) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	logs, err := apps.Logs(c, appID, lines)

	if err != nil {
		return err
	}

	return printLogs(logs)
}

// printLogs prints each log line with a color matched to its category.
func printLogs(logs string) error {
	for _, log := range strings.Split(strings.Trim(logs, `\n`), `\n`) {
		category := "unknown"
		parts := strings.Split(strings.Split(log, ": ")[0], " ")
		if len(parts) >= 2 {
			category = parts[1]
		}
		colorVars := map[string]string{
			"Color": chooseColor(category),
			"Log":   log,
		}
		fmt.Println(prettyprint.ColorizeVars("{{.V.Color}}{{.V.Log}}{{.C.Default}}", colorVars))
	}

	return nil
}

// AppRun runs a one time command in the app.
func AppRun(appID, command string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	fmt.Printf("Running '%s'...\n", command)

	out, err := apps.Run(c, appID, command)

	if err != nil {
		return err
	}

	fmt.Print(out.Output)
	os.Exit(out.ReturnCode)
	return nil
}

// AppDestroy destroys an app.
func AppDestroy(appID, confirm string) error {
	gitSession := false

	c, err := client.New()

	if err != nil {
		return err
	}

	if appID == "" {
		appID, err = git.DetectAppName(c.ControllerURL.Host)

		if err != nil {
			return err
		}

		gitSession = true
	}

	if confirm == "" {
		fmt.Printf(` !    WARNING: Potentially Destructive Action
 !    This command will destroy the application: %s
 !    To proceed, type "%s" or re-run this command with --confirm=%s

> `, appID, appID, appID)

		fmt.Scanln(&confirm)
	}

	if confirm != appID {
		return fmt.Errorf("App %s does not match confirm %s, aborting.", appID, confirm)
	}

	startTime := time.Now()
	fmt.Printf("Destroying %s...\n", appID)

	if err = apps.Delete(c, appID); err != nil {
		return err
	}

	fmt.Printf("done in %ds\n", int(time.Since(startTime).Seconds()))

	if gitSession {
		return git.DeleteRemote(appID)
	}

	return nil
}

// AppTransfer transfers app ownership to another user.
func AppTransfer(appID, username string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	fmt.Printf("Transferring %s to %s... ", appID, username)

	err = apps.Transfer(c, appID, username)

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}
<commit_msg>fix(client): suggest help when git remote creation fails<commit_after>package cmd

import (
	"fmt"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/deis/deis/pkg/prettyprint"

	"github.com/deis/deis/client/controller/api"
	"github.com/deis/deis/client/controller/client"
	"github.com/deis/deis/client/controller/models/apps"
	"github.com/deis/deis/client/controller/models/config"
	"github.com/deis/deis/client/pkg/git"
	"github.com/deis/deis/client/pkg/webbrowser"
)

// AppCreate creates an app.
func AppCreate(id string, buildpack string, remote string, noRemote bool) error {
	c, err := client.New()

	fmt.Print("Creating Application... ")
	quit := progress()
	app, err := apps.New(c, id)

	quit <- true
	<-quit

	if err != nil {
		return err
	}

	fmt.Printf("done, created %s\n", app.ID)

	if buildpack != "" {
		configValues := api.Config{
			Values: map[string]interface{}{
				"BUILDPACK_URL": buildpack,
			},
		}
		if _, err = config.Set(c, app.ID, configValues); err != nil {
			return err
		}
	}

	if !noRemote {
		if err = git.CreateRemote(c.ControllerURL.Host, remote, app.ID); err != nil {
			if err.Error() == "exit status 128" {
				fmt.Println("To replace the existing git remote entry, run:")
				fmt.Printf("  git remote rename deis deis.old && deis git:remote -a %s\n", app.ID)
			}
			return err
		}
	}

	fmt.Println("remote available at", git.RemoteURL(c.ControllerURL.Host, app.ID))

	return nil
}

// AppsList lists apps on the Deis controller.
func AppsList(results int) error {
	c, err := client.New()

	if err != nil {
		return err
	}

	if results == defaultLimit {
		results = c.ResponseLimit
	}

	apps, count, err := apps.List(c, results)

	if err != nil {
		return err
	}

	fmt.Printf("=== Apps%s", limitCount(len(apps), count))

	for _, app := range apps {
		fmt.Println(app.ID)
	}
	return nil
}

// AppInfo prints info about app.
func AppInfo(appID string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	app, err := apps.Get(c, appID)

	if err != nil {
		return err
	}

	fmt.Printf("=== %s Application\n", app.ID)
	fmt.Println("updated: ", app.Updated)
	fmt.Println("uuid:    ", app.UUID)
	fmt.Println("created: ", app.Created)
	fmt.Println("url:     ", app.URL)
	fmt.Println("owner:   ", app.Owner)
	fmt.Println("id:      ", app.ID)

	fmt.Println()
	// print the app processes
	if err = PsList(app.ID, defaultLimit); err != nil {
		return err
	}

	fmt.Println()
	// print the app domains
	if err = DomainsList(app.ID, defaultLimit); err != nil {
		return err
	}

	fmt.Println()

	return nil
}

// AppOpen opens an app in the default webbrowser.
func AppOpen(appID string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	app, err := apps.Get(c, appID)

	if err != nil {
		return err
	}

	u, err := url.Parse(app.URL)

	if err != nil {
		return err
	}

	u.Scheme = "http"

	return webbrowser.Webbrowser(u.String())
}

// AppLogs returns the logs from an app.
func AppLogs(appID string, lines int) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	logs, err := apps.Logs(c, appID, lines)

	if err != nil {
		return err
	}

	return printLogs(logs)
}

// printLogs prints each log line with a color matched to its category.
func printLogs(logs string) error {
	for _, log := range strings.Split(strings.Trim(logs, `\n`), `\n`) {
		category := "unknown"
		parts := strings.Split(strings.Split(log, ": ")[0], " ")
		if len(parts) >= 2 {
			category = parts[1]
		}
		colorVars := map[string]string{
			"Color": chooseColor(category),
			"Log":   log,
		}
		fmt.Println(prettyprint.ColorizeVars("{{.V.Color}}{{.V.Log}}{{.C.Default}}", colorVars))
	}

	return nil
}

// AppRun runs a one time command in the app.
func AppRun(appID, command string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	fmt.Printf("Running '%s'...\n", command)

	out, err := apps.Run(c, appID, command)

	if err != nil {
		return err
	}

	fmt.Print(out.Output)
	os.Exit(out.ReturnCode)
	return nil
}

// AppDestroy destroys an app.
func AppDestroy(appID, confirm string) error {
	gitSession := false

	c, err := client.New()

	if err != nil {
		return err
	}

	if appID == "" {
		appID, err = git.DetectAppName(c.ControllerURL.Host)

		if err != nil {
			return err
		}

		gitSession = true
	}

	if confirm == "" {
		fmt.Printf(` !    WARNING: Potentially Destructive Action
 !    This command will destroy the application: %s
 !    To proceed, type "%s" or re-run this command with --confirm=%s

> `, appID, appID, appID)

		fmt.Scanln(&confirm)
	}

	if confirm != appID {
		return fmt.Errorf("App %s does not match confirm %s, aborting.", appID, confirm)
	}

	startTime := time.Now()
	fmt.Printf("Destroying %s...\n", appID)

	if err = apps.Delete(c, appID); err != nil {
		return err
	}

	fmt.Printf("done in %ds\n", int(time.Since(startTime).Seconds()))

	if gitSession {
		return git.DeleteRemote(appID)
	}

	return nil
}

// AppTransfer transfers app ownership to another user.
func AppTransfer(appID, username string) error {
	c, appID, err := load(appID)

	if err != nil {
		return err
	}

	fmt.Printf("Transferring %s to %s... ", appID, username)

	err = apps.Transfer(c, appID, username)

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}
<|endoftext|>