<commit_before>package wallet

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/log"
)

const AssetLimit = 50
const CollectionLimit = 300

type TraitValue string

func (st *TraitValue) UnmarshalJSON(b []byte) error {
	var item interface{}
	if err := json.Unmarshal(b, &item); err != nil {
		return err
	}
	switch v := item.(type) {
	case int:
		*st = TraitValue(strconv.Itoa(v))
	case string:
		*st = TraitValue(v)

	}
	return nil
}

type OpenseaAssetContainer struct {
	Assets []OpenseaAsset `json:"assets"`
}

type OpenseaAssetCollection struct {
	Name string `json:"name"`
}

type OpenseaContract struct {
	Address string `json:"address"`
}

type OpenseaTrait struct {
	TraitType   string     `json:"trait_type"`
	Value       TraitValue `json:"value"`
	DisplayType string     `json:"display_type"`
}

type OpenseaAsset struct {
	ID                int                    `json:"id"`
	Name              string                 `json:"name"`
	Description       string                 `json:"description"`
	Permalink         string                 `json:"permalink"`
	ImageThumbnailURL string                 `json:"image_thumbnail_url"`
	ImageURL          string                 `json:"image_url"`
	Contract          OpenseaContract        `json:"asset_contract"`
	Collection        OpenseaAssetCollection `json:"collection"`
	Traits            []OpenseaTrait         `json:"traits"`
}

type OpenseaCollection struct {
	Name            string `json:"name"`
	Slug            string `json:"slug"`
	ImageURL        string `json:"image_url"`
	OwnedAssetCount int    `json:"owned_asset_count"`
}

type OpenseaClient struct {
	client *http.Client
	url    string
}

// new opensea client.
func newOpenseaClient() *OpenseaClient {
	client := &http.Client{
		Timeout: time.Second * 5,
	}

	return &OpenseaClient{client: client, url: "https://api.opensea.io/api/v1"}
}

func (o *OpenseaClient) fetchAllCollectionsByOwner(owner common.Address) ([]OpenseaCollection, error) {
	offset := 0
	var collections []OpenseaCollection
	for {
		url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		var tmp []OpenseaCollection
		err = json.Unmarshal(body, &tmp)
		if err != nil {
			return nil, err
		}

		collections = append(collections, tmp...)

		if len(tmp) < CollectionLimit {
			break
		}
	}
	return collections, nil
}

func (o *OpenseaClient) fetchAllAssetsByOwnerAndCollection(owner common.Address, collectionSlug string, limit int) ([]OpenseaAsset, error) {
	offset := 0
	var assets []OpenseaAsset
	for {
		url := fmt.Sprintf("%s/assets?owner=%s&collection=%s&offset=%d&limit=%d", o.url, owner, collectionSlug, offset, AssetLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		container := OpenseaAssetContainer{}
		err = json.Unmarshal(body, &container)
		if err != nil {
			return nil, err
		}

		assets = append(assets, container.Assets...)

		if len(container.Assets) < AssetLimit {
			break
		}

		if len(assets) >= limit {
			break
		}
	}
	return assets, nil
}

func (o *OpenseaClient) doOpenseaRequest(url string) ([]byte, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := o.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Error("failed to close opensea request body", "err", err)
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}
<commit_msg>feat: Add more attributes from opensea (#2354)<commit_after>package wallet

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/log"
)

const AssetLimit = 50
const CollectionLimit = 300

type TraitValue string

func (st *TraitValue) UnmarshalJSON(b []byte) error {
	var item interface{}
	if err := json.Unmarshal(b, &item); err != nil {
		return err
	}

	switch v := item.(type) {
	case float64:
		*st = TraitValue(strconv.FormatFloat(v, 'f', 2, 64))
	case int:
		*st = TraitValue(strconv.Itoa(v))
	case string:
		*st = TraitValue(v)

	}
	return nil
}

type OpenseaAssetContainer struct {
	Assets []OpenseaAsset `json:"assets"`
}

type OpenseaAssetCollection struct {
	Name string `json:"name"`
}

type OpenseaContract struct {
	Address string `json:"address"`
}

type OpenseaTrait struct {
	TraitType   string     `json:"trait_type"`
	Value       TraitValue `json:"value"`
	DisplayType string     `json:"display_type"`
	MaxValue    string     `json:"max_value"`
}

type OpenseaPaymentToken struct {
	ID       int    `json:"id"`
	Symbol   string `json:"symbol"`
	Address  string `json:"address"`
	ImageURL string `json:"image_url"`
	Name     string `json:"name"`
	Decimals int    `json:"decimals"`
	EthPrice string `json:"eth_price"`
	UsdPrice string `json:"usd_price"`
}

type OpenseaLastSale struct {
	PaymentToken OpenseaPaymentToken `json:"payment_token"`
}

type OpenseaSellOrder struct {
	CurrentPrice string `json:"current_price"`
}
type OpenseaAsset struct {
	ID                int                    `json:"id"`
	Name              string                 `json:"name"`
	Description       string                 `json:"description"`
	Permalink         string                 `json:"permalink"`
	ImageThumbnailURL string                 `json:"image_thumbnail_url"`
	ImageURL          string                 `json:"image_url"`
	Contract          OpenseaContract        `json:"asset_contract"`
	Collection        OpenseaAssetCollection `json:"collection"`
	Traits            []OpenseaTrait         `json:"traits"`
	LastSale          OpenseaLastSale        `json:"last_sale"`
	SellOrders        []OpenseaSellOrder     `json:"sell_orders"`
	BackgroundColor   string                 `json:"background_color"`
}

type OpenseaCollectionTrait struct {
	Min float64 `json:"min"`
	Max float64 `json:"max"`
}

type OpenseaCollection struct {
	Name            string                            `json:"name"`
	Slug            string                            `json:"slug"`
	ImageURL        string                            `json:"image_url"`
	OwnedAssetCount int                               `json:"owned_asset_count"`
	Traits          map[string]OpenseaCollectionTrait `json:"traits"`
}

type OpenseaClient struct {
	client *http.Client
	url    string
}

// new opensea client.
func newOpenseaClient() *OpenseaClient {
	client := &http.Client{
		Timeout: time.Second * 5,
	}

	return &OpenseaClient{client: client, url: "https://api.opensea.io/api/v1"}
}

func (o *OpenseaClient) fetchAllCollectionsByOwner(owner common.Address) ([]OpenseaCollection, error) {
	offset := 0
	var collections []OpenseaCollection
	for {
		url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		var tmp []OpenseaCollection
		err = json.Unmarshal(body, &tmp)
		if err != nil {
			return nil, err
		}

		collections = append(collections, tmp...)

		if len(tmp) < CollectionLimit {
			break
		}
	}
	return collections, nil
}

func (o *OpenseaClient) fetchAllAssetsByOwnerAndCollection(owner common.Address, collectionSlug string, limit int) ([]OpenseaAsset, error) {
	offset := 0
	var assets []OpenseaAsset
	for {
		url := fmt.Sprintf("%s/assets?owner=%s&collection=%s&offset=%d&limit=%d", o.url, owner, collectionSlug, offset, AssetLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		container := OpenseaAssetContainer{}
		err = json.Unmarshal(body, &container)
		if err != nil {
			return nil, err
		}

		assets = append(assets, container.Assets...)

		if len(container.Assets) < AssetLimit {
			break
		}

		if len(assets) >= limit {
			break
		}
	}
	return assets, nil
}

func (o *OpenseaClient) doOpenseaRequest(url string) ([]byte, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := o.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Error("failed to close opensea request body", "err", err)
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}
<|endoftext|>


<commit_before>package wallet

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/log"
)

const AssetLimit = 50
const CollectionLimit = 300

var BaseURLs = map[uint64]string{
	1: "https://api.opensea.io/api/v1",
	4: "https://rinkeby-api.opensea.io/api/v1",
}

type TraitValue string

func (st *TraitValue) UnmarshalJSON(b []byte) error {
	var item interface{}
	if err := json.Unmarshal(b, &item); err != nil {
		return err
	}

	switch v := item.(type) {
	case float64:
		*st = TraitValue(strconv.FormatFloat(v, 'f', 2, 64))
	case int:
		*st = TraitValue(strconv.Itoa(v))
	case string:
		*st = TraitValue(v)

	}
	return nil
}

type OpenseaAssetContainer struct {
	Assets []OpenseaAsset `json:"assets"`
}

type OpenseaAssetCollection struct {
	Name string `json:"name"`
}

type OpenseaContract struct {
	Address string `json:"address"`
}

type OpenseaTrait struct {
	TraitType   string     `json:"trait_type"`
	Value       TraitValue `json:"value"`
	DisplayType string     `json:"display_type"`
	MaxValue    string     `json:"max_value"`
}

type OpenseaPaymentToken struct {
	ID       int    `json:"id"`
	Symbol   string `json:"symbol"`
	Address  string `json:"address"`
	ImageURL string `json:"image_url"`
	Name     string `json:"name"`
	Decimals int    `json:"decimals"`
	EthPrice string `json:"eth_price"`
	UsdPrice string `json:"usd_price"`
}

type OpenseaLastSale struct {
	PaymentToken OpenseaPaymentToken `json:"payment_token"`
}

type OpenseaSellOrder struct {
	CurrentPrice string `json:"current_price"`
}
type OpenseaAsset struct {
	ID                int                    `json:"id"`
	Name              string                 `json:"name"`
	Description       string                 `json:"description"`
	Permalink         string                 `json:"permalink"`
	ImageThumbnailURL string                 `json:"image_thumbnail_url"`
	ImageURL          string                 `json:"image_url"`
	Contract          OpenseaContract        `json:"asset_contract"`
	Collection        OpenseaAssetCollection `json:"collection"`
	Traits            []OpenseaTrait         `json:"traits"`
	LastSale          OpenseaLastSale        `json:"last_sale"`
	SellOrders        []OpenseaSellOrder     `json:"sell_orders"`
	BackgroundColor   string                 `json:"background_color"`
}

type OpenseaCollectionTrait struct {
	Min float64 `json:"min"`
	Max float64 `json:"max"`
}

type OpenseaCollection struct {
	Name            string                            `json:"name"`
	Slug            string                            `json:"slug"`
	ImageURL        string                            `json:"image_url"`
	OwnedAssetCount int                               `json:"owned_asset_count"`
	Traits          map[string]OpenseaCollectionTrait `json:"traits"`
}

type OpenseaClient struct {
	client *http.Client
	url    string
	apiKey string
}

// new opensea client.
func newOpenseaClient(chainID uint64, apiKey string) (*OpenseaClient, error) {
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	if url, ok := BaseURLs[chainID]; ok {
		return &OpenseaClient{client: client, url: url, apiKey: apiKey}, nil
	}

	return nil, errors.New("ChainID not supported")
}

func (o *OpenseaClient) fetchAllCollectionsByOwner(owner common.Address) ([]OpenseaCollection, error) {
	offset := 0
	var collections []OpenseaCollection
	for {
		url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		var tmp []OpenseaCollection
		err = json.Unmarshal(body, &tmp)
		if err != nil {
			return nil, err
		}

		collections = append(collections, tmp...)

		if len(tmp) < CollectionLimit {
			break
		}
	}
	return collections, nil
}

func (o *OpenseaClient) fetchAllAssetsByOwnerAndCollection(owner common.Address, collectionSlug string, limit int) ([]OpenseaAsset, error) {
	offset := 0
	var assets []OpenseaAsset
	for {
		url := fmt.Sprintf("%s/assets?owner=%s&collection=%s&offset=%d&limit=%d", o.url, owner, collectionSlug, offset, AssetLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		container := OpenseaAssetContainer{}
		err = json.Unmarshal(body, &container)
		if err != nil {
			return nil, err
		}

		assets = append(assets, container.Assets...)

		if len(container.Assets) < AssetLimit {
			break
		}

		if len(assets) >= limit {
			break
		}
	}
	return assets, nil
}

func (o *OpenseaClient) doOpenseaRequest(url string) ([]byte, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0")
	req.Header.Set("X-API-KEY", o.apiKey)

	resp, err := o.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Error("failed to close opensea request body", "err", err)
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}
<commit_msg>feat: Update the asset traist to have the correct uppercase formats for trait values (#2781)<commit_after>package wallet

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/log"
)

const AssetLimit = 50
const CollectionLimit = 300

var BaseURLs = map[uint64]string{
	1: "https://api.opensea.io/api/v1",
	4: "https://rinkeby-api.opensea.io/api/v1",
}

type TraitValue string

func (st *TraitValue) UnmarshalJSON(b []byte) error {
	var item interface{}
	if err := json.Unmarshal(b, &item); err != nil {
		return err
	}

	switch v := item.(type) {
	case float64:
		*st = TraitValue(strconv.FormatFloat(v, 'f', 2, 64))
	case int:
		*st = TraitValue(strconv.Itoa(v))
	case string:
		*st = TraitValue(v)

	}
	return nil
}

type OpenseaAssetContainer struct {
	Assets []OpenseaAsset `json:"assets"`
}

type OpenseaAssetCollection struct {
	Name string `json:"name"`
}

type OpenseaContract struct {
	Address string `json:"address"`
}

type OpenseaTrait struct {
	TraitType   string     `json:"trait_type"`
	Value       TraitValue `json:"value"`
	DisplayType string     `json:"display_type"`
	MaxValue    string     `json:"max_value"`
}

type OpenseaPaymentToken struct {
	ID       int    `json:"id"`
	Symbol   string `json:"symbol"`
	Address  string `json:"address"`
	ImageURL string `json:"image_url"`
	Name     string `json:"name"`
	Decimals int    `json:"decimals"`
	EthPrice string `json:"eth_price"`
	UsdPrice string `json:"usd_price"`
}

type OpenseaLastSale struct {
	PaymentToken OpenseaPaymentToken `json:"payment_token"`
}

type OpenseaSellOrder struct {
	CurrentPrice string `json:"current_price"`
}
type OpenseaAsset struct {
	ID                int                    `json:"id"`
	Name              string                 `json:"name"`
	Description       string                 `json:"description"`
	Permalink         string                 `json:"permalink"`
	ImageThumbnailURL string                 `json:"image_thumbnail_url"`
	ImageURL          string                 `json:"image_url"`
	Contract          OpenseaContract        `json:"asset_contract"`
	Collection        OpenseaAssetCollection `json:"collection"`
	Traits            []OpenseaTrait         `json:"traits"`
	LastSale          OpenseaLastSale        `json:"last_sale"`
	SellOrders        []OpenseaSellOrder     `json:"sell_orders"`
	BackgroundColor   string                 `json:"background_color"`
}

type OpenseaCollectionTrait struct {
	Min float64 `json:"min"`
	Max float64 `json:"max"`
}

type OpenseaCollection struct {
	Name            string                            `json:"name"`
	Slug            string                            `json:"slug"`
	ImageURL        string                            `json:"image_url"`
	OwnedAssetCount int                               `json:"owned_asset_count"`
	Traits          map[string]OpenseaCollectionTrait `json:"traits"`
}

type OpenseaClient struct {
	client *http.Client
	url    string
	apiKey string
}

// new opensea client.
func newOpenseaClient(chainID uint64, apiKey string) (*OpenseaClient, error) {
	client := &http.Client{
		Timeout: time.Second * 5,
	}
	if url, ok := BaseURLs[chainID]; ok {
		return &OpenseaClient{client: client, url: url, apiKey: apiKey}, nil
	}

	return nil, errors.New("ChainID not supported")
}

func (o *OpenseaClient) fetchAllCollectionsByOwner(owner common.Address) ([]OpenseaCollection, error) {
	offset := 0
	var collections []OpenseaCollection
	for {
		url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		var tmp []OpenseaCollection
		err = json.Unmarshal(body, &tmp)
		if err != nil {
			return nil, err
		}

		collections = append(collections, tmp...)

		if len(tmp) < CollectionLimit {
			break
		}
	}
	return collections, nil
}

func (o *OpenseaClient) fetchAllAssetsByOwnerAndCollection(owner common.Address, collectionSlug string, limit int) ([]OpenseaAsset, error) {
	offset := 0
	var assets []OpenseaAsset
	for {
		url := fmt.Sprintf("%s/assets?owner=%s&collection=%s&offset=%d&limit=%d", o.url, owner, collectionSlug, offset, AssetLimit)
		body, err := o.doOpenseaRequest(url)
		if err != nil {
			return nil, err
		}

		container := OpenseaAssetContainer{}
		err = json.Unmarshal(body, &container)
		if err != nil {
			return nil, err
		}

		for _, asset := range container.Assets {
			for i := range asset.Traits {
				asset.Traits[i].TraitType = strings.Replace(strings.ToUpper(asset.Traits[i].TraitType), "_", " ", 1)
				asset.Traits[i].Value = TraitValue(strings.Title(string(asset.Traits[i].Value)))
			}
			assets = append(assets, asset)
		}

		if len(container.Assets) < AssetLimit {
			break
		}

		if len(assets) >= limit {
			break
		}
	}
	return assets, nil
}

func (o *OpenseaClient) doOpenseaRequest(url string) ([]byte, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0")
	req.Header.Set("X-API-KEY", o.apiKey)

	resp, err := o.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Error("failed to close opensea request body", "err", err)
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}
<|endoftext|>


<commit_before>package actual_state_listener

import (
	"github.com/cloudfoundry/hm9000/config"
	"github.com/cloudfoundry/hm9000/helpers"
	"github.com/cloudfoundry/hm9000/models"
	"github.com/cloudfoundry/hm9000/store"

	"github.com/cloudfoundry/go_cfmessagebus"

	"encoding/json"
	"strconv"
)

type ActualStateListener struct {
	messageBus     cfmessagebus.MessageBus
	heartbeatStore store.Store
	timeProvider   helpers.TimeProvider
	logger         helpers.Logger
}

func NewActualStateListener(messageBus cfmessagebus.MessageBus,
	heartbeatStore store.Store,
	timeProvider helpers.TimeProvider,
	logger helpers.Logger) *ActualStateListener {

	return &ActualStateListener{
		messageBus:     messageBus,
		heartbeatStore: heartbeatStore,
		timeProvider:   timeProvider,
		logger:         logger,
	}
}

func (listener *ActualStateListener) Start() {
	listener.messageBus.Subscribe("dea.heartbeat", func(messageBody []byte) {
		listener.bumpFreshness()

		var heartbeat models.Heartbeat
		err := json.Unmarshal(messageBody, &heartbeat)

		if err != nil {
			listener.logger.Info("Could not unmarshal heartbeat from store", map[string]string{"Error": err.Error(), "MessageBody": string(messageBody)})
			return
		}

		for _, instance := range heartbeat.InstanceHeartbeats {
			key := "/actual/" + instance.AppGuid + "-" + instance.AppVersion + "/" + strconv.Itoa(instance.InstanceIndex) + "/" + instance.InstanceGuid
			value, err := json.Marshal(instance)
			if err != nil {
				listener.logger.Info("Could not json Marshal instance", map[string]string{"Error": err.Error()})
				continue
			}
			err = listener.heartbeatStore.Set(key, string(value), config.HEARTBEAT_TTL)
			if err != nil {
				listener.logger.Info("Could not put instance heartbeat in store:", map[string]string{"Error": err.Error(), "Heartbeat": string(value)})
			}
		}
	})
}

func (listener *ActualStateListener) bumpFreshness() {
	var jsonTimestamp string
	oldTimestamp, err := listener.heartbeatStore.Get(config.ACTUAL_FRESHNESS_KEY)

	if err == nil {
		jsonTimestamp = oldTimestamp.Value
	} else {
		now := listener.timeProvider.Time().Unix()
		jsonBytes, _ := json.Marshal(models.FreshnessTimestamp{Timestamp: now})
		jsonTimestamp = string(jsonBytes)
	}

	err = listener.heartbeatStore.Set(config.ACTUAL_FRESHNESS_KEY, jsonTimestamp, config.ACTUAL_FRESHNESS_TTL)
	if err != nil {
		listener.logger.Info("Could not update actual freshness", map[string]string{"Error": err.Error()})
	}
}
<commit_msg>endless fiddling<commit_after>package actual_state_listener

import (
	"github.com/cloudfoundry/hm9000/config"
	"github.com/cloudfoundry/hm9000/helpers"
	"github.com/cloudfoundry/hm9000/models"
	"github.com/cloudfoundry/hm9000/store"

	"github.com/cloudfoundry/go_cfmessagebus"

	"encoding/json"
	"strconv"
)

type ActualStateListener struct {
	messageBus     cfmessagebus.MessageBus
	heartbeatStore store.Store
	timeProvider   helpers.TimeProvider
	logger         helpers.Logger
}

func NewActualStateListener(messageBus cfmessagebus.MessageBus,
	heartbeatStore store.Store,
	timeProvider helpers.TimeProvider,
	logger helpers.Logger) *ActualStateListener {

	return &ActualStateListener{
		messageBus:     messageBus,
		heartbeatStore: heartbeatStore,
		timeProvider:   timeProvider,
		logger:         logger,
	}
}

func (listener *ActualStateListener) Start() {
	listener.messageBus.Subscribe("dea.heartbeat", func(messageBody []byte) {
		listener.bumpFreshness()

		var heartbeat models.Heartbeat
		err := json.Unmarshal(messageBody, &heartbeat)

		if err != nil {
			listener.logger.Info("Could not unmarshal heartbeat from store",
				map[string]string{
					"Error":       err.Error(),
					"MessageBody": string(messageBody),
				})
			return
		}

		for _, instance := range heartbeat.InstanceHeartbeats {
			key := "/actual/" + instance.AppGuid + "-" + instance.AppVersion + "/" + strconv.Itoa(instance.InstanceIndex) + "/" + instance.InstanceGuid

			value, err := json.Marshal(instance)
			if err != nil {
				listener.logger.Info("Could not json Marshal instance",
					map[string]string{
						"Error": err.Error(),
					})
				continue
			}

			err = listener.heartbeatStore.Set(key, string(value), config.HEARTBEAT_TTL)
			if err != nil {
				listener.logger.Info("Could not put instance heartbeat in store:",
					map[string]string{
						"Error":     err.Error(),
						"Heartbeat": string(value),
					})
			}
		}
	})
}

func (listener *ActualStateListener) bumpFreshness() {
	var jsonTimestamp string
	oldTimestamp, err := listener.heartbeatStore.Get(config.ACTUAL_FRESHNESS_KEY)

	if err == nil {
		jsonTimestamp = oldTimestamp.Value
	} else {
		now := listener.timeProvider.Time().Unix()
		jsonBytes, _ := json.Marshal(models.FreshnessTimestamp{Timestamp: now})
		jsonTimestamp = string(jsonBytes)
	}

	err = listener.heartbeatStore.Set(config.ACTUAL_FRESHNESS_KEY, jsonTimestamp, config.ACTUAL_FRESHNESS_TTL)

	if err != nil {
		listener.logger.Info("Could not update actual freshness",
			map[string]string{
				"Error": err.Error(),
			})
	}
}
<|endoftext|>


<commit_before>package api

// NetworkZonesPost represents the fields of a new LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonesPost struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`
}

// NetworkZonePut represents the modifiable fields of a LXD network zoned
//
// swagger:model
//
// API extension: network_dns
type NetworkZonePut struct {
	// Description of the network zone
	// Example: Internal domain
	Description string `json:"description" yaml:"description"`

	// Zone configuration map (refer to doc/network-zones.md)
	// Example: {"user.mykey": "foo"}
	Config map[string]string `json:"config" yaml:"config"`
}

// NetworkZone represents a network zone (DNS).
//
// swagger:model
//
// API extension: network_dns
type NetworkZone struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`

	// List of URLs of objects using this network zone
	// Read only: true
	// Example: ["/1.0/networks/foo", "/1.0/networks/bar"]
	UsedBy []string `json:"used_by" yaml:"used_by"` // Resources that use the zone.
}

// Writable converts a full NetworkZone struct into a NetworkZonePut struct (filters read-only fields).
func (f *NetworkZone) Writable() NetworkZonePut {
	return f.NetworkZonePut
}
<commit_msg>shared/api: Fix typo<commit_after>package api

// NetworkZonesPost represents the fields of a new LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonesPost struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`
}

// NetworkZonePut represents the modifiable fields of a LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonePut struct {
	// Description of the network zone
	// Example: Internal domain
	Description string `json:"description" yaml:"description"`

	// Zone configuration map (refer to doc/network-zones.md)
	// Example: {"user.mykey": "foo"}
	Config map[string]string `json:"config" yaml:"config"`
}

// NetworkZone represents a network zone (DNS).
//
// swagger:model
//
// API extension: network_dns
type NetworkZone struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`

	// List of URLs of objects using this network zone
	// Read only: true
	// Example: ["/1.0/networks/foo", "/1.0/networks/bar"]
	UsedBy []string `json:"used_by" yaml:"used_by"` // Resources that use the zone.
}

// Writable converts a full NetworkZone struct into a NetworkZonePut struct (filters read-only fields).
func (f *NetworkZone) Writable() NetworkZonePut {
	return f.NetworkZonePut
}
<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2017 TechCatsLab
 *
 * 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.
 */

/*
 * Revision History:
 *     Initial: 2017/04/05        Feng Yifei
 */

package main

import (
	"fmt"
)

func deferWithoutReturnName() int {
	var (
		i int
	)

	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return i
}

func deferWithReturnName() (i int) {
	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return i // return 0 效果是一样的
}

func deferWithAddress() *int {
	var (
		i int
	)

	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return &i
}

/**
 * 从结果分析看：
 *     当返回值命名时，使用的是地址方式的引用
 */
func main() {
	fmt.Println("deferWithoutReturnName", deferWithoutReturnName())
	fmt.Println("deferWithReturnName", deferWithReturnName())
	fmt.Println("deferWithAddress", *deferWithAddress())
}
<commit_msg>defer error sample<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2017 TechCatsLab
 *
 * 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.
 */

/*
 * Revision History:
 *     Initial: 2017/04/05        Feng Yifei
 */

package main

import (
	"errors"
	"fmt"
)

func deferWithoutReturnName() int {
	var (
		i int
	)

	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return i
}

func deferWithReturnName() (i int) {
	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return i // return 0 效果是一样的
}

func deferWithAddress() *int {
	var (
		i int
	)

	defer func() {
		i++
		fmt.Println("1st:", i)
	}()

	defer func() {
		i++
		fmt.Println("2nd:", i)
	}()

	return &i
}

func deferError() error {
	var (
		err error
	)

	defer func() {
		err = errors.New("shouldn't change the return value")
	}()

	return err
}

/**
 * 从结果分析看：
 *     当返回值命名时，使用的是地址方式的引用
 */
func main() {
	fmt.Println("deferWithoutReturnName", deferWithoutReturnName())
	fmt.Println("deferWithReturnName", deferWithReturnName())
	fmt.Println("deferWithAddress", *deferWithAddress())
	fmt.Println("deferError", deferError())
}
<|endoftext|>


<commit_before>package handler

import (
	"context"
	"fmt"
	"net/http"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"github.com/SermoDigital/jose/jws"
	"github.com/go-kit/kit/log"
)

//satClientIDKey is the key to set/get sat client IDs using contexts.
var satClientIDKey = struct{ key string }{key: "sat-client-key"}

const (
	// The Content-Type value for JSON
	JsonContentType string = "application/json; charset=UTF-8"

	// The Content-Type header
	ContentTypeHeader string = "Content-Type"

	// The X-Content-Type-Options header
	ContentTypeOptionsHeader string = "X-Content-Type-Options"

	// NoSniff is the value used for content options for errors written by this package
	NoSniff string = "nosniff"
)

// WriteJsonError writes a standard JSON error to the response
func WriteJsonError(response http.ResponseWriter, code int, message string) error {
	response.Header().Set(ContentTypeHeader, JsonContentType)
	response.Header().Set(ContentTypeOptionsHeader, NoSniff)

	response.WriteHeader(code)
	_, err := fmt.Fprintf(response, `{"message": "%s"}`, message)
	return err
}

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              log.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() log.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return logging.DefaultLogger()
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	var (
		headerName          = a.headerName()
		forbiddenStatusCode = a.forbiddenStatusCode()
		logger              = a.logger()
		errorLog            = logging.Error(logger)
	)

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			errorLog.Log(logging.MessageKey(), "missing header", "name", headerName)
			WriteJsonError(response, forbiddenStatusCode, fmt.Sprintf("missing header: %s", headerName))
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			errorLog.Log(logging.MessageKey(), "invalid authorization header", "name", headerName, "token", headerValue, logging.ErrorKey(), err)
			WriteJsonError(response, forbiddenStatusCode, fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error()))
			return
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.Path)

		satClientID := extractSatClientID(token, logger)

		valid, err := a.Validator.Validate(ctx, token)
		if err == nil && valid {
			request = request.WithContext(NewContextSatID(request.Context(), satClientID))
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		errorLog.Log(
			logging.MessageKey(), "request denied",
			"validator-response", valid,
			"validator-error", err,
			"sat-client-id", satClientID,
			"token", headerValue,
			"method", request.Method,
			"url", request.URL,
			"user-agent", request.Header.Get("User-Agent"),
			"content-length", request.ContentLength,
			"remoteAddress", request.RemoteAddr,
		)

		WriteJsonError(response, forbiddenStatusCode, "request denied")
	})
}

func extractSatClientID(token *secure.Token, logger log.Logger) (satClientID string) {
	satClientID = "N/A"
	if token.Type() == secure.Bearer {
		if jwsObj, errJWSParse := secure.DefaultJWSParser.ParseJWS(token); errJWSParse == nil {
			if claims, ok := jwsObj.Payload().(jws.Claims); ok {
				if satClientIDStr, isString := claims.Get("sub").(string); isString {
					satClientID = satClientIDStr
				} else {
					logging.Error(logger).Log(logging.MessageKey(), "JWT Claim value was not of string type")
				}
			}
		} else {
			logging.Error(logger).Log(logging.MessageKey(), "Unexpected non-fatal JWS parse error", logging.ErrorKey(), errJWSParse)
		}
	}
	return
}

//NewContextSatID returns a context with the specified value
func NewContextSatID(ctx context.Context, satClientID string) context.Context {
	return context.WithValue(ctx, satClientIDKey, satClientID)
}

//FromContextSatID retrieves the SatClientID (if any) from the given context
//the second result indicates whether
func FromContextSatID(ctx context.Context) (string, bool) {
	ID, ok := ctx.Value(satClientIDKey).(string)
	return ID, ok
}
<commit_msg>simplify context key struct<commit_after>package handler

import (
	"context"
	"fmt"
	"net/http"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"github.com/SermoDigital/jose/jws"
	"github.com/go-kit/kit/log"
)

//satClientIDKey is the key to set/get sat client IDs using contexts.
var satClientIDKey = struct{}{}

const (
	// The Content-Type value for JSON
	JsonContentType string = "application/json; charset=UTF-8"

	// The Content-Type header
	ContentTypeHeader string = "Content-Type"

	// The X-Content-Type-Options header
	ContentTypeOptionsHeader string = "X-Content-Type-Options"

	// NoSniff is the value used for content options for errors written by this package
	NoSniff string = "nosniff"
)

// WriteJsonError writes a standard JSON error to the response
func WriteJsonError(response http.ResponseWriter, code int, message string) error {
	response.Header().Set(ContentTypeHeader, JsonContentType)
	response.Header().Set(ContentTypeOptionsHeader, NoSniff)

	response.WriteHeader(code)
	_, err := fmt.Fprintf(response, `{"message": "%s"}`, message)
	return err
}

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              log.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() log.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return logging.DefaultLogger()
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	var (
		headerName          = a.headerName()
		forbiddenStatusCode = a.forbiddenStatusCode()
		logger              = a.logger()
		errorLog            = logging.Error(logger)
	)

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			errorLog.Log(logging.MessageKey(), "missing header", "name", headerName)
			WriteJsonError(response, forbiddenStatusCode, fmt.Sprintf("missing header: %s", headerName))
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			errorLog.Log(logging.MessageKey(), "invalid authorization header", "name", headerName, "token", headerValue, logging.ErrorKey(), err)
			WriteJsonError(response, forbiddenStatusCode, fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error()))
			return
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.Path)

		satClientID := extractSatClientID(token, logger)

		valid, err := a.Validator.Validate(ctx, token)
		if err == nil && valid {
			request = request.WithContext(NewContextSatID(request.Context(), satClientID))
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		errorLog.Log(
			logging.MessageKey(), "request denied",
			"validator-response", valid,
			"validator-error", err,
			"sat-client-id", satClientID,
			"token", headerValue,
			"method", request.Method,
			"url", request.URL,
			"user-agent", request.Header.Get("User-Agent"),
			"content-length", request.ContentLength,
			"remoteAddress", request.RemoteAddr,
		)

		WriteJsonError(response, forbiddenStatusCode, "request denied")
	})
}

func extractSatClientID(token *secure.Token, logger log.Logger) (satClientID string) {
	satClientID = "N/A"
	if token.Type() == secure.Bearer {
		if jwsObj, errJWSParse := secure.DefaultJWSParser.ParseJWS(token); errJWSParse == nil {
			if claims, ok := jwsObj.Payload().(jws.Claims); ok {
				if satClientIDStr, isString := claims.Get("sub").(string); isString {
					satClientID = satClientIDStr
				} else {
					logging.Error(logger).Log(logging.MessageKey(), "JWT Claim value was not of string type")
				}
			}
		} else {
			logging.Error(logger).Log(logging.MessageKey(), "Unexpected non-fatal JWS parse error", logging.ErrorKey(), errJWSParse)
		}
	}
	return
}

//NewContextSatID returns a context with the specified value
func NewContextSatID(ctx context.Context, satClientID string) context.Context {
	return context.WithValue(ctx, satClientIDKey, satClientID)
}

//FromContextSatID retrieves the SatClientID (if any) from the given context
//the second result indicates whether
func FromContextSatID(ctx context.Context) (string, bool) {
	ID, ok := ctx.Value(satClientIDKey).(string)
	return ID, ok
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/gtfierro/cs262-project/common"
	"github.com/tinylib/msgp/msgp"
	"io"
	"net"
	"sync"
	"time"
)

type Coordinator struct {
	address            *net.TCPAddr
	conn               *net.TCPConn
	clientside_address string
	coordside_address  string
	sendL              sync.Mutex
	broker             *RemoteBroker
	brokerID           common.UUID
	encoder            *msgp.Writer

	// the number of seconds to wait before retrying to
	// contact coordinator server
	retryTime int
	// the maximum interval to increase to between attempts to contact
	// the coordinator server
	retryTimeMax int
	// handles outstanding messages that need an ACK
	requests *outstandingManager
	queue    *sendableQueue
}

func ConnectCoordinator(config common.ServerConfig, s *Server) *Coordinator {
	var err error

	c := &Coordinator{broker: s.broker.(*RemoteBroker),
		retryTime:          1,
		retryTimeMax:       60,
		requests:           newOutstandingManager(),
		queue:              newSendableQueue(100),
		clientside_address: fmt.Sprintf("%s:%d", config.Host, config.Port),
		brokerID:           config.BrokerID,
	}

	coordinatorAddress := fmt.Sprintf("%s:%d", config.CoordinatorHost, config.CoordinatorPort)
	c.address, err = net.ResolveTCPAddr("tcp", coordinatorAddress)
	if err != nil {
		log.WithFields(log.Fields{
			"addr": c.address, "error": err,
		}).Fatal("Could not resolve the generated TCP address")
	}
	// Dial a connection to the Coordinator server
	c.rebuildConnection()
	// send a heartbeat as well
	c.sendHeartbeat()
	// before we send, we want to setup the ping/pong service
	go c.handleStateMachine()
	go c.startBeating()

	return c
}

func (c *Coordinator) rebuildConnection() {
	var err error
	c.sendL.Lock()
	defer c.sendL.Unlock()

	c.conn, err = net.DialTCP("tcp", nil, c.address)
	for err != nil {
		log.WithFields(log.Fields{
			"err": err, "server": c.address, "retry": c.retryTime,
		}).Error("Failed to contact coordinator server. Retrying")
		time.Sleep(time.Duration(c.retryTime) * time.Second)
		// increase retry window by factor of 2
		if c.retryTime*2 < c.retryTimeMax {
			c.retryTime *= 2
		} else {
			c.retryTime = c.retryTimeMax
		}
		// Dial a connection to the Coordinator server
		c.conn, err = net.DialTCP("tcp", nil, c.address)
	}
	// if we were successful, reset the wait timer
	c.retryTime = 1
	c.encoder = msgp.NewWriter(c.conn)
	// save the address we're using to connect
	c.coordside_address = c.conn.LocalAddr().String()

	// when we come online, send the BrokerConnectMessage to inform the coordinator
	// server where it should send clients
	// TODO should do something else for the BrokerID since we want it to persist after restarts
	bcm := &common.BrokerConnectMessage{BrokerInfo: common.BrokerInfo{
		BrokerID:         c.brokerID,
		ClientBrokerAddr: c.clientside_address,
		CoordBrokerAddr:  c.coordside_address,
	}, MessageIDStruct: common.GetMessageIDStruct()}
	bcm.Encode(c.encoder)
	// do the actual sending
	c.encoder.Flush()

	//TODO: does this actually work as expected?
	// do replay
	//c.queue.startReplay()
	//for msg := range c.queue.c {
	//	c.send(msg)
	//}
}

// This method handles the bookkeeping messages from the coordinator server
func (c *Coordinator) handleStateMachine() {
	reader := msgp.NewReader(c.conn)
	for {
		msg, err := common.MessageFromDecoderMsgp(reader)
		// when the connection with the coordinator breaks, buffer
		// all outgoing messages
		if err == io.EOF {
			c.rebuildConnection()
			log.Warn("Coordinator is no longer reachable!")
			break
		}
		if err != nil {
			log.WithFields(log.Fields{
				"brokerID": c.brokerID, "message": msg, "error": err, "coordinator": c.address,
			}).Warn("Could not decode incoming message from coordinator")
		}
		// handle incoming message types
		switch m := msg.(type) {
		case *common.RequestHeartbeatMessage:
			log.Info("Received heartbeat from coordinator")
			c.sendHeartbeat()
		case *common.ForwardRequestMessage:
			log.Infof("Received forward request message %v", m)
			c.broker.AddForwardingEntries(m)
			c.ack(m.GetID())
		case *common.BrokerSubscriptionDiffMessage:
			log.Infof("Subscription Diff message %v", m)
			c.broker.ForwardSubscriptionDiffs(m)
			c.broker.UpdateForwardingEntries(m)
			c.ack(m.GetID())
		case *common.CancelForwardRequest:
			c.broker.RemoveForwardingEntry(m)
			c.requests.GotMessage(m)
			c.ack(m.GetID())
		case *common.AcknowledgeMessage:
			c.requests.GotMessage(m)
		case *common.BrokerDeathMessage:
			log.Infof("Got Broker Death Message %v", m)
			//TODO: handle broker death
			c.ack(m.GetID())
		case common.Message:
			log.Infof("Got a %T message %v", m, m)
			c.requests.GotMessage(m)
		default:
			log.WithFields(log.Fields{
				"message": m, "coordinator": c.address,
			}).Warn("I don't know what to do with this")
		}
	}
}

func (c *Coordinator) send(m common.Sendable) {
	c.sendL.Lock()
	defer c.sendL.Unlock()
	if err := m.Encode(c.encoder); err != nil {
		log.WithFields(log.Fields{
			"error": err, "coordinator": c.address, "message": m,
		}).Error("Could not send message to coordinator")
		return
	}
	if err := c.encoder.Flush(); err != nil {
		log.WithFields(log.Fields{
			"error": err, "coordinator": c.address, "message": m,
		}).Error("Could not send message to coordinator")
		// buffer!
		//c.queue.append(m)
	}
}

func (c *Coordinator) ack(id common.MessageIDType) {
	c.send(&common.AcknowledgeMessage{MessageID: id})
}

func (c *Coordinator) sendHeartbeat() {
	log.WithFields(log.Fields{
		"coordinator": c.address,
	}).Debug("Sending hearbeat")
	hb := &common.HeartbeatMessage{}
	c.send(hb)
}

func (c *Coordinator) startBeating() {
	tick := time.NewTicker(5 * time.Second)
	for range tick.C {
		c.sendHeartbeat()
	}
}

// if we receive a subscription and we are *not* using local evaluation,
// then we wrap it up in a BrokerQueryMessage and forward it to the coordinator
//   type BrokerQueryMessage struct {
//   	QueryMessage string
//   	ClientAddr   string
//   }
func (c *Coordinator) forwardSubscription(query string, clientID common.UUID, client net.Conn) {
	bqm := &common.BrokerQueryMessage{
		Query: query,
		UUID:  clientID,
	}
	bqm.MessageID = common.GetMessageID()
	c.send(bqm)
	response, _ := c.requests.WaitForMessage(bqm.GetID())
	switch m := response.(type) {
	case *common.AcknowledgeMessage:
		log.Debugf("Response %v", m)
	case *common.CancelForwardRequest:
		log.Debugf("Got cancel forward request %v", m)
	}
}

// this forwards a publish message from a local producer to the coordinator and receives
// a BrokerSubscriptionDiffMessage in response
func (c *Coordinator) forwardPublish(msg *common.PublishMessage) {
	var bpm = new(common.BrokerPublishMessage)
	bpm.FromPublishMessage(msg)
	c.send(bpm)
	log.Debug("Waiting for publish response")
	response, _ := c.requests.WaitForMessage(bpm.GetID())
	log.Debugf("Got response for pub %v", response)
	if _, ok := response.(*common.AcknowledgeMessage); !ok {
		log.WithFields(log.Fields{
			"response": response,
		}).Error("Did not get a proper acknowledgement")
	}
}

func (c *Coordinator) terminateClient(client *Client) {
	var ctm = &common.ClientTerminationMessage{
		ClientID: client.ID,
	}
	ctm.MessageID = common.GetMessageID()
	c.send(ctm)
	response, _ := c.requests.WaitForMessage(ctm.GetID())
	switch response.(type) {
	case *common.AcknowledgeMessage:
	default:
		log.Error("Did not get an ACK!")
	}
}
<commit_msg>fix error message<commit_after>package main

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/gtfierro/cs262-project/common"
	"github.com/tinylib/msgp/msgp"
	"io"
	"net"
	"sync"
	"time"
)

type Coordinator struct {
	address            *net.TCPAddr
	conn               *net.TCPConn
	clientside_address string
	coordside_address  string
	sendL              sync.Mutex
	broker             *RemoteBroker
	brokerID           common.UUID
	encoder            *msgp.Writer

	// the number of seconds to wait before retrying to
	// contact coordinator server
	retryTime int
	// the maximum interval to increase to between attempts to contact
	// the coordinator server
	retryTimeMax int
	// handles outstanding messages that need an ACK
	requests *outstandingManager
	queue    *sendableQueue
}

func ConnectCoordinator(config common.ServerConfig, s *Server) *Coordinator {
	var err error

	c := &Coordinator{broker: s.broker.(*RemoteBroker),
		retryTime:          1,
		retryTimeMax:       60,
		requests:           newOutstandingManager(),
		queue:              newSendableQueue(100),
		clientside_address: fmt.Sprintf("%s:%d", config.Host, config.Port),
		brokerID:           config.BrokerID,
	}

	coordinatorAddress := fmt.Sprintf("%s:%d", config.CoordinatorHost, config.CoordinatorPort)
	c.address, err = net.ResolveTCPAddr("tcp", coordinatorAddress)
	if err != nil {
		log.WithFields(log.Fields{
			"addr": c.address, "error": err,
		}).Fatal("Could not resolve the generated TCP address")
	}
	// Dial a connection to the Coordinator server
	c.rebuildConnection()
	// send a heartbeat as well
	c.sendHeartbeat()
	// before we send, we want to setup the ping/pong service
	go c.handleStateMachine()
	go c.startBeating()

	return c
}

func (c *Coordinator) rebuildConnection() {
	var err error
	c.sendL.Lock()
	defer c.sendL.Unlock()

	c.conn, err = net.DialTCP("tcp", nil, c.address)
	for err != nil {
		log.WithFields(log.Fields{
			"err": err, "server": c.address, "retry": c.retryTime,
		}).Error("Failed to contact coordinator server. Retrying")
		time.Sleep(time.Duration(c.retryTime) * time.Second)
		// increase retry window by factor of 2
		if c.retryTime*2 < c.retryTimeMax {
			c.retryTime *= 2
		} else {
			c.retryTime = c.retryTimeMax
		}
		// Dial a connection to the Coordinator server
		c.conn, err = net.DialTCP("tcp", nil, c.address)
	}
	// if we were successful, reset the wait timer
	c.retryTime = 1
	c.encoder = msgp.NewWriter(c.conn)
	// save the address we're using to connect
	c.coordside_address = c.conn.LocalAddr().String()

	// when we come online, send the BrokerConnectMessage to inform the coordinator
	// server where it should send clients
	// TODO should do something else for the BrokerID since we want it to persist after restarts
	bcm := &common.BrokerConnectMessage{BrokerInfo: common.BrokerInfo{
		BrokerID:         c.brokerID,
		ClientBrokerAddr: c.clientside_address,
		CoordBrokerAddr:  c.coordside_address,
	}, MessageIDStruct: common.GetMessageIDStruct()}
	bcm.Encode(c.encoder)
	// do the actual sending
	c.encoder.Flush()

	//TODO: does this actually work as expected?
	// do replay
	//c.queue.startReplay()
	//for msg := range c.queue.c {
	//	c.send(msg)
	//}
}

// This method handles the bookkeeping messages from the coordinator server
func (c *Coordinator) handleStateMachine() {
	reader := msgp.NewReader(c.conn)
	for {
		msg, err := common.MessageFromDecoderMsgp(reader)
		// when the connection with the coordinator breaks, buffer
		// all outgoing messages
		if err == io.EOF {
			c.rebuildConnection()
			log.Warn("Coordinator is no longer reachable!")
			break
		}
		if err != nil {
			log.WithFields(log.Fields{
				"brokerID": c.brokerID, "message": msg, "error": err, "coordinator": c.address,
			}).Warn("Could not decode incoming message from coordinator")
		}
		// handle incoming message types
		switch m := msg.(type) {
		case *common.RequestHeartbeatMessage:
			log.Info("Received heartbeat from coordinator")
			c.sendHeartbeat()
		case *common.ForwardRequestMessage:
			log.Infof("Received forward request message %v", m)
			c.broker.AddForwardingEntries(m)
			c.ack(m.GetID())
		case *common.BrokerSubscriptionDiffMessage:
			log.Infof("Subscription Diff message %v", m)
			c.broker.ForwardSubscriptionDiffs(m)
			c.broker.UpdateForwardingEntries(m)
			c.ack(m.GetID())
		case *common.CancelForwardRequest:
			c.broker.RemoveForwardingEntry(m)
			c.requests.GotMessage(m)
			c.ack(m.GetID())
		case *common.AcknowledgeMessage:
			c.requests.GotMessage(m)
		case *common.BrokerDeathMessage:
			log.Infof("Got Broker Death Message %v", m)
			//TODO: handle broker death
			c.ack(m.GetID())
		case common.Message:
			log.Infof("Got a %T message %v", m, m)
			c.requests.GotMessage(m)
		default:
			log.WithFields(log.Fields{
				"message": m, "coordinator": c.address,
			}).Warn("I don't know what to do with this")
		}
	}
}

func (c *Coordinator) send(m common.Sendable) {
	c.sendL.Lock()
	defer c.sendL.Unlock()
	if err := m.Encode(c.encoder); err != nil {
		log.WithFields(log.Fields{
			"error": err, "coordinator": c.address, "message": m,
		}).Error("Could not encode message to coordinator")
		return
	}
	if err := c.encoder.Flush(); err != nil {
		log.WithFields(log.Fields{
			"error": err, "coordinator": c.address, "message": m,
		}).Error("Could not send message to coordinator")
		// buffer!
		//c.queue.append(m)
	}
}

func (c *Coordinator) ack(id common.MessageIDType) {
	c.send(&common.AcknowledgeMessage{MessageID: id})
}

func (c *Coordinator) sendHeartbeat() {
	log.WithFields(log.Fields{
		"coordinator": c.address,
	}).Debug("Sending hearbeat")
	hb := &common.HeartbeatMessage{}
	c.send(hb)
}

func (c *Coordinator) startBeating() {
	tick := time.NewTicker(5 * time.Second)
	for range tick.C {
		c.sendHeartbeat()
	}
}

// if we receive a subscription and we are *not* using local evaluation,
// then we wrap it up in a BrokerQueryMessage and forward it to the coordinator
//   type BrokerQueryMessage struct {
//   	QueryMessage string
//   	ClientAddr   string
//   }
func (c *Coordinator) forwardSubscription(query string, clientID common.UUID, client net.Conn) {
	bqm := &common.BrokerQueryMessage{
		Query: query,
		UUID:  clientID,
	}
	bqm.MessageID = common.GetMessageID()
	c.send(bqm)
	response, _ := c.requests.WaitForMessage(bqm.GetID())
	switch m := response.(type) {
	case *common.AcknowledgeMessage:
		log.Debugf("Response %v", m)
	case *common.CancelForwardRequest:
		log.Debugf("Got cancel forward request %v", m)
	}
}

// this forwards a publish message from a local producer to the coordinator and receives
// a BrokerSubscriptionDiffMessage in response
func (c *Coordinator) forwardPublish(msg *common.PublishMessage) {
	var bpm = new(common.BrokerPublishMessage)
	bpm.FromPublishMessage(msg)
	c.send(bpm)
	log.Debug("Waiting for publish response")
	response, _ := c.requests.WaitForMessage(bpm.GetID())
	log.Debugf("Got response for pub %v", response)
	if _, ok := response.(*common.AcknowledgeMessage); !ok {
		log.WithFields(log.Fields{
			"response": response,
		}).Error("Did not get a proper acknowledgement")
	}
}

func (c *Coordinator) terminateClient(client *Client) {
	var ctm = &common.ClientTerminationMessage{
		ClientID: client.ID,
	}
	ctm.MessageID = common.GetMessageID()
	c.send(ctm)
	response, _ := c.requests.WaitForMessage(ctm.GetID())
	switch response.(type) {
	case *common.AcknowledgeMessage:
	default:
		log.Error("Did not get an ACK!")
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 network

import (
	"context"
	"fmt"
	"net"
	"time"

	"github.com/onsi/ginkgo"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	"k8s.io/kubernetes/test/e2e/framework"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	"k8s.io/kubernetes/test/e2e/network/common"
	imageutils "k8s.io/kubernetes/test/utils/image"
)

const (
	testPodPort    = "8080"
	noSNATTestName = "no-snat-test"
)

var (
	testPod = v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: noSNATTestName,
			Labels: map[string]string{
				noSNATTestName: "",
			},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  noSNATTestName,
					Image: imageutils.GetE2EImage(imageutils.Agnhost),
					Args:  []string{"netexec", "--http-port", testPodPort},
				},
			},
		},
	}
)

// This test verifies that a Pod on each node in a cluster can talk to Pods on every other node without SNAT.
// We use the [Feature:NoSNAT] tag so that most jobs will skip this test by default.
var _ = common.SIGDescribe("NoSNAT [Feature:NoSNAT] [Slow]", func() {
	f := framework.NewDefaultFramework("no-snat-test")
	ginkgo.It("Should be able to send traffic between Pods without SNAT", func() {
		cs := f.ClientSet
		pc := cs.CoreV1().Pods(f.Namespace.Name)
		nc := cs.CoreV1().Nodes()

		ginkgo.By("creating a test pod on each Node")
		nodes, err := nc.List(context.TODO(), metav1.ListOptions{})
		framework.ExpectNoError(err)
		framework.ExpectNotEqual(len(nodes.Items), 0, "no Nodes in the cluster")

		for _, node := range nodes.Items {
			// target Pod at Node
			nodeSelection := e2epod.NodeSelection{Name: node.Name}
			e2epod.SetNodeSelection(&testPod.Spec, nodeSelection)
			_, err = pc.Create(context.TODO(), &testPod, metav1.CreateOptions{})
			framework.ExpectNoError(err)
		}

		ginkgo.By("waiting for all of the no-snat-test pods to be scheduled and running")
		err = wait.PollImmediate(10*time.Second, 1*time.Minute, func() (bool, error) {
			pods, err := pc.List(context.TODO(), metav1.ListOptions{LabelSelector: noSNATTestName})
			if err != nil {
				return false, err
			}

			// check all pods are running
			for _, pod := range pods.Items {
				if pod.Status.Phase != v1.PodRunning {
					if pod.Status.Phase != v1.PodPending {
						return false, fmt.Errorf("expected pod to be in phase \"Pending\" or \"Running\"")
					}
					return false, nil // pod is still pending
				}
			}
			return true, nil // all pods are running
		})
		framework.ExpectNoError(err)

		ginkgo.By("sending traffic from each pod to the others and checking that SNAT does not occur")
		pods, err := pc.List(context.TODO(), metav1.ListOptions{LabelSelector: noSNATTestName})
		framework.ExpectNoError(err)

		// hit the /clientip endpoint on every other Pods to check if source ip is preserved
		// this test is O(n^2) but it doesn't matter because we only run this test on small clusters (~3 nodes)
		for _, sourcePod := range pods.Items {
			for _, targetPod := range pods.Items {
				if targetPod.Name == sourcePod.Name {
					continue
				}
				targetAddr := net.JoinHostPort(targetPod.Status.PodIP, testPodPort)
				sourceIP, execPodIP := execSourceIPTest(sourcePod, targetAddr)
				ginkgo.By("Verifying the preserved source ip")
				framework.ExpectEqual(sourceIP, execPodIP)
			}
		}
	})
})
<commit_msg>e2e create pods only on schedulable nodes<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 network

import (
	"context"
	"fmt"
	"net"
	"time"

	"github.com/onsi/ginkgo"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	"k8s.io/kubernetes/test/e2e/framework"
	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
	"k8s.io/kubernetes/test/e2e/network/common"
	imageutils "k8s.io/kubernetes/test/utils/image"
)

const (
	testPodPort    = "8080"
	noSNATTestName = "no-snat-test"
)

var (
	testPod = v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: noSNATTestName,
			Labels: map[string]string{
				noSNATTestName: "",
			},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  noSNATTestName,
					Image: imageutils.GetE2EImage(imageutils.Agnhost),
					Args:  []string{"netexec", "--http-port", testPodPort},
				},
			},
		},
	}
)

// This test verifies that a Pod on each node in a cluster can talk to Pods on every other node without SNAT.
// We use the [Feature:NoSNAT] tag so that most jobs will skip this test by default.
var _ = common.SIGDescribe("NoSNAT [Feature:NoSNAT] [Slow]", func() {
	f := framework.NewDefaultFramework("no-snat-test")
	ginkgo.It("Should be able to send traffic between Pods without SNAT", func() {
		cs := f.ClientSet
		pc := cs.CoreV1().Pods(f.Namespace.Name)

		ginkgo.By("creating a test pod on each Node")
		nodes, err := e2enode.GetReadySchedulableNodes(cs)
		framework.ExpectNoError(err)
		framework.ExpectNotEqual(len(nodes.Items), 0, "no Nodes in the cluster")

		for _, node := range nodes.Items {
			// target Pod at Node
			nodeSelection := e2epod.NodeSelection{Name: node.Name}
			e2epod.SetNodeSelection(&testPod.Spec, nodeSelection)
			_, err = pc.Create(context.TODO(), &testPod, metav1.CreateOptions{})
			framework.ExpectNoError(err)
		}

		ginkgo.By("waiting for all of the no-snat-test pods to be scheduled and running")
		err = wait.PollImmediate(10*time.Second, 1*time.Minute, func() (bool, error) {
			pods, err := pc.List(context.TODO(), metav1.ListOptions{LabelSelector: noSNATTestName})
			if err != nil {
				return false, err
			}

			// check all pods are running
			for _, pod := range pods.Items {
				if pod.Status.Phase != v1.PodRunning {
					if pod.Status.Phase != v1.PodPending {
						return false, fmt.Errorf("expected pod to be in phase \"Pending\" or \"Running\"")
					}
					return false, nil // pod is still pending
				}
			}
			return true, nil // all pods are running
		})
		framework.ExpectNoError(err)

		ginkgo.By("sending traffic from each pod to the others and checking that SNAT does not occur")
		pods, err := pc.List(context.TODO(), metav1.ListOptions{LabelSelector: noSNATTestName})
		framework.ExpectNoError(err)

		// hit the /clientip endpoint on every other Pods to check if source ip is preserved
		// this test is O(n^2) but it doesn't matter because we only run this test on small clusters (~3 nodes)
		for _, sourcePod := range pods.Items {
			for _, targetPod := range pods.Items {
				if targetPod.Name == sourcePod.Name {
					continue
				}
				targetAddr := net.JoinHostPort(targetPod.Status.PodIP, testPodPort)
				sourceIP, execPodIP := execSourceIPTest(sourcePod, targetAddr)
				ginkgo.By("Verifying the preserved source ip")
				framework.ExpectEqual(sourceIP, execPodIP)
			}
		}
	})
})
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package exec

import (
	"os"
	"strings"
)

// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = os.ErrorString("executable file not found in %PATH%")

func chkStat(file string) os.Error {
	d, err := os.Stat(file)
	if err != nil {
		return err
	}
	if d.IsRegular() {
		return nil
	}
	return os.EPERM
}

func findExecutable(file string, exts []string) (string, os.Error) {
	if len(exts) == 0 {
		return file, chkStat(file)
	}
	f := strings.ToLower(file)
	for _, e := range exts {
		if strings.HasSuffix(f, e) {
			return file, chkStat(file)
		}
	}
	for _, e := range exts {
		if f := file + e; chkStat(f) == nil {
			return f, nil
		}
	}
	return ``, ErrNotFound
}

func LookPath(file string) (f string, err os.Error) {
	exts := []string{}
	if x := os.Getenv(`PATHEXT`); x != `` {
		exts = strings.Split(strings.ToLower(x), `;`, -1)
		for i, e := range exts {
			if e == `` || e[0] != '.' {
				exts[i] = `.` + e
			}
		}
	}
	if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
		if f, err = findExecutable(file, exts); err == nil {
			return
		}
		return ``, &Error{file, err}
	}
	if pathenv := os.Getenv(`PATH`); pathenv == `` {
		if f, err = findExecutable(`.\`+file, exts); err == nil {
			return
		}
	} else {
		for _, dir := range strings.Split(pathenv, `;`, -1) {
			if f, err = findExecutable(dir+`\`+file, exts); err == nil {
				return
			}
		}
	}
	return ``, &Error{file, ErrNotFound}
}
<commit_msg>exec: make LookPath work even when PATHEXT env variable is not set on Windows<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package exec

import (
	"os"
	"strings"
)

// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = os.ErrorString("executable file not found in %PATH%")

func chkStat(file string) os.Error {
	d, err := os.Stat(file)
	if err != nil {
		return err
	}
	if d.IsRegular() {
		return nil
	}
	return os.EPERM
}

func findExecutable(file string, exts []string) (string, os.Error) {
	if len(exts) == 0 {
		return file, chkStat(file)
	}
	f := strings.ToLower(file)
	for _, e := range exts {
		if strings.HasSuffix(f, e) {
			return file, chkStat(file)
		}
	}
	for _, e := range exts {
		if f := file + e; chkStat(f) == nil {
			return f, nil
		}
	}
	return ``, ErrNotFound
}

func LookPath(file string) (f string, err os.Error) {
	x := os.Getenv(`PATHEXT`)
	if x == `` {
		x = `.COM;.EXE;.BAT;.CMD`
	}
	exts := []string{}
	for _, e := range strings.Split(strings.ToLower(x), `;`, -1) {
		if e == "" {
			continue
		}
		if e[0] != '.' {
			e = "." + e
		}
		exts = append(exts, e)
	}
	if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
		if f, err = findExecutable(file, exts); err == nil {
			return
		}
		return ``, &Error{file, err}
	}
	if pathenv := os.Getenv(`PATH`); pathenv == `` {
		if f, err = findExecutable(`.\`+file, exts); err == nil {
			return
		}
	} else {
		for _, dir := range strings.Split(pathenv, `;`, -1) {
			if f, err = findExecutable(dir+`\`+file, exts); err == nil {
				return
			}
		}
	}
	return ``, &Error{file, ErrNotFound}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A package of simple functions to manipulate strings.
package strings

import (
	"unicode"
	"utf8"
)

// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n <= 0 means no limit).
// Invalid UTF-8 sequences become correct encodings of U+FFF8.
func explode(s string, n int) []string {
	if n <= 0 {
		n = len(s)
	}
	a := make([]string, n)
	var size, rune int
	na := 0
	for len(s) > 0 {
		if na+1 >= n {
			a[na] = s
			na++
			break
		}
		rune, size = utf8.DecodeRuneInString(s)
		s = s[size:]
		a[na] = string(rune)
		na++
	}
	return a[0:na]
}

// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep string) int {
	if sep == "" {
		return utf8.RuneCountInString(s) + 1
	}
	c := sep[0]
	n := 0
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			n++
			i += len(sep) - 1
		}
	}
	return n
}

// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return 0
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return len(s)
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := len(s) - 1; i >= 0; i-- {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := len(s) - n; i >= 0; i-- {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string {
	if sep == "" {
		return explode(s, n)
	}
	if n <= 0 {
		n = Count(s, sep) + 1
	}
	c := sep[0]
	start := 0
	a := make([]string, n)
	na := 0
	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start : i+sepSave]
			na++
			start = i + len(sep)
			i += len(sep) - 1
		}
	}
	a[na] = s[start:]
	return a[0 : na+1]
}

// Split splits the string s around each instance of sep, returning an array of substrings of s.
// If sep is empty, Split splits s after each UTF-8 sequence.
// If n > 0, Split splits s into at most n substrings; the last substring will be the unsplit remainder.
func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }

// SplitAfter splits the string s after each instance of sep, returning an array of substrings of s.
// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
// If n > 0, SplitAfter splits s into at most n substrings; the last substring will be the unsplit remainder.
func SplitAfter(s, sep string, n int) []string {
	return genSplit(s, sep, len(sep), n)
}

// Fields splits the string s around each instance of one or more consecutive white space
// characters, returning an array of substrings of s or an empty list if s contains only white space.
func Fields(s string) []string {
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !unicode.IsSpace(rune)
		if inField && !wasInField {
			n++
		}
	}

	a := make([]string, n)
	na := 0
	fieldStart := -1
	for i, rune := range s {
		if unicode.IsSpace(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart != -1 {
		a[na] = s[fieldStart:]
		na++
	}
	return a[0:na]
}

// Join concatenates the elements of a to create a single string.   The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := 0
	for i := 0; i < len(a); i++ {
		s := a[i]
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
		if i+1 < len(a) {
			s = sep
			for j := 0; j < len(s); j++ {
				b[bp] = s[j]
				bp++
			}
		}
	}
	return string(b)
}

// HasPrefix tests whether the string s begins with prefix.
func HasPrefix(s, prefix string) bool {
	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}

// HasSuffix tests whether the string s ends with suffix.
func HasSuffix(s, suffix string) bool {
	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}

// Map returns a copy of the string s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement.
func Map(mapping func(rune int) int, s string) string {
	// In the worst case, the string can grow when mapped, making
	// things unpleasant.  But it's so rare we barge in assuming it's
	// fine.  It could also shrink but that falls out naturally.
	maxbytes := len(s) // length of b
	nbytes := 0        // number of bytes encoded in b
	b := make([]byte, maxbytes)
	for _, c := range s {
		rune := mapping(c)
		if rune >= 0 {
			wid := 1
			if rune >= utf8.RuneSelf {
				wid = utf8.RuneLen(rune)
			}
			if nbytes+wid > maxbytes {
				// Grow the buffer.
				maxbytes = maxbytes*2 + utf8.UTFMax
				nb := make([]byte, maxbytes)
				for i, c := range b[0:nbytes] {
					nb[i] = c
				}
				b = nb
			}
			nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
		}
	}
	return string(b[0:nbytes])
}

// Repeat returns a new string consisting of count copies of the string s.
func Repeat(s string, count int) string {
	b := make([]byte, len(s)*count)
	bp := 0
	for i := 0; i < count; i++ {
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
	}
	return string(b)
}

// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
func ToUpper(s string) string { return Map(unicode.ToUpper, s) }

// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
func ToLower(s string) string { return Map(unicode.ToLower, s) }

// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }

// Trim returns a slice of the string s, with all leading and trailing white space
// removed, as defined by Unicode.
func TrimSpace(s string) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRuneInString(s[start:end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		start += wid
	}
	for start < end {
		wid := 1
		rune := int(s[end-1])
		if rune >= utf8.RuneSelf {
			// Back up carefully looking for beginning of rune. Mustn't pass start.
			for wid = 2; start <= end-wid && !utf8.RuneStart(s[end-wid]); wid++ {
			}
			if start > end-wid { // invalid UTF-8 sequence; stop processing
				return s[start:end]
			}
			rune, wid = utf8.DecodeRuneInString(s[end-wid : end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		end -= wid
	}
	return s[start:end]
}
<commit_msg>strings: make Split(s, "", n) faster<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A package of simple functions to manipulate strings.
package strings

import (
	"unicode"
	"utf8"
)

// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n <= 0 means no limit).
// Invalid UTF-8 sequences become correct encodings of U+FFF8.
func explode(s string, n int) []string {
	l := utf8.RuneCountInString(s)
	if n <= 0 || n > l {
		n = l
	}
	a := make([]string, n)
	var size, rune int
	i, cur := 0, 0
	for ; i+1 < n; i++ {
		rune, size = utf8.DecodeRuneInString(s[cur:])
		a[i] = string(rune)
		cur += size
	}
	// add the rest
	a[i] = s[cur:]
	return a
}

// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep string) int {
	if sep == "" {
		return utf8.RuneCountInString(s) + 1
	}
	c := sep[0]
	l := len(sep)
	n := 0
	if l == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				n++
			}
		}
		return n
	}
	for i := 0; i+l <= len(s); i++ {
		if s[i] == c && s[i:i+l] == sep {
			n++
			i += l - 1
		}
	}
	return n
}

// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return 0
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := 0; i < len(s); i++ {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := 0; i+n <= len(s); i++ {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
func LastIndex(s, sep string) int {
	n := len(sep)
	if n == 0 {
		return len(s)
	}
	c := sep[0]
	if n == 1 {
		// special case worth making fast
		for i := len(s) - 1; i >= 0; i-- {
			if s[i] == c {
				return i
			}
		}
		return -1
	}
	// n > 1
	for i := len(s) - n; i >= 0; i-- {
		if s[i] == c && s[i:i+n] == sep {
			return i
		}
	}
	return -1
}

// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string {
	if sep == "" {
		return explode(s, n)
	}
	if n <= 0 {
		n = Count(s, sep) + 1
	}
	c := sep[0]
	start := 0
	a := make([]string, n)
	na := 0
	for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start : i+sepSave]
			na++
			start = i + len(sep)
			i += len(sep) - 1
		}
	}
	a[na] = s[start:]
	return a[0 : na+1]
}

// Split splits the string s around each instance of sep, returning an array of substrings of s.
// If sep is empty, Split splits s after each UTF-8 sequence.
// If n > 0, Split splits s into at most n substrings; the last substring will be the unsplit remainder.
func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }

// SplitAfter splits the string s after each instance of sep, returning an array of substrings of s.
// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
// If n > 0, SplitAfter splits s into at most n substrings; the last substring will be the unsplit remainder.
func SplitAfter(s, sep string, n int) []string {
	return genSplit(s, sep, len(sep), n)
}

// Fields splits the string s around each instance of one or more consecutive white space
// characters, returning an array of substrings of s or an empty list if s contains only white space.
func Fields(s string) []string {
	n := 0
	inField := false
	for _, rune := range s {
		wasInField := inField
		inField = !unicode.IsSpace(rune)
		if inField && !wasInField {
			n++
		}
	}

	a := make([]string, n)
	na := 0
	fieldStart := -1
	for i, rune := range s {
		if unicode.IsSpace(rune) {
			if fieldStart >= 0 {
				a[na] = s[fieldStart:i]
				na++
				fieldStart = -1
			}
		} else if fieldStart == -1 {
			fieldStart = i
		}
	}
	if fieldStart != -1 {
		a[na] = s[fieldStart:]
		na++
	}
	return a[0:na]
}

// Join concatenates the elements of a to create a single string.   The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := 0
	for i := 0; i < len(a); i++ {
		s := a[i]
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
		if i+1 < len(a) {
			s = sep
			for j := 0; j < len(s); j++ {
				b[bp] = s[j]
				bp++
			}
		}
	}
	return string(b)
}

// HasPrefix tests whether the string s begins with prefix.
func HasPrefix(s, prefix string) bool {
	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}

// HasSuffix tests whether the string s ends with suffix.
func HasSuffix(s, suffix string) bool {
	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}

// Map returns a copy of the string s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement.
func Map(mapping func(rune int) int, s string) string {
	// In the worst case, the string can grow when mapped, making
	// things unpleasant.  But it's so rare we barge in assuming it's
	// fine.  It could also shrink but that falls out naturally.
	maxbytes := len(s) // length of b
	nbytes := 0        // number of bytes encoded in b
	b := make([]byte, maxbytes)
	for _, c := range s {
		rune := mapping(c)
		if rune >= 0 {
			wid := 1
			if rune >= utf8.RuneSelf {
				wid = utf8.RuneLen(rune)
			}
			if nbytes+wid > maxbytes {
				// Grow the buffer.
				maxbytes = maxbytes*2 + utf8.UTFMax
				nb := make([]byte, maxbytes)
				for i, c := range b[0:nbytes] {
					nb[i] = c
				}
				b = nb
			}
			nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
		}
	}
	return string(b[0:nbytes])
}

// Repeat returns a new string consisting of count copies of the string s.
func Repeat(s string, count int) string {
	b := make([]byte, len(s)*count)
	bp := 0
	for i := 0; i < count; i++ {
		for j := 0; j < len(s); j++ {
			b[bp] = s[j]
			bp++
		}
	}
	return string(b)
}

// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
func ToUpper(s string) string { return Map(unicode.ToUpper, s) }

// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
func ToLower(s string) string { return Map(unicode.ToLower, s) }

// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
func ToTitle(s string) string { return Map(unicode.ToTitle, s) }

// Trim returns a slice of the string s, with all leading and trailing white space
// removed, as defined by Unicode.
func TrimSpace(s string) string {
	start, end := 0, len(s)
	for start < end {
		wid := 1
		rune := int(s[start])
		if rune >= utf8.RuneSelf {
			rune, wid = utf8.DecodeRuneInString(s[start:end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		start += wid
	}
	for start < end {
		wid := 1
		rune := int(s[end-1])
		if rune >= utf8.RuneSelf {
			// Back up carefully looking for beginning of rune. Mustn't pass start.
			for wid = 2; start <= end-wid && !utf8.RuneStart(s[end-wid]); wid++ {
			}
			if start > end-wid { // invalid UTF-8 sequence; stop processing
				return s[start:end]
			}
			rune, wid = utf8.DecodeRuneInString(s[end-wid : end])
		}
		if !unicode.IsSpace(rune) {
			break
		}
		end -= wid
	}
	return s[start:end]
}
<|endoftext|>