<commit_before>package proxy

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/dokku/dokku/plugins/common"
	"github.com/dokku/dokku/plugins/config"
	columnize "github.com/ryanuber/columnize"
)

// PortMap is a struct that contains a scheme:host-port:container-port mapping
type PortMap struct {
	ContainerPort int
	HostPort      int
	Scheme        string
}

func (p PortMap) String() string {
	return fmt.Sprintf("%s:%d:%d", p.Scheme, p.HostPort, p.ContainerPort)
}

// IsAppProxyEnabled returns true if proxy is enabled; otherwise return false
func IsAppProxyEnabled(appName string) bool {
	err := common.VerifyAppName(appName)
	if err != nil {
		common.LogFail(err.Error())
	}

	proxyEnabled := true
	disableProxy := config.GetWithDefault(appName, "DOKKU_DISABLE_PROXY", "")
	if disableProxy != "" {
		proxyEnabled = false
	}
	return proxyEnabled
}

// ReportSingleApp is an internal function that displays the app report for one or more apps
func ReportSingleApp(appName string, infoFlag string) error {
	if err := common.VerifyAppName(appName); err != nil {
		return err
	}

	proxyEnabled := "false"
	if IsAppProxyEnabled(appName) {
		proxyEnabled = "true"
	}

	var proxyPortMap []string
	for _, portMap := range getProxyPortMap(appName) {
		proxyPortMap = append(proxyPortMap, portMap.String())
	}

	infoFlags := map[string]string{
		"--proxy-enabled":  proxyEnabled,
		"--proxy-type":     getAppProxyType(appName),
		"--proxy-port-map": strings.Join(proxyPortMap, " "),
	}

	trimPrefix := false
	uppercaseFirstCharacter := true
	return common.ReportSingleApp("proxy", appName, infoFlag, infoFlags, trimPrefix, uppercaseFirstCharacter)
}

func addProxyPorts(appName string, proxyPortMap []PortMap) error {
	allPortMaps := getProxyPortMap(appName)
	allPortMaps = append(allPortMaps, proxyPortMap...)

	return setProxyPorts(appName, allPortMaps)
}

func filterAppProxyPorts(appName string, scheme string, hostPort int) []PortMap {
	var filteredProxyMaps []PortMap
	proxyPortMap := getProxyPortMap(appName)
	for _, portMap := range proxyPortMap {
		if portMap.Scheme == scheme && portMap.HostPort == hostPort {
			filteredProxyMaps = append(filteredProxyMaps, portMap)
		}
	}

	return filteredProxyMaps
}

func getAppName(args []string) (appName string, err error) {
	if len(args) >= 1 {
		appName = args[0]
	} else {
		err = errors.New("Please specify an app to run the command on")
	}

	return
}

func getAppProxyType(appName string) string {
	return config.GetWithDefault(appName, "DOKKU_APP_PROXY_TYPE", "nginx")
}

func getProxyPortMap(appName string) []PortMap {
	value := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "")
	return parseProxyPortMapString(value)
}

func listAppProxyPorts(appName string) error {
	proxyPortMap := getProxyPortMap(appName)

	if len(proxyPortMap) == 0 {
		return errors.New("No port mappings configured for app")
	}

	var lines []string
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		lines = append(lines, "-----> scheme:host port:container port")
	}

	for _, portMap := range proxyPortMap {
		lines = append(lines, portMap.String())
	}

	common.LogInfo1Quiet(fmt.Sprintf("Port mappings for %s", appName))
	config := columnize.DefaultConfig()
	config.Delim = ":"
	config.Prefix = "    "
	config.Empty = ""
	fmt.Println(columnize.Format(lines, config))
	return nil
}

func setProxyPorts(appName string, proxyPortMap []PortMap) error {
	var value []string
	for _, portMap := range uniqueProxyPortMap(proxyPortMap) {
		value = append(value, portMap.String())
	}

	entries := map[string]string{
		"DOKKU_PROXY_PORT_MAP": strings.Join(value, " "),
	}
	return config.SetMany(appName, entries, false)
}

func removeProxyPorts(appName string, proxyPortMap []PortMap) error {
	var toRemove map[string]bool

	for _, portMap := range proxyPortMap {
		toRemove[portMap.String()] = true
	}

	var toSet []PortMap
	existingPortMaps := getProxyPortMap(appName)
	for _, portMap := range existingPortMaps {
		if toRemove[portMap.String()] {
			continue
		}

		toSet = append(toSet, portMap)
	}

	if len(toSet) == 0 {
		keys := []string{"DOKKU_PROXY_PORT_MAP"}
		return config.UnsetMany(appName, keys, false)
	}

	return setProxyPorts(appName, toSet)
}

func parseProxyPortMapString(stringPortMap string) []PortMap {
	var proxyPortMap []PortMap

	for _, v := range strings.Split(strings.TrimSpace(stringPortMap), " ") {
		parts := strings.SplitN(v, ":", 3)
		if len(parts) != 3 {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
			continue
		}

		hostPort, err := strconv.Atoi(parts[1])
		if err != nil {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
		}

		containerPort, err := strconv.Atoi(parts[2])
		if err != nil {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
		}

		proxyPortMap = append(proxyPortMap, PortMap{
			ContainerPort: containerPort,
			HostPort:      hostPort,
			Scheme:        parts[0],
		})
	}

	return uniqueProxyPortMap(proxyPortMap)
}

func uniqueProxyPortMap(proxyPortMap []PortMap) []PortMap {
	var unique []PortMap
	var existingPortMaps map[string]bool

	for _, portMap := range proxyPortMap {
		if existingPortMaps[portMap.String()] {
			continue
		}

		existingPortMaps[portMap.String()] = true
		unique = append(unique, portMap)
	}

	return unique
}
<commit_msg>fix: correct issue with nil map<commit_after>package proxy

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/dokku/dokku/plugins/common"
	"github.com/dokku/dokku/plugins/config"
	columnize "github.com/ryanuber/columnize"
)

// PortMap is a struct that contains a scheme:host-port:container-port mapping
type PortMap struct {
	ContainerPort int
	HostPort      int
	Scheme        string
}

func (p PortMap) String() string {
	return fmt.Sprintf("%s:%d:%d", p.Scheme, p.HostPort, p.ContainerPort)
}

// IsAppProxyEnabled returns true if proxy is enabled; otherwise return false
func IsAppProxyEnabled(appName string) bool {
	err := common.VerifyAppName(appName)
	if err != nil {
		common.LogFail(err.Error())
	}

	proxyEnabled := true
	disableProxy := config.GetWithDefault(appName, "DOKKU_DISABLE_PROXY", "")
	if disableProxy != "" {
		proxyEnabled = false
	}
	return proxyEnabled
}

// ReportSingleApp is an internal function that displays the app report for one or more apps
func ReportSingleApp(appName string, infoFlag string) error {
	if err := common.VerifyAppName(appName); err != nil {
		return err
	}

	proxyEnabled := "false"
	if IsAppProxyEnabled(appName) {
		proxyEnabled = "true"
	}

	var proxyPortMap []string
	for _, portMap := range getProxyPortMap(appName) {
		proxyPortMap = append(proxyPortMap, portMap.String())
	}

	infoFlags := map[string]string{
		"--proxy-enabled":  proxyEnabled,
		"--proxy-type":     getAppProxyType(appName),
		"--proxy-port-map": strings.Join(proxyPortMap, " "),
	}

	trimPrefix := false
	uppercaseFirstCharacter := true
	return common.ReportSingleApp("proxy", appName, infoFlag, infoFlags, trimPrefix, uppercaseFirstCharacter)
}

func addProxyPorts(appName string, proxyPortMap []PortMap) error {
	allPortMaps := getProxyPortMap(appName)
	allPortMaps = append(allPortMaps, proxyPortMap...)

	return setProxyPorts(appName, allPortMaps)
}

func filterAppProxyPorts(appName string, scheme string, hostPort int) []PortMap {
	var filteredProxyMaps []PortMap
	proxyPortMap := getProxyPortMap(appName)
	for _, portMap := range proxyPortMap {
		if portMap.Scheme == scheme && portMap.HostPort == hostPort {
			filteredProxyMaps = append(filteredProxyMaps, portMap)
		}
	}

	return filteredProxyMaps
}

func getAppName(args []string) (appName string, err error) {
	if len(args) >= 1 {
		appName = args[0]
	} else {
		err = errors.New("Please specify an app to run the command on")
	}

	return
}

func getAppProxyType(appName string) string {
	return config.GetWithDefault(appName, "DOKKU_APP_PROXY_TYPE", "nginx")
}

func getProxyPortMap(appName string) []PortMap {
	value := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "")
	return parseProxyPortMapString(value)
}

func listAppProxyPorts(appName string) error {
	proxyPortMap := getProxyPortMap(appName)

	if len(proxyPortMap) == 0 {
		return errors.New("No port mappings configured for app")
	}

	var lines []string
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		lines = append(lines, "-----> scheme:host port:container port")
	}

	for _, portMap := range proxyPortMap {
		lines = append(lines, portMap.String())
	}

	common.LogInfo1Quiet(fmt.Sprintf("Port mappings for %s", appName))
	config := columnize.DefaultConfig()
	config.Delim = ":"
	config.Prefix = "    "
	config.Empty = ""
	fmt.Println(columnize.Format(lines, config))
	return nil
}

func setProxyPorts(appName string, proxyPortMap []PortMap) error {
	var value []string
	for _, portMap := range uniqueProxyPortMap(proxyPortMap) {
		value = append(value, portMap.String())
	}

	entries := map[string]string{
		"DOKKU_PROXY_PORT_MAP": strings.Join(value, " "),
	}
	return config.SetMany(appName, entries, false)
}

func removeProxyPorts(appName string, proxyPortMap []PortMap) error {
	toRemove := map[string]bool{}

	for _, portMap := range proxyPortMap {
		toRemove[portMap.String()] = true
	}

	var toSet []PortMap
	existingPortMaps := getProxyPortMap(appName)
	for _, portMap := range existingPortMaps {
		if toRemove[portMap.String()] {
			continue
		}

		toSet = append(toSet, portMap)
	}

	if len(toSet) == 0 {
		keys := []string{"DOKKU_PROXY_PORT_MAP"}
		return config.UnsetMany(appName, keys, false)
	}

	return setProxyPorts(appName, toSet)
}

func parseProxyPortMapString(stringPortMap string) []PortMap {
	var proxyPortMap []PortMap

	for _, v := range strings.Split(strings.TrimSpace(stringPortMap), " ") {
		parts := strings.SplitN(v, ":", 3)
		if len(parts) != 3 {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
			continue
		}

		hostPort, err := strconv.Atoi(parts[1])
		if err != nil {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
		}

		containerPort, err := strconv.Atoi(parts[2])
		if err != nil {
			common.LogWarn(fmt.Sprintf("Invalid port map %s", v))
		}

		proxyPortMap = append(proxyPortMap, PortMap{
			ContainerPort: containerPort,
			HostPort:      hostPort,
			Scheme:        parts[0],
		})
	}

	return uniqueProxyPortMap(proxyPortMap)
}

func uniqueProxyPortMap(proxyPortMap []PortMap) []PortMap {
	var unique []PortMap
	existingPortMaps := map[string]bool{}

	for _, portMap := range proxyPortMap {
		if existingPortMaps[portMap.String()] {
			continue
		}

		existingPortMaps[portMap.String()] = true
		unique = append(unique, portMap)
	}

	return unique
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/cswank/gogadgets"
	"github.com/cswank/gogadgets/utils"
)

const (
	defaultDir    = "~/.gadgets"
	defaultConfig = "/Users/Cswank/.gadgets/config.json"
)

var (
	host   = flag.String("h", "localhost", "Name of Host")
	config = flag.String("g", "", "Path to a Gadgets config file")
	cmd    = flag.String("c", "", "a Robot Command Language string")
	status = flag.Bool("s", false, "get the status of a gadgets system")
)

func main() {
	flag.Parse()
	if len(*cmd) > 0 {
		sendCommand()
	} else if *status {
		getStatus()
	} else {
		runGadgets()
	}
}

func runGadgets() {
	cfg := getConfig()
	if cfg == "" {
		listen()
	} else {
		a := gogadgets.NewApp(cfg)
		a.Start()
	}
}

func getConfig() string {
	cfg := *config
	if cfg != "" {
		return cfg
	}
	if utils.FileExists(defaultConfig) {
		return defaultConfig
	}
	return ""
}

func getStatus() {
	s, err := gogadgets.NewClientSockets(*host)
	defer s.Close()
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	status, err := s.SendStatusRequest()
	time.Sleep(100 * time.Millisecond)
	if err == nil {
		fmt.Println("status", status, err)
	} else {
		fmt.Println(err)
	}
	os.Exit(0)
}

func sendCommand() {
	s, err := gogadgets.NewClientSockets(*host)
	defer s.Close()
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	fmt.Println(*cmd, "host", *host)
	s.Send(*cmd)
	time.Sleep(100 * time.Millisecond)
	os.Exit(0)

}

//Waits for a zmq message that contains a gogadgets
//config.  When one is recieved it is written to the
//default config path and a a gogadgts system is started.
func listen() {
	s, err := gogadgets.NewSockets()
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	log.Println("listening for new gadgets")
	msg := s.Recv()
	d, err := json.Marshal(&msg.Config)
	if err != nil {
		panic(err)
	}
	os.Mkdir(defaultDir, 0644)
	err = ioutil.WriteFile(defaultConfig, d, 0644)
	if err != nil {
		panic(err)
	}
	s.Close()
	time.Sleep(100 * time.Millisecond)
	runGadgets()
}
<commit_msg>oops - broke the cli<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/cswank/gogadgets"
	"github.com/cswank/gogadgets/utils"
)

const (
	defaultDir    = "~/.gadgets"
	defaultConfig = "/Users/Cswank/.gadgets/config.json"
)

var (
	host   = flag.String("h", "localhost", "Name of Host")
	config = flag.String("g", "", "Path to a Gadgets config file")
	cmd    = flag.String("c", "", "a Robot Command Language string")
	status = flag.Bool("s", false, "get the status of a gadgets system")
)

func main() {
	flag.Parse()
	if len(*cmd) > 0 {
		sendCommand()
	} else if *status {
		getStatus()
	} else {
		runGadgets()
	}
}

func runGadgets() {
	cfg := getConfig()
	if cfg == "" {
		listen()
	} else {
		a := gogadgets.NewApp(cfg)
		a.Start()
	}
}

func getConfig() string {
	cfg := *config
	if cfg != "" {
		return cfg
	}
	if utils.FileExists(defaultConfig) {
		return defaultConfig
	}
	return ""
}

func getStatus() {
	cfg := gogadgets.SocketsConfig{
		Host:    *host,
		SubPort: 6111,
		PubPort: 6112,
		Master:  false,
	}
	s, err := gogadgets.NewClientSockets(cfg)
	defer s.Close()
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	status, err := s.SendStatusRequest()
	time.Sleep(100 * time.Millisecond)
	if err == nil {
		fmt.Println("status", status, err)
	} else {
		fmt.Println(err)
	}
	os.Exit(0)
}

func sendCommand() {
	cfg := gogadgets.SocketsConfig{
		Host:    *host,
		SubPort: 6111,
		PubPort: 6112,
		Master:  false,
	}
	s, err := gogadgets.NewClientSockets(cfg)
	defer s.Close()
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	fmt.Println(*cmd, "host", *host)
	s.Send(*cmd)
	time.Sleep(100 * time.Millisecond)
	os.Exit(0)

}

//Waits for a zmq message that contains a gogadgets
//config.  When one is recieved it is written to the
//default config path and a a gogadgts system is started.
func listen() {
	cfg := gogadgets.SocketsConfig{
		Host:    *host,
		SubPort: 6111,
		PubPort: 6112,
		Master:  false,
	}
	s, err := gogadgets.NewSockets(cfg)
	if err != nil {
		panic(err)
	}
	time.Sleep(100 * time.Millisecond)
	log.Println("listening for new gadgets")
	msg := s.Recv()
	d, err := json.Marshal(&msg.Config)
	if err != nil {
		panic(err)
	}
	os.Mkdir(defaultDir, 0644)
	err = ioutil.WriteFile(defaultConfig, d, 0644)
	if err != nil {
		panic(err)
	}
	s.Close()
	time.Sleep(100 * time.Millisecond)
	runGadgets()
}
<|endoftext|>


<commit_before>package goketo

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/Sirupsen/logrus"
)

// Client http client tracker
type Client struct {
	client   *http.Client
	endpoint string
	identity string
	version  string
	token    *AuthToken
}

// bearerRoundTripper wrapper for query params
type bearerRoundTripper struct {
	Delegate     http.RoundTripper
	clientID     string
	clientSecret string
}

// AuthToken holds data from Auth request
type AuthToken struct {
	Token   string `json:"access_token"`
	Type    string `json:"token_type"`
	Expires int    `json:"expires_in"` // in seconds
	Scope   string `json:"scope"`
}

func (b *bearerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	if b.Delegate == nil {
		b.Delegate = http.DefaultTransport
	}
	values := req.URL.Query()
	values.Add("client_id", b.clientID)
	values.Add("client_secret", b.clientSecret)
	req.URL.RawQuery = values.Encode()
	return b.Delegate.RoundTrip(req)
}

func errHandler(err error) {
	if err != nil {
		log.Print(err)
	}
}

// NewAuthClient request application/json
func NewAuthClient(clientID string, ClientSecret string, ClientEndpoint string) (*Client, error) {
	// Endpoint: /identity/oauth/token?grant_type=client_credentials
	version := "v1"
	var endpoint string
	var identity string

	// Check if endpoint has proper protocol
	if strings.HasPrefix(ClientEndpoint, "http") {
		endpoint = ClientEndpoint + "/rest/" + version + "/"
		identity = ClientEndpoint + "/identity/"
	} else {
		endpoint = "https://" + ClientEndpoint + "/rest/" + version + "/"
		identity = "https://" + ClientEndpoint + "/identity/"
	}
	// Add credentials to the request
	client := &http.Client{
		Transport: &bearerRoundTripper{
			clientID:     clientID,
			clientSecret: ClientSecret,
		},
	}
	// Make request for token
	resp, err := client.Get(identity + "oauth/token?grant_type=client_credentials")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var auth AuthToken
	if resp.StatusCode == 200 {
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logrus.Errorf("Could not convert response: %v", err)
		}
		err = json.Unmarshal(data, &auth)
		logrus.Infof("Token: %s - Type: %s", auth.Token, auth.Type)
	} else {
		logrus.Errorf("An error occured while fetching data: %v", resp)
	}

	return &Client{
		client:   client,
		endpoint: endpoint,
		identity: identity,
		version:  version,
		token:    &auth,
	}, nil
}

func (c *Client) do(req *http.Request) ([]byte, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data with \"%s\"", resp.StatusCode, string(body))
		return nil, err
	}
	return body, nil
}

// Get resource string
func (c *Client) Get(resource string) ([]byte, error) {
	req, err := http.NewRequest("GET", c.endpoint+resource, nil)
	if err != nil {
		return nil, err
	}
	return c.do(req)
}

// Post to resource string the data provided
func (c *Client) Post(resource string, data url.Values) ([]byte, error) {
	req, err := http.NewRequest("POST", c.endpoint+resource, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	return c.do(req)
}
<commit_msg>Added auth token to requests<commit_after>package goketo

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/Sirupsen/logrus"
)

// Client http client tracker
type Client struct {
	client   *http.Client
	endpoint string
	identity string
	version  string
	auth     *AuthToken
}

// bearerRoundTripper wrapper for query params
type bearerRoundTripper struct {
	Delegate     http.RoundTripper
	clientID     string
	clientSecret string
}

// AuthToken holds data from Auth request
type AuthToken struct {
	Token   string `json:"access_token"`
	Type    string `json:"token_type"`
	Expires int    `json:"expires_in"` // in seconds
	Scope   string `json:"scope"`
}

func (b *bearerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	if b.Delegate == nil {
		b.Delegate = http.DefaultTransport
	}
	values := req.URL.Query()
	values.Add("client_id", b.clientID)
	values.Add("client_secret", b.clientSecret)
	req.URL.RawQuery = values.Encode()
	return b.Delegate.RoundTrip(req)
}

func errHandler(err error) {
	if err != nil {
		log.Print(err)
	}
}

// NewAuthClient request application/json
func NewAuthClient(clientID string, ClientSecret string, ClientEndpoint string) (*Client, error) {
	// Endpoint: /identity/oauth/token?grant_type=client_credentials
	version := "v1"
	var endpoint string
	var identity string

	// Check if endpoint has proper protocol
	if strings.HasPrefix(ClientEndpoint, "http") {
		endpoint = ClientEndpoint + "/rest/" + version + "/"
		identity = ClientEndpoint + "/identity/"
	} else {
		endpoint = "https://" + ClientEndpoint + "/rest/" + version + "/"
		identity = "https://" + ClientEndpoint + "/identity/"
	}
	// Add credentials to the request
	client := &http.Client{
		Transport: &bearerRoundTripper{
			clientID:     clientID,
			clientSecret: ClientSecret,
		},
	}
	// Make request for token
	resp, err := client.Get(identity + "oauth/token?grant_type=client_credentials")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var auth AuthToken
	if resp.StatusCode == 200 {
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logrus.Errorf("Could not convert response: %v", err)
		}
		err = json.Unmarshal(data, &auth)
		logrus.Infof("Token: %s - Type: %s", auth.Token, auth.Type)
	} else {
		logrus.Errorf("An error occured while fetching data: %v", resp)
	}

	return &Client{
		client:   client,
		endpoint: endpoint,
		identity: identity,
		version:  version,
		auth:     &auth,
	}, nil
}

func (c *Client) do(req *http.Request) ([]byte, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data with \"%s\"", resp.StatusCode, string(body))
		return nil, err
	}
	return body, nil
}

// Get resource string
func (c *Client) Get(resource string) ([]byte, error) {
	req, err := http.NewRequest("GET", c.endpoint+resource, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", strings.ToUpper(c.auth.Type[:1])+c.auth.Type[1:]+" "+c.auth.Token)
	return c.do(req)
}

// Post to resource string the data provided
func (c *Client) Post(resource string, data url.Values) ([]byte, error) {
	req, err := http.NewRequest("POST", c.endpoint+resource, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Authorization", strings.ToUpper(c.auth.Type[:1])+c.auth.Type[1:]+" "+c.auth.Token)

	return c.do(req)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 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 or at
// https://developers.google.com/open-source/licenses/bsd.

// golint lints the Go source files named on its command line.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/lint"
)

var minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")

func main() {
	flag.Parse()

	for _, filename := range flag.Args() {
		if isDir(filename) {
			lintDir(filename)
		} else {
			lintFile(filename)
		}
	}
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func lintFile(filename string) {
	src, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Printf("Failed reading %v: %v", filename, err)
		return
	}

	l := new(lint.Linter)
	ps, err := l.Lint(filename, src)
	if err != nil {
		log.Printf("Failed parsing %v: %v", filename, err)
		return
	}
	for _, p := range ps {
		if p.Confidence >= *minConfidence {
			fmt.Printf("%s:%v: %s\n", filename, p.Position, p.Text)
		}
	}
}

func lintDir(dirname string) {
	filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() && strings.HasSuffix(path, ".go") {
			lintFile(path)
		}
		return err
	})
}
<commit_msg>error output now compatible with vim quickfix<commit_after>// Copyright (c) 2013 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 or at
// https://developers.google.com/open-source/licenses/bsd.

// golint lints the Go source files named on its command line.
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/lint"
)

var minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")

func main() {
	flag.Parse()

	for _, filename := range flag.Args() {
		if isDir(filename) {
			lintDir(filename)
		} else {
			lintFile(filename)
		}
	}
}

func isDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func lintFile(filename string) {
	src, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	l := new(lint.Linter)
	ps, err := l.Lint(filename, src)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v:%v\n", filename, err)
		return
	}
	for _, p := range ps {
		if p.Confidence >= *minConfidence {
			fmt.Printf("%s:%v: %s\n", filename, p.Position, p.Text)
		}
	}
}

func lintDir(dirname string) {
	filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() && strings.HasSuffix(path, ".go") {
			lintFile(path)
		}
		return err
	})
}
<|endoftext|>


<commit_before>package nsqlookup

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// A ProxyEngine implements the Engine interface an is intended to be used as a
// frontend to a set of standard nsqlookupd servers to expose them as if
// they were a single entity.
type ProxyEngine struct {
	Transport http.RoundTripper
	Resolver  Resolver
}

func (p *ProxyEngine) Close() error {
	return nil
}

func (p *ProxyEngine) RegisterNode(ctx context.Context, node NodeInfo) (Node, error) {
	return nil, errUnsupported
}

func (p *ProxyEngine) TombstoneTopic(ctx context.Context, node NodeInfo, topic string) (err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	errcount := 0
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			errors <- p.post(ctx, server+"/tombstone_topic_producer?topic="+url.QueryEscape(topic)+"&node="+url.QueryEscape(httpBroadcastAddress(node)), nil, nil)
		}(server)
	}

	for i := 0; i != srvcount; i++ {
		if e := <-errors; e != nil {
			err = appendError(err, e)
			errcount++
		}
	}

	if errcount == srvcount {
		return
	}

	err = nil
	return
}

func (p *ProxyEngine) LookupNodes(ctx context.Context) (nodes []NodeInfo, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []NodeInfo, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Producers []NodeInfo `json:"producers"`
			}
			if err := p.get(ctx, server+"/nodes", &res); err != nil {
				errors <- err
			} else {
				results <- res.Producers
			}
		}(server)
	}

	set := make(map[string]NodeInfo)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, n := range r {
				set[httpBroadcastAddress(n)] = n
			}
		case e := <-errors:
			err = appendError(err, e)
		}
	}

	if len(set) != 0 {
		nodes = make([]NodeInfo, 0, len(set))
		for _, node := range set {
			nodes = append(nodes, node)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupProducers(ctx context.Context, topic string) (nodes []NodeInfo, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []NodeInfo, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Producers []NodeInfo `json:"producers"`
			}
			if err := p.get(ctx, server+"/lookup?topic="+url.QueryEscape(topic), &res); err != nil {
				errors <- err
			} else {
				results <- res.Producers
			}
		}(server)
	}

	set := make(map[string]NodeInfo)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, n := range r {
				set[httpBroadcastAddress(n)] = n
			}
		case e := <-errors:
			err = appendError(err, e)
		}
	}

	if len(set) != 0 {
		nodes = make([]NodeInfo, 0, len(set))
		for _, node := range set {
			nodes = append(nodes, node)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupTopics(ctx context.Context) (topics []string, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []string, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Topics []string `json:"topics"`
			}
			if err := p.get(ctx, server+"/topics", &res); err != nil {
				errors <- err
			} else {
				results <- res.Topics
			}
		}(server)
	}

	set := make(map[string]bool)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, c := range r {
				set[c] = true
			}
		case e := <-errors:
			err = appendError(err, e)
		}
	}

	if len(set) != 0 {
		topics = make([]string, 0, len(set))
		for topic := range set {
			topics = append(topics, topic)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupChannels(ctx context.Context, topic string) (channels []string, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []string, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Channels []string `json:"channels"`
			}
			if err := p.get(ctx, server+"/channels?topic="+url.QueryEscape(topic), &res); err != nil {
				errors <- err
			} else {
				results <- res.Channels
			}
		}(server)
	}

	set := make(map[string]bool)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, c := range r {
				set[c] = true
			}
		case e := <-errors:
			err = appendError(err, e)
		}
	}

	if len(set) != 0 {
		channels = make([]string, 0, len(set))
		for channel := range set {
			channels = append(channels, channel)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupInfo(ctx context.Context) (info EngineInfo, err error) {
	info.Type = "proxy"
	info.Version = "0.3.8"
	return
}

func (p *ProxyEngine) CheckHealth(ctx context.Context) (err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	errcount := 0
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			errors <- p.get(ctx, server+"/ping", nil)
		}(server)
	}

	for i := 0; i != srvcount; i++ {
		if e := <-errors; e != nil {
			err = appendError(err, e)
			errcount++
		}
	}

	if errcount == srvcount {
		return
	}

	err = nil
	return
}

func (p *ProxyEngine) get(ctx context.Context, url string, recv interface{}) error {
	return p.do(ctx, "GET", url, nil, recv)
}

func (p *ProxyEngine) post(ctx context.Context, url string, send interface{}, recv interface{}) error {
	return p.do(ctx, "POST", url, send, recv)
}

func (e *ProxyEngine) do(ctx context.Context, method string, url string, send interface{}, recv interface{}) (err error) {
	var req *http.Request
	var res *http.Response
	var r io.Reader
	var b []byte
	var t http.RoundTripper

	if t = e.Transport; t == nil {
		t = http.DefaultTransport
	}

	if send != nil {
		if b, err = json.Marshal(send); err != nil {
			return
		}
		r = bytes.NewReader(b)
	}

	if strings.Index(url, "://") < 0 {
		url = "http://" + url
	}

	if req, err = http.NewRequest(method, url, r); err != nil {
		return
	}
	req.Header.Set("User-Agent", "nsqlookup proxy engine")
	req.Header.Set("Accept", "application/vnd.nsq; version=1.0")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")

	if ctx != nil {
		req = req.WithContext(ctx)
	}

	if res, err = t.RoundTrip(req); err != nil {
		return
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		b := &bytes.Buffer{}
		io.Copy(b, res.Body)
		err = &proxyError{
			method:  method,
			url:     url,
			status:  res.StatusCode,
			reason:  res.Status,
			message: b.String(),
		}
		return
	}

	if recv != nil {
		if err = json.NewDecoder(res.Body).Decode(recv); err != nil {
			return
		}
	} else {
		io.Copy(ioutil.Discard, res.Body)
	}

	return
}

type ProxyNode struct {
	server string
	info   NodeInfo
}

type proxyError struct {
	method  string
	url     string
	status  int
	reason  string
	message string
}

func (e *proxyError) Error() string {
	return fmt.Sprintf("%s %s: %d %s: %s", e.method, e.url, e.status, e.reason, e.message)
}

var (
	errUnsupported = errors.New("unsupported")
)
<commit_msg>don't report 404 errors on lookup endpoints<commit_after>package nsqlookup

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// A ProxyEngine implements the Engine interface an is intended to be used as a
// frontend to a set of standard nsqlookupd servers to expose them as if
// they were a single entity.
type ProxyEngine struct {
	Transport http.RoundTripper
	Resolver  Resolver
}

func (p *ProxyEngine) Close() error {
	return nil
}

func (p *ProxyEngine) RegisterNode(ctx context.Context, node NodeInfo) (Node, error) {
	return nil, errUnsupported
}

func (p *ProxyEngine) TombstoneTopic(ctx context.Context, node NodeInfo, topic string) (err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	errcount := 0
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			errors <- p.post(ctx, server+"/tombstone_topic_producer?topic="+url.QueryEscape(topic)+"&node="+url.QueryEscape(httpBroadcastAddress(node)), nil, nil)
		}(server)
	}

	for i := 0; i != srvcount; i++ {
		if e := <-errors; e != nil {
			err = appendError(err, e)
			errcount++
		}
	}

	if errcount == srvcount {
		return
	}

	err = nil
	return
}

func (p *ProxyEngine) LookupNodes(ctx context.Context) (nodes []NodeInfo, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []NodeInfo, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Producers []NodeInfo `json:"producers"`
			}
			if err := p.get(ctx, server+"/nodes", &res); err != nil {
				errors <- err
			} else {
				results <- res.Producers
			}
		}(server)
	}

	set := make(map[string]NodeInfo)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, n := range r {
				set[httpBroadcastAddress(n)] = n
			}
		case e := <-errors:
			if e != errNotFound {
				err = appendError(err, e)
			}
		}
	}

	if len(set) != 0 {
		nodes = make([]NodeInfo, 0, len(set))
		for _, node := range set {
			nodes = append(nodes, node)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupProducers(ctx context.Context, topic string) (nodes []NodeInfo, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []NodeInfo, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Producers []NodeInfo `json:"producers"`
			}
			if err := p.get(ctx, server+"/lookup?topic="+url.QueryEscape(topic), &res); err != nil {
				errors <- err
			} else {
				results <- res.Producers
			}
		}(server)
	}

	set := make(map[string]NodeInfo)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, n := range r {
				set[httpBroadcastAddress(n)] = n
			}
		case e := <-errors:
			if e != errNotFound {
				err = appendError(err, e)
			}
		}
	}

	if len(set) != 0 {
		nodes = make([]NodeInfo, 0, len(set))
		for _, node := range set {
			nodes = append(nodes, node)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupTopics(ctx context.Context) (topics []string, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []string, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Topics []string `json:"topics"`
			}
			if err := p.get(ctx, server+"/topics", &res); err != nil {
				errors <- err
			} else {
				results <- res.Topics
			}
		}(server)
	}

	set := make(map[string]bool)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, c := range r {
				set[c] = true
			}
		case e := <-errors:
			if e != errNotFound {
				err = appendError(err, e)
			}
		}
	}

	if len(set) != 0 {
		topics = make([]string, 0, len(set))
		for topic := range set {
			topics = append(topics, topic)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupChannels(ctx context.Context, topic string) (channels []string, err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	results := make(chan []string, srvcount)
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			var res struct {
				Channels []string `json:"channels"`
			}
			if err := p.get(ctx, server+"/channels?topic="+url.QueryEscape(topic), &res); err != nil {
				errors <- err
			} else {
				results <- res.Channels
			}
		}(server)
	}

	set := make(map[string]bool)
	for i := 0; i != srvcount; i++ {
		select {
		case r := <-results:
			for _, c := range r {
				set[c] = true
			}
		case e := <-errors:
			if e != errNotFound {
				err = appendError(err, e)
			}
		}
	}

	if len(set) != 0 {
		channels = make([]string, 0, len(set))
		for channel := range set {
			channels = append(channels, channel)
		}
		err = nil
	}

	return
}

func (p *ProxyEngine) LookupInfo(ctx context.Context) (info EngineInfo, err error) {
	info.Type = "proxy"
	info.Version = "0.3.8"
	return
}

func (p *ProxyEngine) CheckHealth(ctx context.Context) (err error) {
	var servers []string
	if servers, err = p.Resolver.Resolve(ctx); err != nil {
		return
	}

	srvcount := len(servers)
	errcount := 0
	errors := make(chan error, srvcount)

	for _, server := range servers {
		go func(server string) {
			errors <- p.get(ctx, server+"/ping", nil)
		}(server)
	}

	for i := 0; i != srvcount; i++ {
		if e := <-errors; e != nil {
			err = appendError(err, e)
			errcount++
		}
	}

	if errcount == srvcount {
		return
	}

	err = nil
	return
}

func (p *ProxyEngine) get(ctx context.Context, url string, recv interface{}) error {
	return p.do(ctx, "GET", url, nil, recv)
}

func (p *ProxyEngine) post(ctx context.Context, url string, send interface{}, recv interface{}) error {
	return p.do(ctx, "POST", url, send, recv)
}

func (e *ProxyEngine) do(ctx context.Context, method string, url string, send interface{}, recv interface{}) (err error) {
	var req *http.Request
	var res *http.Response
	var r io.Reader
	var b []byte
	var t http.RoundTripper

	if t = e.Transport; t == nil {
		t = http.DefaultTransport
	}

	if send != nil {
		if b, err = json.Marshal(send); err != nil {
			return
		}
		r = bytes.NewReader(b)
	}

	if strings.Index(url, "://") < 0 {
		url = "http://" + url
	}

	if req, err = http.NewRequest(method, url, r); err != nil {
		return
	}
	req.Header.Set("User-Agent", "nsqlookup proxy engine")
	req.Header.Set("Accept", "application/vnd.nsq; version=1.0")
	req.Header.Set("Content-Type", "application/json; charset=utf-8")

	if ctx != nil {
		req = req.WithContext(ctx)
	}

	if res, err = t.RoundTrip(req); err != nil {
		return
	}
	defer res.Body.Close()

	switch res.StatusCode {
	case http.StatusOK:
	case http.StatusNotFound:
		io.Copy(ioutil.Discard, res.Body)
		err = errNotFound
		return
	default:
		b := &bytes.Buffer{}
		io.Copy(b, res.Body)
		err = &proxyError{
			method:  method,
			url:     url,
			status:  res.StatusCode,
			reason:  res.Status,
			message: b.String(),
		}
		return
	}

	if recv == nil {
		io.Copy(ioutil.Discard, res.Body)
		return
	}

	err = json.NewDecoder(res.Body).Decode(recv)
	return
}

type ProxyNode struct {
	server string
	info   NodeInfo
}

type proxyError struct {
	method  string
	url     string
	status  int
	reason  string
	message string
}

func (e *proxyError) Error() string {
	return fmt.Sprintf("%s %s: %d %s: %s", e.method, e.url, e.status, e.reason, e.message)
}

var (
	errNotFound    = errors.New("not found")
	errUnsupported = errors.New("unsupported")
)
<|endoftext|>


<commit_before>//  Copyright (c) 2019 Cisco and/or its affiliates.
//
//  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 client

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/docker/docker/api/types/versions"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/ligato/cn-infra/db/keyval"
	"github.com/ligato/cn-infra/db/keyval/etcd"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/cn-infra/logging/logrus"

	"github.com/ligato/vpp-agent/api"
	"github.com/ligato/vpp-agent/api/types"
	"github.com/ligato/vpp-agent/client"
	"github.com/ligato/vpp-agent/client/remoteclient"
	"github.com/ligato/vpp-agent/pkg/debug"
)

var (
	// DefaultAgentHost defines default host address for agent
	DefaultAgentHost = "127.0.0.1"

	DefaultPortGRPC = 9111
	DefaultPortHTTP = 9191
)

var _ APIClient = (*Client)(nil)

// Client is the API client that performs all operations
// against a Ligato agent.
type Client struct {
	scheme   string
	host     string
	proto    string
	addr     string
	basePath string

	grpcAddr      string
	grpcTLS       *tls.Config
	httpAddr      string
	httpTLS       *tls.Config
	kvdbEndpoints []string
	kvdbTLS       *tls.Config
	serviceLabel  string

	grpcClient *grpc.ClientConn
	httpClient *http.Client

	customHTTPHeaders map[string]string
	version           string
	manualOverride    bool
	negotiateVersion  bool
	negotiated        bool
}

// NewClient returns client with host option.
func NewClient(host string) (*Client, error) {
	return NewClientWithOpts(WithHost(host))
}

// NewClientFromEnv returns client with options from environment.
func NewClientFromEnv() (*Client, error) {
	return NewClientWithOpts(FromEnv)
}

// NewClientWithOpts returns client with ops applied.
func NewClientWithOpts(ops ...Opt) (*Client, error) {
	c := &Client{
		host:    DefaultAgentHost,
		version: api.DefaultVersion,
		proto:   "tcp",
		scheme:  "http",
	}
	for _, op := range ops {
		if err := op(c); err != nil {
			return nil, err
		}
	}
	return c, nil
}

func (c *Client) ConfigClient() (client.ConfigClient, error) {
	conn, err := c.GRPCConn()
	if err != nil {
		return nil, err
	}
	return remoteclient.NewClientGRPC(conn), nil
}

func (c *Client) AgentHost() string {
	return c.host
}

func (c *Client) ClientVersion() string {
	return c.version
}

// Close the transport used by the client
func (c *Client) Close() error {
	if c.httpClient != nil {
		if t, ok := c.httpClient.Transport.(*http.Transport); ok {
			t.CloseIdleConnections()
		}
	}
	if c.grpcClient != nil {
		if err := c.grpcClient.Close(); err != nil {
			return err
		}
	}
	return nil
}

// GRPCConn returns configured gRPC client.
func (c *Client) GRPCConn() (*grpc.ClientConn, error) {
	if c.grpcClient == nil {
		conn, err := connectGrpc(c.grpcAddr, c.grpcTLS)
		if err != nil {
			return nil, err
		}
		c.grpcClient = conn
	}
	return c.grpcClient, nil
}

// HTTPClient returns configured HTTP client.
func (c *Client) HTTPClient() *http.Client {
	if c.httpClient == nil {
		tr := http.DefaultTransport.(*http.Transport).Clone()
		tr.TLSClientConfig = c.httpTLS

		c.httpClient = &http.Client{
			Transport: tr,
		}
	}
	return c.httpClient
}

// KVDBClient returns configured KVDB client.
func (c *Client) KVDBClient() (KVDBAPIClient, error) {
	kvdb, err := connectEtcd(c.kvdbEndpoints, c.kvdbTLS)
	if err != nil {
		return nil, fmt.Errorf("connecting to Etcd failed: %v", err)
	}
	return NewKVDBClient(kvdb, c.serviceLabel), nil
}

// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {
	if !strings.Contains(host, "://") {
		host = "tcp://" + host
	}
	protoAddrParts := strings.SplitN(host, "://", 2)
	if len(protoAddrParts) == 1 {
		return nil, fmt.Errorf("unable to parse agent host `%s`", host)
	}
	var basePath string
	proto, addr := protoAddrParts[0], protoAddrParts[1]
	if proto == "tcp" {
		parsed, err := url.Parse("tcp://" + addr)
		if err != nil {
			return nil, err
		}
		addr = parsed.Host
		basePath = parsed.Path
	}
	return &url.URL{
		Scheme: proto,
		Host:   addr,
		Path:   basePath,
	}, nil
}

// getAPIPath returns the versioned request path to call the api.
// It appends the query parameters to the path if they are not empty.
func (c *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
	var apiPath string
	if c.negotiateVersion && !c.negotiated {
		c.NegotiateAPIVersion(ctx)
	}
	if c.version != "" {
		v := strings.TrimPrefix(c.version, "v")
		apiPath = path.Join(c.basePath, "/v"+v, p)
	} else {
		apiPath = path.Join(c.basePath, p)
	}
	return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
}

func (c *Client) NegotiateAPIVersion(ctx context.Context) {
	if !c.manualOverride {
		ping, _ := c.Ping(ctx)
		c.negotiateAPIVersionPing(ping)
	}
}

func (c *Client) NegotiateAPIVersionPing(p types.Ping) {
	if !c.manualOverride {
		c.negotiateAPIVersionPing(p)
	}
}

// negotiateAPIVersionPing queries the API and updates the version to match the
// API version. Any errors are silently ignored.
func (c *Client) negotiateAPIVersionPing(p types.Ping) {
	// try the latest version before versioning headers existed
	if p.APIVersion == "" {
		p.APIVersion = "0.1"
	}

	// if the client is not initialized with a version, start with the latest supported version
	if c.version == "" {
		c.version = api.DefaultVersion
	}

	// if server version is lower than the client version, downgrade
	if versions.LessThan(p.APIVersion, c.version) {
		c.version = p.APIVersion
	}

	// Store the results, so that automatic API version negotiation (if enabled)
	// won't be performed on the next request.
	if c.negotiateVersion {
		c.negotiated = true
	}
}

func connectGrpc(addr string, tc *tls.Config) (*grpc.ClientConn, error) {
	dialOpt := grpc.WithInsecure()
	if tc != nil {
		dialOpt = grpc.WithTransportCredentials(credentials.NewTLS(tc))
	}

	logging.Debugf("dialing grpc address: %v", addr)

	return grpc.Dial(addr, dialOpt)
}

func connectEtcd(endpoints []string, tc *tls.Config) (keyval.CoreBrokerWatcher, error) {
	log := logrus.NewLogger("etcd-client")
	if debug.IsEnabledFor("kvdb") {
		log.SetLevel(logging.DebugLevel)
	} else {
		log.SetLevel(logging.WarnLevel)
	}

	cfg := etcd.ClientConfig{
		Config: &clientv3.Config{
			Endpoints:   endpoints,
			DialTimeout: time.Second * 3,
			TLS:         tc,
		},
		OpTimeout: time.Second * 10,
	}

	kvdb, err := etcd.NewEtcdConnectionWithBytes(cfg, log)
	if err != nil {
		return nil, err
	}
	return kvdb, nil
}
<commit_msg>Do not use new Clone() method on Transport. Support older versions of Go<commit_after>//  Copyright (c) 2019 Cisco and/or its affiliates.
//
//  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 client

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/docker/docker/api/types/versions"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"github.com/ligato/cn-infra/db/keyval"
	"github.com/ligato/cn-infra/db/keyval/etcd"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/cn-infra/logging/logrus"

	"github.com/ligato/vpp-agent/api"
	"github.com/ligato/vpp-agent/api/types"
	"github.com/ligato/vpp-agent/client"
	"github.com/ligato/vpp-agent/client/remoteclient"
	"github.com/ligato/vpp-agent/pkg/debug"
)

var (
	// DefaultAgentHost defines default host address for agent
	DefaultAgentHost = "127.0.0.1"

	DefaultPortGRPC = 9111
	DefaultPortHTTP = 9191
)

var _ APIClient = (*Client)(nil)

// Client is the API client that performs all operations
// against a Ligato agent.
type Client struct {
	scheme   string
	host     string
	proto    string
	addr     string
	basePath string

	grpcAddr      string
	grpcTLS       *tls.Config
	httpAddr      string
	httpTLS       *tls.Config
	kvdbEndpoints []string
	kvdbTLS       *tls.Config
	serviceLabel  string

	grpcClient *grpc.ClientConn
	httpClient *http.Client

	customHTTPHeaders map[string]string
	version           string
	manualOverride    bool
	negotiateVersion  bool
	negotiated        bool
}

// NewClient returns client with host option.
func NewClient(host string) (*Client, error) {
	return NewClientWithOpts(WithHost(host))
}

// NewClientFromEnv returns client with options from environment.
func NewClientFromEnv() (*Client, error) {
	return NewClientWithOpts(FromEnv)
}

// NewClientWithOpts returns client with ops applied.
func NewClientWithOpts(ops ...Opt) (*Client, error) {
	c := &Client{
		host:    DefaultAgentHost,
		version: api.DefaultVersion,
		proto:   "tcp",
		scheme:  "http",
	}
	for _, op := range ops {
		if err := op(c); err != nil {
			return nil, err
		}
	}
	return c, nil
}

func (c *Client) ConfigClient() (client.ConfigClient, error) {
	conn, err := c.GRPCConn()
	if err != nil {
		return nil, err
	}
	return remoteclient.NewClientGRPC(conn), nil
}

func (c *Client) AgentHost() string {
	return c.host
}

func (c *Client) ClientVersion() string {
	return c.version
}

// Close the transport used by the client
func (c *Client) Close() error {
	if c.httpClient != nil {
		if t, ok := c.httpClient.Transport.(*http.Transport); ok {
			t.CloseIdleConnections()
		}
	}
	if c.grpcClient != nil {
		if err := c.grpcClient.Close(); err != nil {
			return err
		}
	}
	return nil
}

// GRPCConn returns configured gRPC client.
func (c *Client) GRPCConn() (*grpc.ClientConn, error) {
	if c.grpcClient == nil {
		conn, err := connectGrpc(c.grpcAddr, c.grpcTLS)
		if err != nil {
			return nil, err
		}
		c.grpcClient = conn
	}
	return c.grpcClient, nil
}

// HTTPClient returns configured HTTP client.
func (c *Client) HTTPClient() *http.Client {
	if c.httpClient == nil {
		// tr is copy-pasted definition of DefaultTransport from the net/http package
		// In Go 1.13 method `Clone()` for http.Transport was introduced, so replace
		// following definition of tr with
		//		`tr := http.DefaultTransport.(*http.Transport).Clone()`
		// when ready. For now, I think, it's better to support older versions of Go too.
		tr := &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
				DualStack: true,
			}).DialContext,
			ForceAttemptHTTP2:     true,
			MaxIdleConns:          100,
			IdleConnTimeout:       90 * time.Second,
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		}
		tr.TLSClientConfig = c.httpTLS

		c.httpClient = &http.Client{
			Transport: tr,
		}
	}
	return c.httpClient
}

// KVDBClient returns configured KVDB client.
func (c *Client) KVDBClient() (KVDBAPIClient, error) {
	kvdb, err := connectEtcd(c.kvdbEndpoints, c.kvdbTLS)
	if err != nil {
		return nil, fmt.Errorf("connecting to Etcd failed: %v", err)
	}
	return NewKVDBClient(kvdb, c.serviceLabel), nil
}

// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {
	if !strings.Contains(host, "://") {
		host = "tcp://" + host
	}
	protoAddrParts := strings.SplitN(host, "://", 2)
	if len(protoAddrParts) == 1 {
		return nil, fmt.Errorf("unable to parse agent host `%s`", host)
	}
	var basePath string
	proto, addr := protoAddrParts[0], protoAddrParts[1]
	if proto == "tcp" {
		parsed, err := url.Parse("tcp://" + addr)
		if err != nil {
			return nil, err
		}
		addr = parsed.Host
		basePath = parsed.Path
	}
	return &url.URL{
		Scheme: proto,
		Host:   addr,
		Path:   basePath,
	}, nil
}

// getAPIPath returns the versioned request path to call the api.
// It appends the query parameters to the path if they are not empty.
func (c *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
	var apiPath string
	if c.negotiateVersion && !c.negotiated {
		c.NegotiateAPIVersion(ctx)
	}
	if c.version != "" {
		v := strings.TrimPrefix(c.version, "v")
		apiPath = path.Join(c.basePath, "/v"+v, p)
	} else {
		apiPath = path.Join(c.basePath, p)
	}
	return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
}

func (c *Client) NegotiateAPIVersion(ctx context.Context) {
	if !c.manualOverride {
		ping, _ := c.Ping(ctx)
		c.negotiateAPIVersionPing(ping)
	}
}

func (c *Client) NegotiateAPIVersionPing(p types.Ping) {
	if !c.manualOverride {
		c.negotiateAPIVersionPing(p)
	}
}

// negotiateAPIVersionPing queries the API and updates the version to match the
// API version. Any errors are silently ignored.
func (c *Client) negotiateAPIVersionPing(p types.Ping) {
	// try the latest version before versioning headers existed
	if p.APIVersion == "" {
		p.APIVersion = "0.1"
	}

	// if the client is not initialized with a version, start with the latest supported version
	if c.version == "" {
		c.version = api.DefaultVersion
	}

	// if server version is lower than the client version, downgrade
	if versions.LessThan(p.APIVersion, c.version) {
		c.version = p.APIVersion
	}

	// Store the results, so that automatic API version negotiation (if enabled)
	// won't be performed on the next request.
	if c.negotiateVersion {
		c.negotiated = true
	}
}

func connectGrpc(addr string, tc *tls.Config) (*grpc.ClientConn, error) {
	dialOpt := grpc.WithInsecure()
	if tc != nil {
		dialOpt = grpc.WithTransportCredentials(credentials.NewTLS(tc))
	}

	logging.Debugf("dialing grpc address: %v", addr)

	return grpc.Dial(addr, dialOpt)
}

func connectEtcd(endpoints []string, tc *tls.Config) (keyval.CoreBrokerWatcher, error) {
	log := logrus.NewLogger("etcd-client")
	if debug.IsEnabledFor("kvdb") {
		log.SetLevel(logging.DebugLevel)
	} else {
		log.SetLevel(logging.WarnLevel)
	}

	cfg := etcd.ClientConfig{
		Config: &clientv3.Config{
			Endpoints:   endpoints,
			DialTimeout: time.Second * 3,
			TLS:         tc,
		},
		OpTimeout: time.Second * 10,
	}

	kvdb, err := etcd.NewEtcdConnectionWithBytes(cfg, log)
	if err != nil {
		return nil, err
	}
	return kvdb, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/30x/apid"
	"github.com/30x/apid/factory"
	_ "github.com/30x/apidGatewayDeploy"
	"io/ioutil"
	"github.com/30x/apidGatewayDeploy"
	"os"
	"encoding/json"
)

func main() {
	deploymentsFlag := flag.String("deployments", "", "file path to a deployments file (for testing)")
	flag.Parse()
	deploymentsFile := *deploymentsFlag

	apid.Initialize(factory.DefaultServicesFactory())

	log := apid.Log()
	log.Debug("initializing...")

	configService := apid.Config()

	var deployments apiGatewayDeploy.ApiDeploymentResponse
	if deploymentsFile != "" {
		log.Printf("Running in temp dir using deployments file: %s", deploymentsFile)
		tmpDir, err := ioutil.TempDir("", "apidGatewayDeploy")
		if err != nil {
			log.Panicf("ERROR: Unable to create temp dir", err)
		}
		defer os.RemoveAll(tmpDir)

		configService.Set("data_path", tmpDir)
		configService.Set("gatewaydeploy_bundle_dir", tmpDir) // todo: legacy?

		if deploymentsFile != "" {
			bytes, err := ioutil.ReadFile(deploymentsFile)
			if err != nil {
				log.Errorf("ERROR: Unable to read bundle config file at %s", deploymentsFile)
				return

			}

			err = json.Unmarshal(bytes, &deployments)
			if err != nil {
				log.Errorf("ERROR: Unable to parse deployments %v", err)
				return
			}
		}
	}

	apid.InitializePlugins()

	insertTestDeployments(deployments)

	// print the base url to the console
	basePath := "/deployments"
	port := configService.GetString("api_port")
	log.Print()
	log.Printf("API is at: http://localhost:%s%s", port, basePath)
	log.Print()

	// start client API listener
	api := apid.API()
	err := api.Listen() // doesn't return if no error
	log.Fatalf("Error. Is something already running on port %d? %s", port, err)
}

func insertTestDeployments(deployments apiGatewayDeploy.ApiDeploymentResponse) error {

	if len(deployments) == 0 {
		return nil
	}

	log := apid.Log()

	db, err := apid.Data().DB()
	if err != nil {
		return err
	}
	apiGatewayDeploy.SetDB(db)

	err = apiGatewayDeploy.InitDB(db)
	if err != nil {
		return err
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}

	for _, ad := range deployments {

		dep := apiGatewayDeploy.DataDeployment{
			ID:                 ad.ID,
			BundleConfigID:     ad.ID,
			ApidClusterID:      ad.ID,
			DataScopeID:        ad.ScopeId,
			BundleConfigJSON:   string(ad.BundleConfigJson),
			ConfigJSON:         string(ad.ConfigJson),
			Status:             "",
			Created:            "",
			CreatedBy:          "",
			Updated:            "",
			UpdatedBy:          "",
			BundleName:         deploymentID,
			BundleURI:          bundleFile,
			BundleChecksum:     "",
			BundleChecksumType: "",
			LocalBundleURI:     bundleFile,
		}

		err = apiGatewayDeploy.InsertDeployment(tx, dep)
		if err != nil {
			log.Error("Unable to insert deployment")
			return err
		}

	}

	err = tx.Commit()
	if err != nil {
		return err
	}

	apiGatewayDeploy.InitAPI()

	return nil
}<commit_msg>Repair main.go<commit_after>package main

import (
	"flag"
	"github.com/30x/apid"
	"github.com/30x/apid/factory"
	_ "github.com/30x/apidGatewayDeploy"
	"io/ioutil"
	"github.com/30x/apidGatewayDeploy"
	"os"
	"encoding/json"
)

func main() {
	deploymentsFlag := flag.String("deployments", "", "file path to a deployments file (for testing)")
	flag.Parse()
	deploymentsFile := *deploymentsFlag

	apid.Initialize(factory.DefaultServicesFactory())

	log := apid.Log()
	log.Debug("initializing...")

	configService := apid.Config()

	var deployments apiGatewayDeploy.ApiDeploymentResponse
	if deploymentsFile != "" {
		log.Printf("Running in temp dir using deployments file: %s", deploymentsFile)
		tmpDir, err := ioutil.TempDir("", "apidGatewayDeploy")
		if err != nil {
			log.Panicf("ERROR: Unable to create temp dir", err)
		}
		defer os.RemoveAll(tmpDir)

		configService.Set("data_path", tmpDir)
		configService.Set("gatewaydeploy_bundle_dir", tmpDir) // todo: legacy?

		if deploymentsFile != "" {
			bytes, err := ioutil.ReadFile(deploymentsFile)
			if err != nil {
				log.Errorf("ERROR: Unable to read bundle config file at %s", deploymentsFile)
				return

			}

			err = json.Unmarshal(bytes, &deployments)
			if err != nil {
				log.Errorf("ERROR: Unable to parse deployments %v", err)
				return
			}
		}
	}

	apid.InitializePlugins()

	insertTestDeployments(deployments)

	// print the base url to the console
	basePath := "/deployments"
	port := configService.GetString("api_port")
	log.Print()
	log.Printf("API is at: http://localhost:%s%s", port, basePath)
	log.Print()

	// start client API listener
	api := apid.API()
	err := api.Listen() // doesn't return if no error
	log.Fatalf("Error. Is something already running on port %d? %s", port, err)
}

func insertTestDeployments(deployments apiGatewayDeploy.ApiDeploymentResponse) error {

	if len(deployments) == 0 {
		return nil
	}

	log := apid.Log()

	db, err := apid.Data().DB()
	if err != nil {
		return err
	}
	apiGatewayDeploy.SetDB(db)

	err = apiGatewayDeploy.InitDB(db)
	if err != nil {
		return err
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}

	for _, ad := range deployments {

		dep := apiGatewayDeploy.DataDeployment{
			ID:                 ad.ID,
			BundleConfigID:     ad.ID,
			ApidClusterID:      ad.ID,
			DataScopeID:        ad.ScopeId,
			BundleConfigJSON:   string(ad.BundleConfigJson),
			ConfigJSON:         string(ad.ConfigJson),
			Status:             "",
			Created:            "",
			CreatedBy:          "",
			Updated:            "",
			UpdatedBy:          "",
			BundleName:         ad.DisplayName,
			BundleURI:          ad.URI,
			BundleChecksum:     "",
			BundleChecksumType: "",
			LocalBundleURI:     ad.URI,
		}

		err = apiGatewayDeploy.InsertDeployment(tx, dep)
		if err != nil {
			log.Error("Unable to insert deployment")
			return err
		}

	}

	err = tx.Commit()
	if err != nil {
		return err
	}

	apiGatewayDeploy.InitAPI()

	return nil
}<|endoftext|>


<commit_before>package gosnitch

import "testing"

func TestPidof(t *testing.T) {
	_, err := Pidof("go")
	if err != nil {
		t.Error("Did not find pid of 'go'")
	}
}

func TestPidofNotExisting(t *testing.T) {
	pid, err := Pidof("fake-process")
	if err == nil {
		t.Errorf("Found pid %s when expected to find nothing", pid)
	}
}

func TestProbe(t *testing.T) {
	pid, err := Pidof("go")
	if err != nil {
		t.Error("Expected to find 'go' pid but found nothing")
	}

	s := NewTopSampler(pid)
	s.Probe(pid)
}<commit_msg>Make sure that Probe called on unexisting pid does not crash<commit_after>package gosnitch

import "testing"

func TestPidof(t *testing.T) {
	_, err := Pidof("go")
	if err != nil {
		t.Error("Did not find pid of 'go'")
	}
}

func TestPidofNotExisting(t *testing.T) {
	pid, err := Pidof("fake-process")
	if err == nil {
		t.Errorf("Found pid %s when expected to find nothing", pid)
	}
}

func TestProbe(t *testing.T) {
	pid, err := Pidof("go")
	if err != nil {
		t.Error("Expected to find 'go' pid but found nothing")
	}

	s := NewTopSampler(pid)
	s.Probe(pid)
}

func TestProbeNotExistingDoesNotPanic(t *testing.T) {
	s := NewTopSampler(99999999999999999)
	s.Probe(99999999999999999)
}<|endoftext|>


<commit_before>package gosxnotifier

import (
	"errors"
	"net/url"
	"os/exec"
	"strings"
)

func init() {

}

type Sound string

const (
	Default Sound = "'default'"
	Basso   Sound = "Basso"
	Blow    Sound = "Blow"
	Bottle  Sound = "Bottle"
	Frog    Sound = "Frog"
	Funk    Sound = "Funk"
	Glass   Sound = "Glass"
	Hero    Sound = "Hero"
	Morse   Sound = "Morse"
	Ping    Sound = "Ping"
	Pop     Sound = "Pop"
	Purr    Sound = "Purr"
	Sosumi  Sound = "Sosumi"
	Tink    Sound = "Tink"
)

type Notification struct {
	Message  string //required
	Title    string //optional
	Subtitle string //optional
	Sound    Sound  //optional
	Link     string //optional
	Sender   string //optional
}

func NewNotification(message string) *Notification {
	n := &Notification{Message: message}
	return n
}

func (n *Notification) SendNotification() error {

	commandTuples := make([]string, 0)

	//check required commands
	if n.Message == "" {
		return errors.New("Please specifiy a proper message argument.")
	} else {
		commandTuples = append(commandTuples, []string{"-message", n.Message}...)
	}

	//add title if found
	if n.Title != "" {
		commandTuples = append(commandTuples, []string{"-title", n.Title}...)
	}

	//add subtitle if found
	if n.Subtitle != "" {
		commandTuples = append(commandTuples, []string{"-subtitle", n.Subtitle}...)
	}

	//add sound if specified
	if n.Sound != "" {
		commandTuples = append(commandTuples, []string{"-sound", string(n.Sound)}...)
	}

	//add url if specified
	url, err := url.Parse(n.Link)
	if err != nil {
		n.Link = ""
	}
	if url != nil {
		commandTuples = append(commandTuples, []string{"-open", n.Link}...)
	}

	//add bundle id if specified
	if strings.HasPrefix(strings.ToLower(n.Link), "com.") {
		commandTuples = append(commandTuples, []string{"-activate", n.Link}...)
	}

	//add sender if specified
	if strings.HasPrefix(strings.ToLower(n.Sender), "com.") {
		commandTuples = append(commandTuples, []string{"-sender", n.Sender}...)
	}

	if len(commandTuples) == 0 {
		return errors.New("Please provide a Message and Type at a minimum.")
	}

	_, err = exec.Command(FinalPath, commandTuples...).Output()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Oops, removing empty init() function. Doh, how'd you get in there.<commit_after>package gosxnotifier

import (
	"errors"
	"net/url"
	"os/exec"
	"strings"
)

type Sound string

const (
	Default Sound = "'default'"
	Basso   Sound = "Basso"
	Blow    Sound = "Blow"
	Bottle  Sound = "Bottle"
	Frog    Sound = "Frog"
	Funk    Sound = "Funk"
	Glass   Sound = "Glass"
	Hero    Sound = "Hero"
	Morse   Sound = "Morse"
	Ping    Sound = "Ping"
	Pop     Sound = "Pop"
	Purr    Sound = "Purr"
	Sosumi  Sound = "Sosumi"
	Tink    Sound = "Tink"
)

type Notification struct {
	Message  string //required
	Title    string //optional
	Subtitle string //optional
	Sound    Sound  //optional
	Link     string //optional
	Sender   string //optional
}

func NewNotification(message string) *Notification {
	n := &Notification{Message: message}
	return n
}

func (n *Notification) SendNotification() error {

	commandTuples := make([]string, 0)

	//check required commands
	if n.Message == "" {
		return errors.New("Please specifiy a proper message argument.")
	} else {
		commandTuples = append(commandTuples, []string{"-message", n.Message}...)
	}

	//add title if found
	if n.Title != "" {
		commandTuples = append(commandTuples, []string{"-title", n.Title}...)
	}

	//add subtitle if found
	if n.Subtitle != "" {
		commandTuples = append(commandTuples, []string{"-subtitle", n.Subtitle}...)
	}

	//add sound if specified
	if n.Sound != "" {
		commandTuples = append(commandTuples, []string{"-sound", string(n.Sound)}...)
	}

	//add url if specified
	url, err := url.Parse(n.Link)
	if err != nil {
		n.Link = ""
	}
	if url != nil {
		commandTuples = append(commandTuples, []string{"-open", n.Link}...)
	}

	//add bundle id if specified
	if strings.HasPrefix(strings.ToLower(n.Link), "com.") {
		commandTuples = append(commandTuples, []string{"-activate", n.Link}...)
	}

	//add sender if specified
	if strings.HasPrefix(strings.ToLower(n.Sender), "com.") {
		commandTuples = append(commandTuples, []string{"-sender", n.Sender}...)
	}

	if len(commandTuples) == 0 {
		return errors.New("Please provide a Message and Type at a minimum.")
	}

	_, err = exec.Command(FinalPath, commandTuples...).Output()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/uoregon-libraries/rais-image-server/iiif"
	"github.com/uoregon-libraries/rais-image-server/openjpeg"
	"github.com/uoregon-libraries/rais-image-server/transform"
	"image"
	"log"
	"os"
	"path"
	"strings"
)

var (
	ErrImageDoesNotExist = errors.New("Image file does not exist")
	ErrInvalidFiletype   = errors.New("Invalid or unknown file type")
	ErrDecodeImage       = errors.New("Unable to decode image")
)

// IIIFImage defines an interface for reading images in a generic way.  It's
// heavily biased toward the way we've had to do our JP2 images since they're
// the more unusual use-case.
type IIIFImage interface {
	CleanupResources()
	DecodeImage() (image.Image, error)
	GetDimensions() (image.Rectangle, error)
	SetCrop(image.Rectangle)
	SetResizeWH(int, int)
	SetScale(float64)
}

type ImageResource struct {
	Image    IIIFImage
	ID       iiif.ID
	FilePath string
}

// Initializes and returns an IIIFImage for the given id and path.  If the path
// doesn't resolve to a valid file, or resolves to a file type that isn't
// supported, an error is returned.  File type is determined by extension, so
// images will need standard extensions in order to work.
func NewImageResource(id iiif.ID, filepath string) (*ImageResource, error) {
	var err error

	// First, does the file exist?
	if _, err = os.Stat(filepath); err != nil {
		log.Printf("Image does not exist: %#v", filepath)
		return nil, ErrImageDoesNotExist
	}

	// File exists - is it a valid filetype?
	var i IIIFImage
	fileExt := strings.ToLower(path.Ext(filepath))
	switch fileExt {
	case ".jp2":
		i, err = openjpeg.NewJP2Image(filepath)
	case ".tif", ".tiff", ".png", ".jpg", "jpeg", ".gif":
		i, err = NewSimpleImage(filepath)
	default:
		log.Printf("Image type unknown / invalid: %#v", filepath)
		return nil, ErrInvalidFiletype
	}

	if err != nil {
		log.Printf("Unable to read image %#v: %s", filepath)
		return nil, errors.New(fmt.Sprintf("Unable to read image %#v: %s", id, err))
	}

	img := &ImageResource{ID: id, Image: i, FilePath: filepath}
	return img, nil
}

// Apply runs all image manipulation operations described by the IIIF URL, and
// returns an image.Image ready for encoding to the client
func (res *ImageResource) Apply(u *iiif.URL) (image.Image, error) {
	// Crop and resize have to be prepared before we can decode
	res.prepCrop(u.Region)
	res.prepResize(u.Size)

	img, err := res.Image.DecodeImage()
	if err != nil {
		log.Println("Unable to decode image: ", err)
		return nil, ErrDecodeImage
	}

	if u.Rotation.Degrees != 0 {
		img = rotate(img, u.Rotation)
	}

	return img, nil
}

func (res *ImageResource) prepCrop(r iiif.Region) {
	if r.Type == iiif.RTPixel {
		rect := image.Rect(int(r.X), int(r.Y), int(r.X+r.W), int(r.Y+r.H))
		res.Image.SetCrop(rect)
	}
}

func (res *ImageResource) prepResize(s iiif.Size) {
	switch s.Type {
	case iiif.STScaleToWidth:
		res.Image.SetResizeWH(s.W, 0)
	case iiif.STScaleToHeight:
		res.Image.SetResizeWH(0, s.H)
	case iiif.STExact:
		res.Image.SetResizeWH(s.W, s.H)
	case iiif.STScalePercent:
		res.Image.SetScale(s.Percent / 100.0)
	}
}

func rotate(img image.Image, rot iiif.Rotation) image.Image {
	var r transform.Rotator
	switch img0 := img.(type) {
	case *image.Gray:
		r = transform.GrayRotator{img0}
	case *image.RGBA:
		r = transform.RGBARotator{img0}
	}

	switch rot.Degrees {
	case 90:
		img = r.Rotate90()
	case 180:
		img = r.Rotate180()
	case 270:
		img = r.Rotate270()
	}

	return img
}
<commit_msg>Fix NewImageResource comment<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/uoregon-libraries/rais-image-server/iiif"
	"github.com/uoregon-libraries/rais-image-server/openjpeg"
	"github.com/uoregon-libraries/rais-image-server/transform"
	"image"
	"log"
	"os"
	"path"
	"strings"
)

var (
	ErrImageDoesNotExist = errors.New("Image file does not exist")
	ErrInvalidFiletype   = errors.New("Invalid or unknown file type")
	ErrDecodeImage       = errors.New("Unable to decode image")
)

// IIIFImage defines an interface for reading images in a generic way.  It's
// heavily biased toward the way we've had to do our JP2 images since they're
// the more unusual use-case.
type IIIFImage interface {
	CleanupResources()
	DecodeImage() (image.Image, error)
	GetDimensions() (image.Rectangle, error)
	SetCrop(image.Rectangle)
	SetResizeWH(int, int)
	SetScale(float64)
}

type ImageResource struct {
	Image    IIIFImage
	ID       iiif.ID
	FilePath string
}

// Initializes and returns an ImageResource for the given id and path.  If the path
// doesn't resolve to a valid file, or resolves to a file type that isn't
// supported, an error is returned.  File type is determined by extension, so
// images will need standard extensions in order to work.
func NewImageResource(id iiif.ID, filepath string) (*ImageResource, error) {
	var err error

	// First, does the file exist?
	if _, err = os.Stat(filepath); err != nil {
		log.Printf("Image does not exist: %#v", filepath)
		return nil, ErrImageDoesNotExist
	}

	// File exists - is it a valid filetype?
	var i IIIFImage
	fileExt := strings.ToLower(path.Ext(filepath))
	switch fileExt {
	case ".jp2":
		i, err = openjpeg.NewJP2Image(filepath)
	case ".tif", ".tiff", ".png", ".jpg", "jpeg", ".gif":
		i, err = NewSimpleImage(filepath)
	default:
		log.Printf("Image type unknown / invalid: %#v", filepath)
		return nil, ErrInvalidFiletype
	}

	if err != nil {
		log.Printf("Unable to read image %#v: %s", filepath)
		return nil, errors.New(fmt.Sprintf("Unable to read image %#v: %s", id, err))
	}

	img := &ImageResource{ID: id, Image: i, FilePath: filepath}
	return img, nil
}

// Apply runs all image manipulation operations described by the IIIF URL, and
// returns an image.Image ready for encoding to the client
func (res *ImageResource) Apply(u *iiif.URL) (image.Image, error) {
	// Crop and resize have to be prepared before we can decode
	res.prepCrop(u.Region)
	res.prepResize(u.Size)

	img, err := res.Image.DecodeImage()
	if err != nil {
		log.Println("Unable to decode image: ", err)
		return nil, ErrDecodeImage
	}

	if u.Rotation.Degrees != 0 {
		img = rotate(img, u.Rotation)
	}

	return img, nil
}

func (res *ImageResource) prepCrop(r iiif.Region) {
	if r.Type == iiif.RTPixel {
		rect := image.Rect(int(r.X), int(r.Y), int(r.X+r.W), int(r.Y+r.H))
		res.Image.SetCrop(rect)
	}
}

func (res *ImageResource) prepResize(s iiif.Size) {
	switch s.Type {
	case iiif.STScaleToWidth:
		res.Image.SetResizeWH(s.W, 0)
	case iiif.STScaleToHeight:
		res.Image.SetResizeWH(0, s.H)
	case iiif.STExact:
		res.Image.SetResizeWH(s.W, s.H)
	case iiif.STScalePercent:
		res.Image.SetScale(s.Percent / 100.0)
	}
}

func rotate(img image.Image, rot iiif.Rotation) image.Image {
	var r transform.Rotator
	switch img0 := img.(type) {
	case *image.Gray:
		r = transform.GrayRotator{img0}
	case *image.RGBA:
		r = transform.RGBARotator{img0}
	}

	switch rot.Degrees {
	case 90:
		img = r.Rotate90()
	case 180:
		img = r.Rotate180()
	case 270:
		img = r.Rotate270()
	}

	return img
}
<|endoftext|>


<commit_before>package gosxnotifier

import (
	"errors"
	"net/url"
	"os/exec"
	"path/filepath"
	"strings"
)

type Sound string

const (
	Default Sound = "'default'"
	Basso   Sound = "Basso"
	Blow    Sound = "Blow"
	Bottle  Sound = "Bottle"
	Frog    Sound = "Frog"
	Funk    Sound = "Funk"
	Glass   Sound = "Glass"
	Hero    Sound = "Hero"
	Morse   Sound = "Morse"
	Ping    Sound = "Ping"
	Pop     Sound = "Pop"
	Purr    Sound = "Purr"
	Sosumi  Sound = "Sosumi"
	Tink    Sound = "Tink"
)

type Notification struct {
	Message      string //required
	Title        string //optional
	Subtitle     string //optional
	Sound        Sound  //optional
	Link         string //optional
	Sender       string //optional
	Group        string //optional
	AppIcon      string //optional
	ContentImage string //optional
}

func NewNotification(message string) *Notification {
	n := &Notification{Message: message}
	return n
}

func (n *Notification) Push() error {
	if supportedOS() {
		commandTuples := make([]string, 0)

		//check required commands
		if n.Message == "" {
			return errors.New("Please specifiy a proper message argument.")
		} else {
			commandTuples = append(commandTuples, []string{"-message", n.Message}...)
		}

		//add title if found
		if n.Title != "" {
			commandTuples = append(commandTuples, []string{"-title", n.Title}...)
		}

		//add subtitle if found
		if n.Subtitle != "" {
			commandTuples = append(commandTuples, []string{"-subtitle", n.Subtitle}...)
		}

		//add sound if specified
		if n.Sound != "" {
			commandTuples = append(commandTuples, []string{"-sound", string(n.Sound)}...)
		}

		//add group if specified
		if n.Group != "" {
			commandTuples = append(commandTuples, []string{"-group", n.Group}...)
		}

		//add appIcon if specified
		if n.AppIcon != "" {
			img, err := normalizeImagePath(n.AppIcon)

			if err != nil {
				return err
			}

			commandTuples = append(commandTuples, []string{"-appIcon", img}...)
		}

		//add contentImage if specified
		if n.ContentImage != "" {
			img, err := normalizeImagePath(n.ContentImage)

			if err != nil {
				return err
			}
			commandTuples = append(commandTuples, []string{"-contentImage", img}...)
		}

		//add url if specified
		url, err := url.Parse(n.Link)
		if err != nil {
			n.Link = ""
		}
		if url != nil && n.Link != "" {
			commandTuples = append(commandTuples, []string{"-open", n.Link}...)
		}

		//add bundle id if specified
		if strings.HasPrefix(strings.ToLower(n.Link), "com.") {
			commandTuples = append(commandTuples, []string{"-activate", n.Link}...)
		}

		//add sender if specified
		if strings.HasPrefix(strings.ToLower(n.Sender), "com.") {
			commandTuples = append(commandTuples, []string{"-sender", n.Sender}...)
		}

		if len(commandTuples) == 0 {
			return errors.New("Please provide a Message and Type at a minimum.")
		}

		_, err = exec.Command(FinalPath, commandTuples...).Output()
		if err != nil {
			return err
		}
	}
	return nil
}

func normalizeImagePath(image string) (string, error) {
	if imagePath, err := filepath.Abs(image); err != nil {
		return "", errors.New("Could not resolve image path of image: " + image)
	} else {
		return imagePath, nil
	}
}
<commit_msg>Submarine is missing in the definition<commit_after>package gosxnotifier

import (
	"errors"
	"net/url"
	"os/exec"
	"path/filepath"
	"strings"
)

type Sound string

const (
	Default Sound = "'default'"
	Basso   Sound = "Basso"
	Blow    Sound = "Blow"
	Bottle  Sound = "Bottle"
	Frog    Sound = "Frog"
	Funk    Sound = "Funk"
	Glass   Sound = "Glass"
	Hero    Sound = "Hero"
	Morse   Sound = "Morse"
	Ping    Sound = "Ping"
	Pop     Sound = "Pop"
	Purr    Sound = "Purr"
	Sosumi  Sound = "Sosumi"
	Submarine  Sound = "Submarine"
	Tink       Sound = "Tink"
)

type Notification struct {
	Message      string //required
	Title        string //optional
	Subtitle     string //optional
	Sound        Sound  //optional
	Link         string //optional
	Sender       string //optional
	Group        string //optional
	AppIcon      string //optional
	ContentImage string //optional
}

func NewNotification(message string) *Notification {
	n := &Notification{Message: message}
	return n
}

func (n *Notification) Push() error {
	if supportedOS() {
		commandTuples := make([]string, 0)

		//check required commands
		if n.Message == "" {
			return errors.New("Please specifiy a proper message argument.")
		} else {
			commandTuples = append(commandTuples, []string{"-message", n.Message}...)
		}

		//add title if found
		if n.Title != "" {
			commandTuples = append(commandTuples, []string{"-title", n.Title}...)
		}

		//add subtitle if found
		if n.Subtitle != "" {
			commandTuples = append(commandTuples, []string{"-subtitle", n.Subtitle}...)
		}

		//add sound if specified
		if n.Sound != "" {
			commandTuples = append(commandTuples, []string{"-sound", string(n.Sound)}...)
		}

		//add group if specified
		if n.Group != "" {
			commandTuples = append(commandTuples, []string{"-group", n.Group}...)
		}

		//add appIcon if specified
		if n.AppIcon != "" {
			img, err := normalizeImagePath(n.AppIcon)

			if err != nil {
				return err
			}

			commandTuples = append(commandTuples, []string{"-appIcon", img}...)
		}

		//add contentImage if specified
		if n.ContentImage != "" {
			img, err := normalizeImagePath(n.ContentImage)

			if err != nil {
				return err
			}
			commandTuples = append(commandTuples, []string{"-contentImage", img}...)
		}

		//add url if specified
		url, err := url.Parse(n.Link)
		if err != nil {
			n.Link = ""
		}
		if url != nil && n.Link != "" {
			commandTuples = append(commandTuples, []string{"-open", n.Link}...)
		}

		//add bundle id if specified
		if strings.HasPrefix(strings.ToLower(n.Link), "com.") {
			commandTuples = append(commandTuples, []string{"-activate", n.Link}...)
		}

		//add sender if specified
		if strings.HasPrefix(strings.ToLower(n.Sender), "com.") {
			commandTuples = append(commandTuples, []string{"-sender", n.Sender}...)
		}

		if len(commandTuples) == 0 {
			return errors.New("Please provide a Message and Type at a minimum.")
		}

		_, err = exec.Command(FinalPath, commandTuples...).Output()
		if err != nil {
			return err
		}
	}
	return nil
}

func normalizeImagePath(image string) (string, error) {
	if imagePath, err := filepath.Abs(image); err != nil {
		return "", errors.New("Could not resolve image path of image: " + image)
	} else {
		return imagePath, nil
	}
}
<|endoftext|>