<commit_before>// The gosym command prints symbols in Go source code.
package main

import (
	"bufio"
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/sym"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// TODO allow changing of package identifiers too.

// caveats:
// - map keys
// - no declaration for init
// - type switches?
// - embedded types
// - import to .
// - test files are ignored.
// - can't change package identifiers
// - there's no way to give an error if renaming creates a
//	clash of symbols.

//gosym list [-t] [pkg...]
//
//list all symbols in all named packages.
//	foo/filename.go:23:3: package referenced-package name type-kind
//
//gosym used pkg...
//
//	reads lines in long format; prints any definitions (in long format)
//	found in pkgs that are used by any other packages.
//
//gosym unused pkg
//	reads lines in long format; prints any definitions (in long format)
//	found in pkgs that are not used by any other packages.
//
//gosym unexport
//	reads lines in long or short format; changes any
//	identifier names to be uncapitalised.
//
//gosym short
//	reads lines in long or short format; prints them in short format.
//
//gosym rename from1 to1 from2 to2 ...
//	reads lines in long or short format; renames symbols according
//	to the given rules.
//
//gosym write [pkg...]
//	reads lines in short format; makes any requested changes,
//	restricting changes to the listed packages.
var verbose = flag.Bool("v", true, "print warning messages")

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [-v] command [flags] [args...]\n")
		printf("%s", `
Gosym manipulates symbols in Go source code.
Various sub-commands print, process or write symbols.
`)
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() == 0 {
		flag.Usage()
	}
	name := flag.Arg(0)
	if name == "help" {
		help()
		return
	}
	var c cmd
	var args []string
	for _, e := range cmds {
		if e.name == name {
			e.fset.Parse(flag.Args()[1:])
			c = e.c
			args = e.fset.Args()
			break
		}
	}
	if c == nil {
		flag.Usage()
	}
	if err := runCmd(c, args); err != nil {
		log.Printf("gosym %s: %v", name, err)
		os.Exit(1)
	}
}

func runCmd(c cmd, args []string) error {
	types.Panic = false
	initGoPath()
	ctxt := newContext()
	defer ctxt.stdout.Flush()
	return c.run(ctxt, args)
}

type cmd interface {
	run(*context, []string) error
}

type cmdEntry struct {
	name  string
	about string
	c     cmd
	fset  *flag.FlagSet
}

var cmds []cmdEntry

func register(name string, c cmd, fset *flag.FlagSet, about string) {
	if fset == nil {
		fset = flag.NewFlagSet("gosym "+name, flag.ExitOnError)
	}
	fset.Usage = func() {
		fmt.Fprint(os.Stderr, about)
		fset.PrintDefaults()
	}
	cmds = append(cmds, cmdEntry{
		name:  name,
		about: about,
		c:     c,
		fset:  fset,
	})
}

func help() {
	for i, e := range cmds {
		if i > 0 {
			fmt.Printf("\n")
		}
		e.fset.SetOutput(os.Stdout)
		fmt.Print(e.about)
		e.fset.PrintDefaults()
	}
}

type context struct {
	mu sync.Mutex
	*sym.Context
	pkgCache map[string]*ast.Package
	pkgDirs  map[string]string // map from directory to package name.
	stdout   *bufio.Writer
}

func newContext() *context {
	ctxt := &context{
		pkgDirs: make(map[string]string),
		stdout:  bufio.NewWriter(os.Stdout),
		Context: sym.NewContext(),
	}
	ctxt.Logf = func(pos token.Pos, f string, a ...interface{}) {
		if !*verbose {
			return
		}
		log.Printf("%v: %s", ctxt.position(pos), fmt.Sprintf(f, a...))
	}
	return ctxt
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

func (ctxt *context) positionToImportPath(p token.Position) string {
	if p.Filename == "" {
		panic("empty file name")
	}
	dir := filepath.Dir(p.Filename)
	if pkg, ok := ctxt.pkgDirs[dir]; ok {
		return pkg
	}
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	ctxt.pkgDirs[dir] = bpkg.ImportPath
	return bpkg.ImportPath
}

func (ctxt *context) printf(f string, a ...interface{}) {
	fmt.Fprintf(ctxt.stdout, f, a...)
}

func (ctxt *context) position(pos token.Pos) token.Position {
	return ctxt.FileSet.Position(pos)
}

var emptyFileSet = token.NewFileSet()

func pretty(n ast.Node) string {
	var b bytes.Buffer
	printer.Fprint(&b, emptyFileSet, n)
	return b.String()
}
<commit_msg>exp/cmd/gosym: add docs<commit_after>// The gosym command prints symbols in Go source code.
// It supports the following commands:
//
// gosym short
//
// The short command reads lines from standard input
// in short or long format (see the list command) and
// prints them in short format:
// 	file-position name new-name
// The file-position field holds the location of the identifier.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The new-name field holds the desired new name for the identifier.
//
// gosym export
//
// The export command reads lines in short or long
// format from its standard input and capitalises the first letter
// of all symbols (thus making them available to external
// packages)
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym unexport
//
// The unexport command reads lines in short or long
// format from its standard input and uncapitalises the first letter
// of all symbols (thus making them unavailable to external
// packages).
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym rename [old new]...
//
// The rename command renames any symbol with the
// given old name to the given new name. The
// qualifier symbol's qualifier is ignored.
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new name.
//
// gosym used pkg...
//
// The used command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have references to them from any other package.
//
// gosym unused pkg...
//
// The unused command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have no references to them from any other package.
//
// gosym list [flags] [pkg...]
//
// The list command prints a line for each identifier
// used in the named packages. Each line printed has at least 6 space-separated fields
// in the following format:
// 	file-position referenced-file-position package referenced-package name type-kind
// This format is known as "long" format.
// If no packages are named, "." is used.
//
// The file-position field holds the location of the identifier.
// The referenced-file-position field holds the location of the
// definition of the identifier.
// The package field holds the path of the package containing the identifier.
// The referenced-package field holds the path of the package
// where the identifier is defined.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The type-kind field holds the type class of identifier (const,
// type, var or func), and ends with a "+" sign if this line
// marks the definition of the identifier.
//   -a=false: print internal and universe symbols too
//   -k="type,const,var,func": kinds of symbol types to include
//   -t=false: print symbol type
//   -v=false: print warnings about undefined symbols
//
// gosym write [pkg...]
//
// The gosym command reads lines in short format (see the
// "short" subcommand) from its standard input
// that represent changes to make, and changes any of the
// named packages accordingly - that is, the identifier
// at each line's file-position (and all uses of it) is changed to the new-name
// field.
//
// If no packages are named, "." is used. No files outside the named packages
// will be changed. The names of any changed files will
// be printed.
//
// As with gofix, writes are destructive - make sure your
// source files are backed up before using this command.
package main

import (
	"bufio"
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/sym"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// TODO allow changing of package identifiers too.

// caveats:
// - map keys
// - no declaration for init
// - type switches?
// - embedded types
// - import to .
// - test files are ignored.
// - can't change package identifiers
// - there's no way to give an error if renaming creates a
//	clash of symbols.

//gosym list [-t] [pkg...]
//
//list all symbols in all named packages.
//	foo/filename.go:23:3: package referenced-package name type-kind
//
//gosym used pkg...
//
//	reads lines in long format; prints any definitions (in long format)
//	found in pkgs that are used by any other packages.
//
//gosym unused pkg
//	reads lines in long format; prints any definitions (in long format)
//	found in pkgs that are not used by any other packages.
//
//gosym unexport
//	reads lines in long or short format; changes any
//	identifier names to be uncapitalised.
//
//gosym short
//	reads lines in long or short format; prints them in short format.
//
//gosym rename from1 to1 from2 to2 ...
//	reads lines in long or short format; renames symbols according
//	to the given rules.
//
//gosym write [pkg...]
//	reads lines in short format; makes any requested changes,
//	restricting changes to the listed packages.
var verbose = flag.Bool("v", true, "print warning messages")

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [-v] command [flags] [args...]\n")
		printf("%s", `
Gosym manipulates symbols in Go source code.
Various sub-commands print, process or write symbols.
`)
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() == 0 {
		flag.Usage()
	}
	name := flag.Arg(0)
	if name == "help" {
		help()
		return
	}
	var c cmd
	var args []string
	for _, e := range cmds {
		if e.name == name {
			e.fset.Parse(flag.Args()[1:])
			c = e.c
			args = e.fset.Args()
			break
		}
	}
	if c == nil {
		flag.Usage()
	}
	if err := runCmd(c, args); err != nil {
		log.Printf("gosym %s: %v", name, err)
		os.Exit(1)
	}
}

func runCmd(c cmd, args []string) error {
	types.Panic = false
	initGoPath()
	ctxt := newContext()
	defer ctxt.stdout.Flush()
	return c.run(ctxt, args)
}

type cmd interface {
	run(*context, []string) error
}

type cmdEntry struct {
	name  string
	about string
	c     cmd
	fset  *flag.FlagSet
}

var cmds []cmdEntry

func register(name string, c cmd, fset *flag.FlagSet, about string) {
	if fset == nil {
		fset = flag.NewFlagSet("gosym "+name, flag.ExitOnError)
	}
	fset.Usage = func() {
		fmt.Fprint(os.Stderr, about)
		fset.PrintDefaults()
	}
	cmds = append(cmds, cmdEntry{
		name:  name,
		about: about,
		c:     c,
		fset:  fset,
	})
}

func help() {
	for i, e := range cmds {
		if i > 0 {
			fmt.Printf("\n")
		}
		e.fset.SetOutput(os.Stdout)
		fmt.Print(e.about)
		e.fset.PrintDefaults()
	}
}

type context struct {
	mu sync.Mutex
	*sym.Context
	pkgCache map[string]*ast.Package
	pkgDirs  map[string]string // map from directory to package name.
	stdout   *bufio.Writer
}

func newContext() *context {
	ctxt := &context{
		pkgDirs: make(map[string]string),
		stdout:  bufio.NewWriter(os.Stdout),
		Context: sym.NewContext(),
	}
	ctxt.Logf = func(pos token.Pos, f string, a ...interface{}) {
		if !*verbose {
			return
		}
		log.Printf("%v: %s", ctxt.position(pos), fmt.Sprintf(f, a...))
	}
	return ctxt
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

func (ctxt *context) positionToImportPath(p token.Position) string {
	if p.Filename == "" {
		panic("empty file name")
	}
	dir := filepath.Dir(p.Filename)
	if pkg, ok := ctxt.pkgDirs[dir]; ok {
		return pkg
	}
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	ctxt.pkgDirs[dir] = bpkg.ImportPath
	return bpkg.ImportPath
}

func (ctxt *context) printf(f string, a ...interface{}) {
	fmt.Fprintf(ctxt.stdout, f, a...)
}

func (ctxt *context) position(pos token.Pos) token.Position {
	return ctxt.FileSet.Position(pos)
}

var emptyFileSet = token.NewFileSet()

func pretty(n ast.Node) string {
	var b bytes.Buffer
	printer.Fprint(&b, emptyFileSet, n)
	return b.String()
}
<|endoftext|>


<commit_before>package cliutil

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	grpcCodes "google.golang.org/grpc/codes"
	grpcStatus "google.golang.org/grpc/status"
	empty "google.golang.org/protobuf/types/known/emptypb"
	"gopkg.in/yaml.v2"

	"github.com/datawire/dlib/dexec"
	"github.com/telepresenceio/telepresence/rpc/v2/connector"
	"github.com/telepresenceio/telepresence/v2/pkg/client"
	"github.com/telepresenceio/telepresence/v2/pkg/client/errcat"
	"github.com/telepresenceio/telepresence/v2/pkg/client/userd/auth/authdata"
	"github.com/telepresenceio/telepresence/v2/pkg/filelocation"
)

// EnsureLoggedIn ensures that the user is logged in to Ambassador Cloud.  An error is returned if
// login fails.  The result code will indicate if this is a new login or if it resued an existing
// login.  If the `apikey` argument is empty an interactive login is performed; if it is non-empty
// the key is used instead of performing an interactive login.
func EnsureLoggedIn(ctx context.Context, apikey string) (connector.LoginResult_Code, error) {
	err := GetTelepresencePro(ctx)
	if err != nil {
		return connector.LoginResult_UNSPECIFIED, err
	}
	var code connector.LoginResult_Code
	err = WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		code, err = ClientEnsureLoggedIn(ctx, apikey, connectorClient)
		return err
	})
	return code, err
}

// ClientEnsureLoggedIn is like EnsureLoggedIn but uses an already acquired ConnectorClient.
func ClientEnsureLoggedIn(ctx context.Context, apikey string, connectorClient connector.ConnectorClient) (connector.LoginResult_Code, error) {
	resp, err := connectorClient.Login(ctx, &connector.LoginRequest{
		ApiKey: apikey,
	})
	if err != nil {
		if grpcStatus.Code(err) == grpcCodes.PermissionDenied {
			err = errcat.User.New(grpcStatus.Convert(err).Message())
		}
		return connector.LoginResult_UNSPECIFIED, err
	}
	return resp.GetCode(), nil
}

// Logout logs out of Ambassador Cloud.  Returns an error if not logged in.
func Logout(ctx context.Context) error {
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		_, err := connectorClient.Logout(ctx, &empty.Empty{})
		return err
	})
	if grpcStatus.Code(err) == grpcCodes.NotFound {
		err = errcat.User.New(grpcStatus.Convert(err).Message())
	}
	if err != nil {
		return err
	}
	return nil
}

// EnsureLoggedOut ensures that the user is logged out of Ambassador Cloud.  Returns nil if not
// logged in.
func EnsureLoggedOut(ctx context.Context) error {
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		_, err := connectorClient.Logout(ctx, &empty.Empty{})
		return err
	})
	if grpcStatus.Code(err) == grpcCodes.NotFound {
		err = nil
	}
	if err != nil {
		return err
	}
	return nil
}

// HasLoggedIn returns true if either the user has an active login session or an expired login
// session, and returns false if either the user has never logged in or has explicitly logged out.
func HasLoggedIn(ctx context.Context) bool {
	_, err := authdata.LoadUserInfoFromUserCache(ctx)
	return err == nil
}

func GetCloudUserInfo(ctx context.Context, autoLogin bool, refresh bool) (*connector.UserInfo, error) {
	var userInfo *connector.UserInfo
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		userInfo, err = connectorClient.GetCloudUserInfo(ctx, &connector.UserInfoRequest{
			AutoLogin: autoLogin,
			Refresh:   refresh,
		})
		return err
	})
	if err != nil {
		return nil, err
	}
	return userInfo, nil
}

func GetCloudAPIKey(ctx context.Context, description string, autoLogin bool) (string, error) {
	var keyData *connector.KeyData
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		keyData, err = connectorClient.GetCloudAPIKey(ctx, &connector.KeyRequest{
			AutoLogin:   autoLogin,
			Description: description,
		})
		return err
	})
	if err != nil {
		return "", err
	}
	return keyData.GetApiKey(), nil
}

// GetCloudLicense communicates with system a to get the jwt version of the
// license, puts it in a kubernetes secret, and then writes that secret to the
// output file for the user to apply to their cluster
func GetCloudLicense(ctx context.Context, outputFile, id string) (string, string, error) {
	var licenseData *connector.LicenseData
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		licenseData, err = connectorClient.GetCloudLicense(ctx, &connector.LicenseRequest{
			Id: id,
		})
		return err
	})
	if err != nil {
		return "", "", err
	}
	return licenseData.GetLicense(), licenseData.GetHostDomain(), nil
}

// GetTelepresencePro prompts the user to optionally install Telepresence Pro
// if it isn't installed. If the user installs it, it also asks the user to
// automatically update their configuration to use the new binary.
func GetTelepresencePro(ctx context.Context) error {
	dir, err := filelocation.AppUserConfigDir(ctx)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to get path to config files: %w", err)
	}

	// If telepresence-pro doesn't exist, then we should ask the user
	// if they want to install it
	telProLocation := filepath.Join(dir, "telepresence-pro")
	if _, err := os.Stat(telProLocation); os.IsNotExist(err) {
		reader := bufio.NewReader(os.Stdin)
		fmt.Printf("Telepresence Pro is recommended when using login features, can Telepresence install it? (y/n)")
		reply, err := reader.ReadString('\n')
		if err != nil {
			return errcat.User.Newf("error reading input: %w", err)
		}

		// If the user doesn't want to install it, then we we'll proceed
		// with launching the daemon normally
		reply = strings.TrimSpace(reply)
		if reply != "y" {
			return nil
		}

		err = installTelepresencePro(ctx, telProLocation)
		if err != nil {
			return err
		}

		// Ask the user if they want to automatically update their config
		// with the telepresence-pro binary.
		// TODO: This will remove any comments that exist in the config file
		// which it's yaml so that's _fine_ but it would be nice if we didn't
		// do that.
		fmt.Printf("Update your Telepresence config to use Telepresence Pro? (y/n)")
		reply, err = reader.ReadString('\n')
		if err != nil {
			return errcat.User.Newf("error reading input: %w", err)
		}
		reply = strings.TrimSpace(reply)
		if reply != "y" {
			return nil
		}
		err = updateConfig(ctx, telProLocation)
		if err != nil {
			return err
		}
	} else {
		// If the binary is present, we check its version to ensure it's compatible
		// with the CLI
		proCmd := dexec.CommandContext(ctx, telProLocation, "pro-version")
		proCmd.DisableLogging = true

		output, err := proCmd.CombinedOutput()
		if err != nil {
			return errcat.NoDaemonLogs.Newf("Unable to get telepresence pro version")
		}

		if !strings.Contains(string(output), client.Version()) {
			reader := bufio.NewReader(os.Stdin)
			fmt.Printf("Telepresence Pro needs to be upgraded to work with CLI version %s, allow Telepresence to upgrade it? (y/n)",
				client.Version())
			reply, err := reader.ReadString('\n')
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error reading input: %w", err)
			}

			// If the user doesn't want to install it, then we we'll proceed
			// with launching the daemon normally
			reply = strings.TrimSpace(reply)
			if reply != "y" {
				return nil
			}
			err = os.Remove(telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error removing Telepresence Pro: %w", err)
			}
			// Since we've already asked the user for permission to upgrade,
			// we can run these functions without asking permission again.
			err = installTelepresencePro(ctx, telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error installing updated Telepresence Pro: %w",
					err)
			}

			// The users configuration is most likely correct if they are upgrading,
			// but we update it just to be extra sure.
			err = updateConfig(ctx, telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error updating config: %w",
					err)
			}
		}
	}
	return nil
}

// installTelepresencePro installs the binary. Users should be asked for
// permission before using this function
func installTelepresencePro(ctx context.Context, telProLocation string) error {
	// We install the correct version of telepresence-pro based on
	// the OSS version that is associated with this client since
	// daemon versions need to match
	clientVersion := strings.Trim(client.Version(), "v")
	systemAHost := client.GetConfig(ctx).Cloud.SystemaHost
	installString := fmt.Sprintf("https://%s/download/tel-pro/%s/%s/%s/latest/telepresence-pro", systemAHost, runtime.GOOS, runtime.GOARCH, clientVersion)

	resp, err := http.Get(installString)
	if err == nil {
		defer resp.Body.Close()
		if resp.StatusCode != http.StatusOK {
			err = errors.New(resp.Status)
		}
	}
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to download Telepresence Pro: %w", err)
	}

	out, err := os.Create(telProLocation)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to create file %q for Telepresence Pro: %w", telProLocation, err)
	}
	defer out.Close()

	if _, err = io.Copy(out, resp.Body); err != nil {
		return errcat.NoDaemonLogs.Newf("unable to copy Telepresence Pro to %q: %w", telProLocation, err)
	}

	if err = os.Chmod(telProLocation, 0755); err != nil {
		return errcat.NoDaemonLogs.Newf("unable to set permissions of %q to 755: %w", telProLocation, err)
	}
	return nil
}

// updateConfig updates the userDaemonBinary in the config to point to
// telProLocation. Users should be asked for permission before this is done.
func updateConfig(ctx context.Context, telProLocation string) error {
	cfg := client.GetConfig(ctx)
	cfg.Daemons.UserDaemonBinary = telProLocation

	b, err := yaml.Marshal(cfg)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error marshaling updating config: %w", err)
	}
	cfgFile := client.GetConfigFile(ctx)
	_, err = os.OpenFile(cfgFile, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error opening config file: %w", err)
	}
	err = os.WriteFile(cfgFile, b, 0644)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error writing config file: %w", err)
	}
	return nil
}
<commit_msg>Ensure that pro-daemon on Windows has a .exe suffix<commit_after>package cliutil

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	grpcCodes "google.golang.org/grpc/codes"
	grpcStatus "google.golang.org/grpc/status"
	empty "google.golang.org/protobuf/types/known/emptypb"
	"gopkg.in/yaml.v2"

	"github.com/datawire/dlib/dexec"
	"github.com/telepresenceio/telepresence/rpc/v2/connector"
	"github.com/telepresenceio/telepresence/v2/pkg/client"
	"github.com/telepresenceio/telepresence/v2/pkg/client/errcat"
	"github.com/telepresenceio/telepresence/v2/pkg/client/userd/auth/authdata"
	"github.com/telepresenceio/telepresence/v2/pkg/filelocation"
)

// EnsureLoggedIn ensures that the user is logged in to Ambassador Cloud.  An error is returned if
// login fails.  The result code will indicate if this is a new login or if it resued an existing
// login.  If the `apikey` argument is empty an interactive login is performed; if it is non-empty
// the key is used instead of performing an interactive login.
func EnsureLoggedIn(ctx context.Context, apikey string) (connector.LoginResult_Code, error) {
	err := GetTelepresencePro(ctx)
	if err != nil {
		return connector.LoginResult_UNSPECIFIED, err
	}
	var code connector.LoginResult_Code
	err = WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		code, err = ClientEnsureLoggedIn(ctx, apikey, connectorClient)
		return err
	})
	return code, err
}

// ClientEnsureLoggedIn is like EnsureLoggedIn but uses an already acquired ConnectorClient.
func ClientEnsureLoggedIn(ctx context.Context, apikey string, connectorClient connector.ConnectorClient) (connector.LoginResult_Code, error) {
	resp, err := connectorClient.Login(ctx, &connector.LoginRequest{
		ApiKey: apikey,
	})
	if err != nil {
		if grpcStatus.Code(err) == grpcCodes.PermissionDenied {
			err = errcat.User.New(grpcStatus.Convert(err).Message())
		}
		return connector.LoginResult_UNSPECIFIED, err
	}
	return resp.GetCode(), nil
}

// Logout logs out of Ambassador Cloud.  Returns an error if not logged in.
func Logout(ctx context.Context) error {
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		_, err := connectorClient.Logout(ctx, &empty.Empty{})
		return err
	})
	if grpcStatus.Code(err) == grpcCodes.NotFound {
		err = errcat.User.New(grpcStatus.Convert(err).Message())
	}
	if err != nil {
		return err
	}
	return nil
}

// EnsureLoggedOut ensures that the user is logged out of Ambassador Cloud.  Returns nil if not
// logged in.
func EnsureLoggedOut(ctx context.Context) error {
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		_, err := connectorClient.Logout(ctx, &empty.Empty{})
		return err
	})
	if grpcStatus.Code(err) == grpcCodes.NotFound {
		err = nil
	}
	if err != nil {
		return err
	}
	return nil
}

// HasLoggedIn returns true if either the user has an active login session or an expired login
// session, and returns false if either the user has never logged in or has explicitly logged out.
func HasLoggedIn(ctx context.Context) bool {
	_, err := authdata.LoadUserInfoFromUserCache(ctx)
	return err == nil
}

func GetCloudUserInfo(ctx context.Context, autoLogin bool, refresh bool) (*connector.UserInfo, error) {
	var userInfo *connector.UserInfo
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		userInfo, err = connectorClient.GetCloudUserInfo(ctx, &connector.UserInfoRequest{
			AutoLogin: autoLogin,
			Refresh:   refresh,
		})
		return err
	})
	if err != nil {
		return nil, err
	}
	return userInfo, nil
}

func GetCloudAPIKey(ctx context.Context, description string, autoLogin bool) (string, error) {
	var keyData *connector.KeyData
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		keyData, err = connectorClient.GetCloudAPIKey(ctx, &connector.KeyRequest{
			AutoLogin:   autoLogin,
			Description: description,
		})
		return err
	})
	if err != nil {
		return "", err
	}
	return keyData.GetApiKey(), nil
}

// GetCloudLicense communicates with system a to get the jwt version of the
// license, puts it in a kubernetes secret, and then writes that secret to the
// output file for the user to apply to their cluster
func GetCloudLicense(ctx context.Context, outputFile, id string) (string, string, error) {
	var licenseData *connector.LicenseData
	err := WithConnector(ctx, func(ctx context.Context, connectorClient connector.ConnectorClient) error {
		var err error
		licenseData, err = connectorClient.GetCloudLicense(ctx, &connector.LicenseRequest{
			Id: id,
		})
		return err
	})
	if err != nil {
		return "", "", err
	}
	return licenseData.GetLicense(), licenseData.GetHostDomain(), nil
}

// GetTelepresencePro prompts the user to optionally install Telepresence Pro
// if it isn't installed. If the user installs it, it also asks the user to
// automatically update their configuration to use the new binary.
func GetTelepresencePro(ctx context.Context) error {
	dir, err := filelocation.AppUserConfigDir(ctx)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to get path to config files: %w", err)
	}

	// If telepresence-pro doesn't exist, then we should ask the user
	// if they want to install it
	telProLocation := filepath.Join(dir, "telepresence-pro")
	if runtime.GOOS == "windows" {
		telProLocation += ".exe"
	}
	if _, err := os.Stat(telProLocation); os.IsNotExist(err) {
		reader := bufio.NewReader(os.Stdin)
		fmt.Printf("Telepresence Pro is recommended when using login features, can Telepresence install it? (y/n)")
		reply, err := reader.ReadString('\n')
		if err != nil {
			return errcat.User.Newf("error reading input: %w", err)
		}

		// If the user doesn't want to install it, then we we'll proceed
		// with launching the daemon normally
		reply = strings.TrimSpace(reply)
		if reply != "y" {
			return nil
		}

		err = installTelepresencePro(ctx, telProLocation)
		if err != nil {
			return err
		}

		// Ask the user if they want to automatically update their config
		// with the telepresence-pro binary.
		// TODO: This will remove any comments that exist in the config file
		// which it's yaml so that's _fine_ but it would be nice if we didn't
		// do that.
		fmt.Printf("Update your Telepresence config to use Telepresence Pro? (y/n)")
		reply, err = reader.ReadString('\n')
		if err != nil {
			return errcat.User.Newf("error reading input: %w", err)
		}
		reply = strings.TrimSpace(reply)
		if reply != "y" {
			return nil
		}
		err = updateConfig(ctx, telProLocation)
		if err != nil {
			return err
		}
	} else {
		// If the binary is present, we check its version to ensure it's compatible
		// with the CLI
		proCmd := dexec.CommandContext(ctx, telProLocation, "pro-version")
		proCmd.DisableLogging = true

		output, err := proCmd.CombinedOutput()
		if err != nil {
			return errcat.NoDaemonLogs.Newf("Unable to get telepresence pro version")
		}

		if !strings.Contains(string(output), client.Version()) {
			reader := bufio.NewReader(os.Stdin)
			fmt.Printf("Telepresence Pro needs to be upgraded to work with CLI version %s, allow Telepresence to upgrade it? (y/n)",
				client.Version())
			reply, err := reader.ReadString('\n')
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error reading input: %w", err)
			}

			// If the user doesn't want to install it, then we we'll proceed
			// with launching the daemon normally
			reply = strings.TrimSpace(reply)
			if reply != "y" {
				return nil
			}
			err = os.Remove(telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error removing Telepresence Pro: %w", err)
			}
			// Since we've already asked the user for permission to upgrade,
			// we can run these functions without asking permission again.
			err = installTelepresencePro(ctx, telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error installing updated Telepresence Pro: %w",
					err)
			}

			// The users configuration is most likely correct if they are upgrading,
			// but we update it just to be extra sure.
			err = updateConfig(ctx, telProLocation)
			if err != nil {
				return errcat.NoDaemonLogs.Newf("error updating config: %w",
					err)
			}
		}
	}
	return nil
}

// installTelepresencePro installs the binary. Users should be asked for
// permission before using this function
func installTelepresencePro(ctx context.Context, telProLocation string) error {
	// We install the correct version of telepresence-pro based on
	// the OSS version that is associated with this client since
	// daemon versions need to match
	clientVersion := strings.Trim(client.Version(), "v")
	systemAHost := client.GetConfig(ctx).Cloud.SystemaHost
	installString := fmt.Sprintf("https://%s/download/tel-pro/%s/%s/%s/latest/%s",
		systemAHost, runtime.GOOS, runtime.GOARCH, clientVersion, filepath.Base(telProLocation))

	resp, err := http.Get(installString)
	if err == nil {
		defer resp.Body.Close()
		if resp.StatusCode != http.StatusOK {
			err = errors.New(resp.Status)
		}
	}
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to download Telepresence Pro: %w", err)
	}

	out, err := os.Create(telProLocation)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("unable to create file %q for Telepresence Pro: %w", telProLocation, err)
	}
	defer out.Close()

	if _, err = io.Copy(out, resp.Body); err != nil {
		return errcat.NoDaemonLogs.Newf("unable to copy Telepresence Pro to %q: %w", telProLocation, err)
	}

	if err = os.Chmod(telProLocation, 0755); err != nil {
		return errcat.NoDaemonLogs.Newf("unable to set permissions of %q to 755: %w", telProLocation, err)
	}
	return nil
}

// updateConfig updates the userDaemonBinary in the config to point to
// telProLocation. Users should be asked for permission before this is done.
func updateConfig(ctx context.Context, telProLocation string) error {
	cfg := client.GetConfig(ctx)
	cfg.Daemons.UserDaemonBinary = telProLocation

	b, err := yaml.Marshal(cfg)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error marshaling updating config: %w", err)
	}
	cfgFile := client.GetConfigFile(ctx)
	_, err = os.OpenFile(cfgFile, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error opening config file: %w", err)
	}
	err = os.WriteFile(cfgFile, b, 0644)
	if err != nil {
		return errcat.NoDaemonLogs.Newf("error writing config file: %w", err)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

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

	"github.com/gorilla/mux"
	"github.com/service-exposer/exposer"
	"github.com/service-exposer/exposer/listener/utils"
	"github.com/service-exposer/exposer/protocal/auth"
	"github.com/service-exposer/exposer/service"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
)

// daemonCmd represents the daemon command
var daemonCmd = &cobra.Command{
	Use:   "daemon",
	Short: "The daemon is server-side of exposer",
}

func init() {
	RootCmd.AddCommand(daemonCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// daemonCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// daemonCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	var (
		addr = "0.0.0.0:9000"
	)
	daemonCmd.Flags().StringVarP(&addr, "addr", "a", addr, "listen address")

	daemonCmd.Run = func(cmd *cobra.Command, args []string) {
		ln, err := net.Listen("tcp", addr)
		if err != nil {
			fmt.Fprintln(os.Stderr, "listen", addr, "failure", err)
			os.Exit(-1)
		}
		defer ln.Close()
		log.Print("listen ", ln.Addr())

		wsln, wsconnHandler, err := utils.WebsocketHandlerListener(ln.Addr())
		if err != nil {
			fmt.Fprintln(os.Stderr, "listen ws", ln.Addr(), "failure", err)
			os.Exit(-2)
		}
		defer wsln.Close()

		serviceRouter := service.NewRouter()

		r := mux.NewRouter()

		r.Path("/api/services").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			services := serviceRouter.All()

			result := make(map[string]*json.RawMessage)
			for _, s := range services {
				s.Attribute().View(func(attr service.Attribute) error {
					data, err := json.Marshal(attr)
					if err != nil {
						return err
					}

					rawmsg := json.RawMessage(data)
					result[s.Name()] = &rawmsg
					return nil
				})
			}

			json.NewEncoder(w).Encode(&result)

		}).Methods("GET")

		r.PathPrefix("/service/{name}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			vars := mux.Vars(r)
			var (
				name = vars["name"]
			)

			s := serviceRouter.Get(name)
			if s == nil {
				http.Error(w, "service is not exist", 404)
				return
			}

			var attr service.Attribute
			s.Attribute().View(func(a service.Attribute) error {
				attr = a
				return nil
			})

			if !attr.HTTP.Is {
				http.Error(w, "service is not a HTTP service", 404)
				return
			}

			if r.URL.Path == "/service/"+name {
				http.Redirect(w, r, "/service/"+name+"/", 302)
				return
			}

			hj, ok := w.(http.Hijacker)
			if !ok {
				http.Error(w, "webserver doesn't support hijacking", 500)
				return
			}

			client, clientbufrw, err := hj.Hijack()
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}

			server, err := s.Open()
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}

			go func(r *http.Request) {
				var err error
				for err == nil {
					subPath := r.URL.Path[len("/service/"+name):]
					if subPath == "" {
						client.Close()
						server.Close()
						return
					}
					if subPath[0] != '/' {
						subPath = "/" + subPath
					}
					url, _ := url.Parse(subPath)

					r.URL = url
					if attr.HTTP.Host != "" {
						r.Host = attr.HTTP.Host
					}
					r.Header.Set("X-Origin-IP", client.RemoteAddr().String())

					r.Write(server)

					if r.Header.Get("Upgrade") != "" {
						break
					}
					r, err = http.ReadRequest(clientbufrw.Reader)
				}

				io.Copy(server, clientbufrw)
				client.Close()
			}(r)

			io.Copy(clientbufrw, server)
			server.Close()
		})

		n := negroni.New()

		// ws
		n.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
			if strings.HasPrefix(r.URL.Path, "/service/") {
				next(w, r)
				return
			}

			connection := r.Header.Get("Connection")
			upgrade := r.Header.Get("Upgrade")
			if connection == "Upgrade" && upgrade == "websocket" {
				wsconnHandler.ServeHTTP(w, r)
				return
			}

			next(w, r)
		})

		// auth
		n.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
			if !strings.HasPrefix(r.URL.Path, "/api/") {
				next(w, r)
				return
			}

			auth := r.Header.Get("Authorization")
			if auth != key {
				w.WriteHeader(401)
				fmt.Fprintln(w, "Please set Header Authorization as Key")
				return
			}

			next(w, r)
		})

		n.UseHandler(r)

		go func() {
			server := &http.Server{
				ReadTimeout:  30 * time.Second,
				WriteTimeout: 30 * time.Second,
				Handler:      n,
			}

			err := server.Serve(ln)
			if err != nil {
				fmt.Fprintln(os.Stderr, "HTTP server shutdown. occur error:", err)
			}
		}()
		exposer.Serve(wsln, func(conn net.Conn) exposer.ProtocalHandler {
			proto := exposer.NewProtocal(conn)
			proto.On = auth.ServerSide(serviceRouter, func(k string) bool {
				return k == key
			})
			return proto
		})
	}
}
<commit_msg>daemon listen enable TLS as https/wss<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/service-exposer/exposer"
	"github.com/service-exposer/exposer/listener/utils"
	"github.com/service-exposer/exposer/protocal/auth"
	"github.com/service-exposer/exposer/service"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
)

// daemonCmd represents the daemon command
var daemonCmd = &cobra.Command{
	Use:   "daemon",
	Short: "The daemon is server-side of exposer",
}

func init() {
	RootCmd.AddCommand(daemonCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// daemonCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// daemonCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	var (
		addr       = "0.0.0.0:9000"
		enableTLS  = false
		https_cert = ""
		https_key  = ""
	)
	daemonCmd.Flags().StringVarP(&addr, "addr", "a", addr, "listen address")
	daemonCmd.Flags().BoolVarP(&enableTLS, "https", "", enableTLS, "enable TLS")
	daemonCmd.Flags().StringVarP(&https_cert, "https-cert", "", https_cert, "TLS certificate")
	daemonCmd.Flags().StringVarP(&https_key, "https-key", "", https_key, "TLS key")

	daemonCmd.Run = func(cmd *cobra.Command, args []string) {
		ln, err := net.Listen("tcp", addr)
		if err != nil {
			fmt.Fprintln(os.Stderr, "listen", addr, "failure", err)
			os.Exit(-1)
		}
		defer ln.Close()

		var schema = "http"
		var tlsConf *tls.Config
		if enableTLS {
			cert, err := tls.LoadX509KeyPair(https_cert, https_key)
			if err != nil {
				exit(-5, "LoadX509KeyPair:", err)
			}
			tlsConf = &tls.Config{
				Certificates: []tls.Certificate{cert},
			}

			// replace ln to tls.Listener
			ln = tls.NewListener(ln, tlsConf)
			defer ln.Close()
			schema = "https"
		}
		log.Print("listen ", fmt.Sprintf("%s://%s/", schema, ln.Addr()))

		wsln, wsconnHandler, err := utils.WebsocketHandlerListener(ln.Addr())
		if err != nil {
			fmt.Fprintln(os.Stderr, "listen ws", ln.Addr(), "failure", err)
			os.Exit(-2)
		}
		defer wsln.Close()

		serviceRouter := service.NewRouter()

		r := mux.NewRouter()

		r.Path("/api/services").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			services := serviceRouter.All()

			result := make(map[string]*json.RawMessage)
			for _, s := range services {
				s.Attribute().View(func(attr service.Attribute) error {
					data, err := json.Marshal(attr)
					if err != nil {
						return err
					}

					rawmsg := json.RawMessage(data)
					result[s.Name()] = &rawmsg
					return nil
				})
			}

			json.NewEncoder(w).Encode(&result)

		}).Methods("GET")

		r.PathPrefix("/service/{name}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			vars := mux.Vars(r)
			var (
				name = vars["name"]
			)

			s := serviceRouter.Get(name)
			if s == nil {
				http.Error(w, "service is not exist", 404)
				return
			}

			var attr service.Attribute
			s.Attribute().View(func(a service.Attribute) error {
				attr = a
				return nil
			})

			if !attr.HTTP.Is {
				http.Error(w, "service is not a HTTP service", 404)
				return
			}

			if r.URL.Path == "/service/"+name {
				http.Redirect(w, r, "/service/"+name+"/", 302)
				return
			}

			hj, ok := w.(http.Hijacker)
			if !ok {
				http.Error(w, "webserver doesn't support hijacking", 500)
				return
			}

			client, clientbufrw, err := hj.Hijack()
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}

			server, err := s.Open()
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}

			go func(r *http.Request) {
				var err error
				for err == nil {
					subPath := r.URL.Path[len("/service/"+name):]
					if subPath == "" {
						client.Close()
						server.Close()
						return
					}
					if subPath[0] != '/' {
						subPath = "/" + subPath
					}
					url, _ := url.Parse(subPath)

					r.URL = url
					if attr.HTTP.Host != "" {
						r.Host = attr.HTTP.Host
					}
					r.Header.Set("X-Origin-IP", client.RemoteAddr().String())

					r.Write(server)

					if r.Header.Get("Upgrade") != "" {
						break
					}
					r, err = http.ReadRequest(clientbufrw.Reader)
				}

				io.Copy(server, clientbufrw)
				client.Close()
			}(r)

			io.Copy(clientbufrw, server)
			server.Close()
		})

		n := negroni.New()

		// ws
		n.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
			if strings.HasPrefix(r.URL.Path, "/service/") {
				next(w, r)
				return
			}

			connection := r.Header.Get("Connection")
			upgrade := r.Header.Get("Upgrade")
			if connection == "Upgrade" && upgrade == "websocket" {
				wsconnHandler.ServeHTTP(w, r)
				return
			}

			next(w, r)
		})

		// auth
		n.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
			if !strings.HasPrefix(r.URL.Path, "/api/") {
				next(w, r)
				return
			}

			auth := r.Header.Get("Authorization")
			if auth != key {
				w.WriteHeader(401)
				fmt.Fprintln(w, "Please set Header Authorization as Key")
				return
			}

			next(w, r)
		})

		n.UseHandler(r)

		go func() {
			server := &http.Server{
				ReadTimeout:  30 * time.Second,
				WriteTimeout: 30 * time.Second,
				Handler:      n,
				TLSConfig:    tlsConf,
			}

			err := server.Serve(ln)
			if err != nil {
				fmt.Fprintln(os.Stderr, "HTTP server shutdown. occur error:", err)
			}
		}()
		exposer.Serve(wsln, func(conn net.Conn) exposer.ProtocalHandler {
			proto := exposer.NewProtocal(conn)
			proto.On = auth.ServerSide(serviceRouter, func(k string) bool {
				return k == key
			})
			return proto
		})
	}
}
<|endoftext|>


<commit_before>package sphero

import (
	"fmt"
	"time"

	"github.com/hybridgroup/gobot"
)

type packet struct {
	header   []uint8
	body     []uint8
	checksum uint8
}

type SpheroDriver struct {
	gobot.Driver
	seq             uint8
	asyncResponse   [][]uint8
	syncResponse    [][]uint8
	packetChannel   chan *packet
	responseChannel chan []uint8
}

func NewSpheroDriver(a *SpheroAdaptor, name string) *SpheroDriver {
	s := &SpheroDriver{
		Driver: *gobot.NewDriver(
			name,
			"SpheroDriver",
			a,
		),
		packetChannel:   make(chan *packet, 1024),
		responseChannel: make(chan []uint8, 1024),
	}

	s.AddEvent("collision")
	s.AddCommand("SetRGB", func(params map[string]interface{}) interface{} {
		r := uint8(params["r"].(float64))
		g := uint8(params["g"].(float64))
		b := uint8(params["b"].(float64))
		s.SetRGB(r, g, b)
		return nil
	})

	s.AddCommand("Roll", func(params map[string]interface{}) interface{} {
		speed := uint8(params["speed"].(float64))
		heading := uint16(params["heading"].(float64))
		s.Roll(speed, heading)
		return nil
	})

	s.AddCommand("Stop", func(params map[string]interface{}) interface{} {
		s.Stop()
		return nil
	})

	s.AddCommand("GetRGB", func(params map[string]interface{}) interface{} {
		return s.GetRGB()
	})

	s.AddCommand("SetBackLED", func(params map[string]interface{}) interface{} {
		level := uint8(params["level"].(float64))
		s.SetBackLED(level)
		return nil
	})

	s.AddCommand("SetHeading", func(params map[string]interface{}) interface{} {
		heading := uint16(params["heading"].(float64))
		s.SetHeading(heading)
		return nil
	})
	s.AddCommand("SetStabilization", func(params map[string]interface{}) interface{} {
		on := params["heading"].(bool)
		s.SetStabilization(on)
		return nil
	})

	return s
}

func (s *SpheroDriver) adaptor() *SpheroAdaptor {
	return s.Adaptor().(*SpheroAdaptor)
}

func (s *SpheroDriver) Init() bool {
	return true
}

func (s *SpheroDriver) Start() bool {
	go func() {
		for {
			packet := <-s.packetChannel
			s.write(packet)
		}
	}()

	go func() {
		for {
			response := <-s.responseChannel
			s.syncResponse = append(s.syncResponse, response)
		}
	}()

	go func() {
		for {
			header := s.readHeader()
			if header != nil && len(header) != 0 {
				body := s.readBody(header[4])
				if header[1] == 0xFE {
					async := append(header, body...)
					s.asyncResponse = append(s.asyncResponse, async)
				} else {
					s.responseChannel <- append(header, body...)
				}
			}
		}
	}()

	go func() {
		for {
			var evt []uint8
			for len(s.asyncResponse) != 0 {
				evt, s.asyncResponse = s.asyncResponse[len(s.asyncResponse)-1], s.asyncResponse[:len(s.asyncResponse)-1]
				if evt[2] == 0x07 {
					s.handleCollisionDetected(evt)
				}
			}
			time.Sleep(100 * time.Millisecond)
		}
	}()

	s.configureCollisionDetection()
	s.enableStopOnDisconnect()

	return true
}

func (s *SpheroDriver) Halt() bool {
	gobot.Every(10*time.Millisecond, func() {
		s.Stop()
	})
	time.Sleep(1 * time.Second)
	return true
}

func (s *SpheroDriver) SetRGB(r uint8, g uint8, b uint8) {
	s.packetChannel <- s.craftPacket([]uint8{r, g, b, 0x01}, 0x20)
}

func (s *SpheroDriver) GetRGB() []uint8 {
	return s.getSyncResponse(s.craftPacket([]uint8{}, 0x22))
}

func (s *SpheroDriver) SetBackLED(level uint8) {
	s.packetChannel <- s.craftPacket([]uint8{level}, 0x21)
}

func (s *SpheroDriver) SetHeading(heading uint16) {
	s.packetChannel <- s.craftPacket([]uint8{uint8(heading >> 8), uint8(heading & 0xFF)}, 0x01)
}

func (s *SpheroDriver) SetStabilization(on bool) {
	b := uint8(0x01)
	if on == false {
		b = 0x00
	}
	s.packetChannel <- s.craftPacket([]uint8{b}, 0x02)
}

func (s *SpheroDriver) Roll(speed uint8, heading uint16) {
	s.packetChannel <- s.craftPacket([]uint8{speed, uint8(heading >> 8), uint8(heading & 0xFF), 0x01}, 0x30)
}

func (s *SpheroDriver) Stop() {
	s.Roll(0, 0)
}

func (s *SpheroDriver) configureCollisionDetection() {
	s.packetChannel <- s.craftPacket([]uint8{0x01, 0x40, 0x40, 0x50, 0x50, 0x60}, 0x12)
}

func (s *SpheroDriver) enableStopOnDisconnect() {
	s.packetChannel <- s.craftPacket([]uint8{0x00, 0x00, 0x00, 0x01}, 0x37)
}

func (s *SpheroDriver) handleCollisionDetected(data []uint8) {
	gobot.Publish(s.Event("collision"), data)
}

func (s *SpheroDriver) getSyncResponse(packet *packet) []byte {
	s.packetChannel <- packet
	for i := 0; i < 500; i++ {
		for key := range s.syncResponse {
			if s.syncResponse[key][3] == packet.header[4] && len(s.syncResponse[key]) > 6 {
				var response []byte
				response, s.syncResponse = s.syncResponse[len(s.syncResponse)-1], s.syncResponse[:len(s.syncResponse)-1]
				return response
			}
		}
		time.Sleep(10 * time.Microsecond)
	}

	return []byte{}
}

func (s *SpheroDriver) craftPacket(body []uint8, cid byte) *packet {
	packet := new(packet)
	packet.body = body
	dlen := len(packet.body) + 1
	packet.header = []uint8{0xFF, 0xFF, 0x02, cid, s.seq, uint8(dlen)}
	packet.checksum = s.calculateChecksum(packet)
	return packet
}

func (s *SpheroDriver) write(packet *packet) {
	buf := append(packet.header, packet.body...)
	buf = append(buf, packet.checksum)
	length, err := s.adaptor().sp.Write(buf)
	if err != nil {
		fmt.Println(s.Name, err)
		s.adaptor().Disconnect()
		fmt.Println("Reconnecting to SpheroDriver...")
		s.adaptor().Connect()
		return
	} else if length != len(buf) {
		fmt.Println("Not enough bytes written", s.Name)
	}
	s.seq++
}

func (s *SpheroDriver) calculateChecksum(packet *packet) uint8 {
	buf := append(packet.header, packet.body...)
	buf = buf[2:]
	var calculatedChecksum uint16
	for i := range buf {
		calculatedChecksum += uint16(buf[i])
	}
	return uint8(^(calculatedChecksum % 256))
}

func (s *SpheroDriver) readHeader() []uint8 {
	data := s.readNextChunk(5)
	if data == nil {
		return nil
	}
	return data
}

func (s *SpheroDriver) readBody(length uint8) []uint8 {
	data := s.readNextChunk(length)
	if data == nil {
		return nil
	}
	return data
}

func (s *SpheroDriver) readNextChunk(length uint8) []uint8 {
	time.Sleep(1000 * time.Microsecond)
	var read = make([]uint8, int(length))
	l, err := s.adaptor().sp.Read(read[:])
	if err != nil || length != uint8(l) {
		return nil
	}
	return read
}
<commit_msg>pass argument DeviceID to func craftPacket to identify virtual device the packet is intended for<commit_after>package sphero

import (
	"fmt"
	"time"

	"github.com/hybridgroup/gobot"
)

type packet struct {
	header   []uint8
	body     []uint8
	checksum uint8
}

type SpheroDriver struct {
	gobot.Driver
	seq             uint8
	asyncResponse   [][]uint8
	syncResponse    [][]uint8
	packetChannel   chan *packet
	responseChannel chan []uint8
}

func NewSpheroDriver(a *SpheroAdaptor, name string) *SpheroDriver {
	s := &SpheroDriver{
		Driver: *gobot.NewDriver(
			name,
			"SpheroDriver",
			a,
		),
		packetChannel:   make(chan *packet, 1024),
		responseChannel: make(chan []uint8, 1024),
	}

	s.AddEvent("collision")
	s.AddCommand("SetRGB", func(params map[string]interface{}) interface{} {
		r := uint8(params["r"].(float64))
		g := uint8(params["g"].(float64))
		b := uint8(params["b"].(float64))
		s.SetRGB(r, g, b)
		return nil
	})

	s.AddCommand("Roll", func(params map[string]interface{}) interface{} {
		speed := uint8(params["speed"].(float64))
		heading := uint16(params["heading"].(float64))
		s.Roll(speed, heading)
		return nil
	})

	s.AddCommand("Stop", func(params map[string]interface{}) interface{} {
		s.Stop()
		return nil
	})

	s.AddCommand("GetRGB", func(params map[string]interface{}) interface{} {
		return s.GetRGB()
	})

	s.AddCommand("SetBackLED", func(params map[string]interface{}) interface{} {
		level := uint8(params["level"].(float64))
		s.SetBackLED(level)
		return nil
	})

	s.AddCommand("SetHeading", func(params map[string]interface{}) interface{} {
		heading := uint16(params["heading"].(float64))
		s.SetHeading(heading)
		return nil
	})
	s.AddCommand("SetStabilization", func(params map[string]interface{}) interface{} {
		on := params["heading"].(bool)
		s.SetStabilization(on)
		return nil
	})

	return s
}

func (s *SpheroDriver) adaptor() *SpheroAdaptor {
	return s.Adaptor().(*SpheroAdaptor)
}

func (s *SpheroDriver) Init() bool {
	return true
}

func (s *SpheroDriver) Start() bool {
	go func() {
		for {
			packet := <-s.packetChannel
			s.write(packet)
		}
	}()

	go func() {
		for {
			response := <-s.responseChannel
			s.syncResponse = append(s.syncResponse, response)
		}
	}()

	go func() {
		for {
			header := s.readHeader()
			if header != nil && len(header) != 0 {
				body := s.readBody(header[4])
				if header[1] == 0xFE {
					async := append(header, body...)
					s.asyncResponse = append(s.asyncResponse, async)
				} else {
					s.responseChannel <- append(header, body...)
				}
			}
		}
	}()

	go func() {
		for {
			var evt []uint8
			for len(s.asyncResponse) != 0 {
				evt, s.asyncResponse = s.asyncResponse[len(s.asyncResponse)-1], s.asyncResponse[:len(s.asyncResponse)-1]
				if evt[2] == 0x07 {
					s.handleCollisionDetected(evt)
				}
			}
			time.Sleep(100 * time.Millisecond)
		}
	}()

	s.configureCollisionDetection()
	s.enableStopOnDisconnect()

	return true
}

func (s *SpheroDriver) Halt() bool {
	gobot.Every(10*time.Millisecond, func() {
		s.Stop()
	})
	time.Sleep(1 * time.Second)
	return true
}

func (s *SpheroDriver) SetRGB(r uint8, g uint8, b uint8) {
	s.packetChannel <- s.craftPacket([]uint8{r, g, b, 0x01}, 0x02, 0x20)
}

func (s *SpheroDriver) GetRGB() []uint8 {
	return s.getSyncResponse(s.craftPacket([]uint8{}, 0x02, 0x22))
}

func (s *SpheroDriver) SetBackLED(level uint8) {
	s.packetChannel <- s.craftPacket([]uint8{level}, 0x02, 0x21)
}

func (s *SpheroDriver) SetHeading(heading uint16) {
	s.packetChannel <- s.craftPacket([]uint8{uint8(heading >> 8), uint8(heading & 0xFF)}, 0x02, 0x01)
}

func (s *SpheroDriver) SetStabilization(on bool) {
	b := uint8(0x01)
	if on == false {
		b = 0x00
	}
	s.packetChannel <- s.craftPacket([]uint8{b}, 0x02, 0x02)
}

func (s *SpheroDriver) Roll(speed uint8, heading uint16) {
	s.packetChannel <- s.craftPacket([]uint8{speed, uint8(heading >> 8), uint8(heading & 0xFF), 0x01}, 0x02, 0x30)
}

func (s *SpheroDriver) Stop() {
	s.Roll(0, 0)
}

func (s *SpheroDriver) configureCollisionDetection() {
	s.packetChannel <- s.craftPacket([]uint8{0x01, 0x40, 0x40, 0x50, 0x50, 0x60}, 0x02, 0x12)
}

func (s *SpheroDriver) enableStopOnDisconnect() {
	s.packetChannel <- s.craftPacket([]uint8{0x00, 0x00, 0x00, 0x01}, 0x02, 0x37)
}

func (s *SpheroDriver) handleCollisionDetected(data []uint8) {
	gobot.Publish(s.Event("collision"), data)
}

func (s *SpheroDriver) getSyncResponse(packet *packet) []byte {
	s.packetChannel <- packet
	for i := 0; i < 500; i++ {
		for key := range s.syncResponse {
			if s.syncResponse[key][3] == packet.header[4] && len(s.syncResponse[key]) > 6 {
				var response []byte
				response, s.syncResponse = s.syncResponse[len(s.syncResponse)-1], s.syncResponse[:len(s.syncResponse)-1]
				return response
			}
		}
		time.Sleep(10 * time.Microsecond)
	}

	return []byte{}
}

func (s *SpheroDriver) craftPacket(body []uint8, did byte, cid byte) *packet {
	packet := new(packet)
	packet.body = body
	dlen := len(packet.body) + 1
	packet.header = []uint8{0xFF, 0xFF, did, cid, s.seq, uint8(dlen)}
	packet.checksum = s.calculateChecksum(packet)
	return packet
}

func (s *SpheroDriver) write(packet *packet) {
	buf := append(packet.header, packet.body...)
	buf = append(buf, packet.checksum)
	length, err := s.adaptor().sp.Write(buf)
	if err != nil {
		fmt.Println(s.Name, err)
		s.adaptor().Disconnect()
		fmt.Println("Reconnecting to SpheroDriver...")
		s.adaptor().Connect()
		return
	} else if length != len(buf) {
		fmt.Println("Not enough bytes written", s.Name)
	}
	s.seq++
}

func (s *SpheroDriver) calculateChecksum(packet *packet) uint8 {
	buf := append(packet.header, packet.body...)
	buf = buf[2:]
	var calculatedChecksum uint16
	for i := range buf {
		calculatedChecksum += uint16(buf[i])
	}
	return uint8(^(calculatedChecksum % 256))
}

func (s *SpheroDriver) readHeader() []uint8 {
	data := s.readNextChunk(5)
	if data == nil {
		return nil
	}
	return data
}

func (s *SpheroDriver) readBody(length uint8) []uint8 {
	data := s.readNextChunk(length)
	if data == nil {
		return nil
	}
	return data
}

func (s *SpheroDriver) readNextChunk(length uint8) []uint8 {
	time.Sleep(1000 * time.Microsecond)
	var read = make([]uint8, int(length))
	l, err := s.adaptor().sp.Read(read[:])
	if err != nil || length != uint8(l) {
		return nil
	}
	return read
}
<|endoftext|>


<commit_before>package mpb

import (
	"io"

	"github.com/vbauerster/mpb/v8/decor"
)

// BarFiller interface.
// Bar (without decorators) renders itself by calling BarFiller's Fill method.
type BarFiller interface {
	Fill(w io.Writer, stat decor.Statistics) error
}

// BarFillerBuilder interface.
// Default implementations are:
//
//	BarStyle()
//	SpinnerStyle()
//	NopStyle()
type BarFillerBuilder interface {
	Build() BarFiller
}

// BarFillerFunc is function type adapter to convert compatible function
// into BarFiller interface.
type BarFillerFunc func(w io.Writer, stat decor.Statistics) error

func (f BarFillerFunc) Fill(w io.Writer, stat decor.Statistics) error {
	return f(w, stat)
}

// BarFillerBuilderFunc is function type adapter to convert compatible
// function into BarFillerBuilder interface.
type BarFillerBuilderFunc func() BarFiller

func (f BarFillerBuilderFunc) Build() BarFiller {
	return f()
}
<commit_msg>minor: drop param names<commit_after>package mpb

import (
	"io"

	"github.com/vbauerster/mpb/v8/decor"
)

// BarFiller interface.
// Bar (without decorators) renders itself by calling BarFiller's Fill method.
type BarFiller interface {
	Fill(io.Writer, decor.Statistics) error
}

// BarFillerBuilder interface.
// Default implementations are:
//
//	BarStyle()
//	SpinnerStyle()
//	NopStyle()
type BarFillerBuilder interface {
	Build() BarFiller
}

// BarFillerFunc is function type adapter to convert compatible function
// into BarFiller interface.
type BarFillerFunc func(io.Writer, decor.Statistics) error

func (f BarFillerFunc) Fill(w io.Writer, stat decor.Statistics) error {
	return f(w, stat)
}

// BarFillerBuilderFunc is function type adapter to convert compatible
// function into BarFillerBuilder interface.
type BarFillerBuilderFunc func() BarFiller

func (f BarFillerBuilderFunc) Build() BarFiller {
	return f()
}
<|endoftext|>


<commit_before>package daikin

import (
	"fmt"
	"log"
	"net/url"
	"strconv"
	"time"
)

type baseDaikin struct {
	info            *BasicInfo
	host            string
	refreshInterval time.Duration

	controlState ControlState
	sensorState  SensorState
	listeners    []chan ACState
}

type AC interface {
	AutoRefresh(interval time.Duration)
	BasicInfo() *BasicInfo
	RefreshBasicInfo() (*BasicInfo, error)
	SendState() error
	RefreshState() (*ControlState, *SensorState, error)
	ControlState() *ControlState
	SensorState() *SensorState
	OnStateUpdate() chan ACState
}

func (d *baseDaikin) ControlState() *ControlState {
	return &d.controlState
}

func (d *baseDaikin) SensorState() *SensorState {
	return &d.sensorState
}

func (d *baseDaikin) BasicInfo() *BasicInfo {
	return d.info
}

func (d *baseDaikin) OnStateUpdate() chan ACState {
	c := make(chan ACState)

	d.listeners = append(d.listeners, c)

	return c
}

func (d *baseDaikin) emitStateUpdate() {
	s := ACState{d.controlState, d.sensorState}
	for _, c := range d.listeners {
		go func() {
			select {
			case c <- s:
			default:
			}
		}()
	}
}

type ACState struct {
	ControlState
	SensorState
}

func defaultControlState() ControlState {
	return ControlState{
		Power:        PowerOff,
		Mode:         ModeNone,
		Fan:          FanNone,
		FanDirection: FanDirectionNone,
		Timer:        TimerNone,
	}
}

type ControlState struct {
	Power             Power
	TargetTemperature float64
	TargetHumidity    int
	Mode              Mode
	Fan               Fan
	FanDirection      FanDirection
	Timer             Timer
}

func (s *ControlState) GetWirelessValues() url.Values {
	return url.Values{
		"pow":    []string{s.Power.wireless},
		"mode":   []string{s.Mode.wireless},
		"stemp":  []string{fmt.Sprintf("%.2f", s.TargetTemperature)},
		"shum":   []string{fmt.Sprintf("%d", s.TargetHumidity)},
		"f_rate": []string{s.Fan.wireless},
		"f_dir":  []string{s.FanDirection.wireless},
	}
}

func (s *ControlState) ParseWirelessValues(values url.Values) error {
	var err error

	if len(values["pow"]) < 1 {
		return fmt.Errorf("pow has zero length")
	}
	s.Power = parsePower(true, values["pow"][0])

	s.Mode = parseMode(true, values["mode"][0])

	if has(values, "stemp") {

		s.TargetTemperature, err = strconv.ParseFloat(values["stemp"][0], 64)
		if err != nil {
			log.Printf("Warning: Couldn't parse target temperature: %s - %s", values["stemp"][0], err)
		}
	}

	if has(values, "shum") {

		targetHumidity, err := strconv.ParseInt(values["shum"][0], 10, 64)
		if err != nil {
			log.Printf("Warning: Couldn't parse target humidity: %s", err)
		}
		s.TargetHumidity = int(targetHumidity)

	}

	if has(values, "f_rate") {
		s.Fan = parseFan(true, values["f_rate"][0])
	}

	if has(values, "f_dir") {
		s.FanDirection = parseFanDirection(true, values["f_dir"][0])
	}

	return nil
}
func has(values url.Values, name string) bool {
	_, ok := values[name]
	return ok
}
func getVal(values url.Values, name string) (val string) {

	if v, ok := values[name]; ok {
		val = v[0]
	}

	return
}

type SensorState struct {
	// sensor info
	InsideTemperature  float64
	InsideHumidity     int
	OutsideTemperature float64
}

func (s *SensorState) GetWirelessValues() url.Values {
	return url.Values{
		"htemp": []string{fmt.Sprintf("%.2f", s.InsideTemperature)},
		"hhum":  []string{fmt.Sprintf("%d", s.InsideHumidity)},
		"otemp": []string{fmt.Sprintf("%.2f", s.OutsideTemperature)},
	}
}

func (s *SensorState) ParseWirelessValues(values url.Values) {
	var err error

	s.InsideTemperature, err = strconv.ParseFloat(values["htemp"][0], 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s - %s", values["htemp"][0], err)
	}

	insideHumidity, err := strconv.ParseInt(values["hhum"][0], 10, 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s", err)
	}
	s.InsideHumidity = int(insideHumidity)

	s.OutsideTemperature, err = strconv.ParseFloat(values["otemp"][0], 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s", err)
	}

}
<commit_msg>If there is an error message, return it.<commit_after>package daikin

import (
	"fmt"
	"log"
	"net/url"
	"strconv"
	"time"
)

type baseDaikin struct {
	info            *BasicInfo
	host            string
	refreshInterval time.Duration

	controlState ControlState
	sensorState  SensorState
	listeners    []chan ACState
}

type AC interface {
	AutoRefresh(interval time.Duration)
	BasicInfo() *BasicInfo
	RefreshBasicInfo() (*BasicInfo, error)
	SendState() error
	RefreshState() (*ControlState, *SensorState, error)
	ControlState() *ControlState
	SensorState() *SensorState
	OnStateUpdate() chan ACState
}

func (d *baseDaikin) ControlState() *ControlState {
	return &d.controlState
}

func (d *baseDaikin) SensorState() *SensorState {
	return &d.sensorState
}

func (d *baseDaikin) BasicInfo() *BasicInfo {
	return d.info
}

func (d *baseDaikin) OnStateUpdate() chan ACState {
	c := make(chan ACState)

	d.listeners = append(d.listeners, c)

	return c
}

func (d *baseDaikin) emitStateUpdate() {
	s := ACState{d.controlState, d.sensorState}
	for _, c := range d.listeners {
		go func() {
			select {
			case c <- s:
			default:
			}
		}()
	}
}

type ACState struct {
	ControlState
	SensorState
}

func defaultControlState() ControlState {
	return ControlState{
		Power:        PowerOff,
		Mode:         ModeNone,
		Fan:          FanNone,
		FanDirection: FanDirectionNone,
		Timer:        TimerNone,
	}
}

type ControlState struct {
	Power             Power
	TargetTemperature float64
	TargetHumidity    int
	Mode              Mode
	Fan               Fan
	FanDirection      FanDirection
	Timer             Timer
}

func (s *ControlState) GetWirelessValues() url.Values {
	return url.Values{
		"pow":    []string{s.Power.wireless},
		"mode":   []string{s.Mode.wireless},
		"stemp":  []string{fmt.Sprintf("%.2f", s.TargetTemperature)},
		"shum":   []string{fmt.Sprintf("%d", s.TargetHumidity)},
		"f_rate": []string{s.Fan.wireless},
		"f_dir":  []string{s.FanDirection.wireless},
	}
}

func (s *ControlState) ParseWirelessValues(values url.Values) error {
	var err error

	if len(values["ret"]) > 0 && values["ret"][0] != "OK" {
		return fmt.Errorf("error: %s", values["ret"])
	}

	if len(values["pow"]) < 1 {
		return fmt.Errorf("pow has zero length")
	}
	s.Power = parsePower(true, values["pow"][0])

	s.Mode = parseMode(true, values["mode"][0])

	if has(values, "stemp") {

		s.TargetTemperature, err = strconv.ParseFloat(values["stemp"][0], 64)
		if err != nil {
			log.Printf("Warning: Couldn't parse target temperature: %s - %s", values["stemp"][0], err)
		}
	}

	if has(values, "shum") {

		targetHumidity, err := strconv.ParseInt(values["shum"][0], 10, 64)
		if err != nil {
			log.Printf("Warning: Couldn't parse target humidity: %s", err)
		}
		s.TargetHumidity = int(targetHumidity)

	}

	if has(values, "f_rate") {
		s.Fan = parseFan(true, values["f_rate"][0])
	}

	if has(values, "f_dir") {
		s.FanDirection = parseFanDirection(true, values["f_dir"][0])
	}

	return nil
}
func has(values url.Values, name string) bool {
	_, ok := values[name]
	return ok
}
func getVal(values url.Values, name string) (val string) {

	if v, ok := values[name]; ok {
		val = v[0]
	}

	return
}

type SensorState struct {
	// sensor info
	InsideTemperature  float64
	InsideHumidity     int
	OutsideTemperature float64
}

func (s *SensorState) GetWirelessValues() url.Values {
	return url.Values{
		"htemp": []string{fmt.Sprintf("%.2f", s.InsideTemperature)},
		"hhum":  []string{fmt.Sprintf("%d", s.InsideHumidity)},
		"otemp": []string{fmt.Sprintf("%.2f", s.OutsideTemperature)},
	}
}

func (s *SensorState) ParseWirelessValues(values url.Values) {
	var err error

	s.InsideTemperature, err = strconv.ParseFloat(values["htemp"][0], 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s - %s", values["htemp"][0], err)
	}

	insideHumidity, err := strconv.ParseInt(values["hhum"][0], 10, 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s", err)
	}
	s.InsideHumidity = int(insideHumidity)

	s.OutsideTemperature, err = strconv.ParseFloat(values["otemp"][0], 64)
	if err != nil {
		log.Printf("Warning: Couldn't parse inside temperature: %s", err)
	}

}
<|endoftext|>


<commit_before>package serial

import (
	"testing"
)

func TestConnection(t *testing.T) {
	if testing.Short() {
		return
	}
	c0 := &Config{Name: "COM5", Baud: 115200}

	/*
		c1 := new(Config)
		c1.Name = "COM5"
		c1.Baud = 115200
	*/

	s, err := OpenPort(c0)
	if err != nil {
		t.Fatal(err)
	}

	_, err = s.Write([]byte("test"))
	if err != nil {
		t.Fatal(err)
	}

	buf := make([]byte, 128)
	_, err = s.Read(buf)
	if err != nil {
		t.Fatal(err)
	}
}

// BUG(tarmigan): Add loopback test
func TestLoopback(t *testing.T) {

}
<commit_msg>Improve loopback test<commit_after>package serial

import (
	"testing"
	"time"
)

func TestConnection(t *testing.T) {
	c0 := &Config{Name: "/dev/ttyUSB0", Baud: 115200}
	c1 := &Config{Name: "/dev/ttyUSB1", Baud: 115200}

	s1, err := OpenPort(c0)
	if err != nil {
		t.Fatal(err)
	}

	s2, err := OpenPort(c1)
	if err != nil {
		t.Fatal(err)
	}

	ch := make(chan int, 1)
	go func() {
		buf := make([]byte, 128)
		var readCount int
		for {
			n, err := s2.Read(buf)
			if err != nil {
				t.Fatal(err)
			}
			readCount++
			t.Logf("Read %v %v bytes: % 02x %s", readCount, n, buf[:n], buf[:n])
			select {
			case <-ch:
				ch <- readCount
				close(ch)
			default:
			}
		}
	}()

	if _, err = s1.Write([]byte("hello")); err != nil {
		t.Fatal(err)
	}
	if _, err = s1.Write([]byte(" ")); err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second)
	if _, err = s1.Write([]byte("world")); err != nil {
		t.Fatal(err)
	}
	time.Sleep(time.Second / 10)

	ch <- 0
	s1.Write([]byte(" ")) // We could be blocked in the read without this
	c := <-ch
	exp := 5
	if c >= exp {
		t.Fatalf("Expected less than %v read, got %v", exp, c)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network_test

import (
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/network"
	"github.com/juju/juju/testing"
)

type PortSetSuite struct {
	testing.BaseSuite

	portRange1 network.PortRange
	portRange2 network.PortRange
	portRange3 network.PortRange
	portRange4 network.PortRange
}

var _ = gc.Suite(&PortSetSuite{})

func (s *PortSetSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	var err error
	s.portRange1, err = network.ParsePortRangePorts("8000-8099", "tcp")
	c.Assert(err, jc.ErrorIsNil)
	s.portRange2, err = network.ParsePortRangePorts("80", "tcp")
	c.Assert(err, jc.ErrorIsNil)
	s.portRange3, err = network.ParsePortRangePorts("79-81", "tcp")
	c.Assert(err, jc.ErrorIsNil)
	s.portRange4, err = network.ParsePortRangePorts("5000-5123", "udp")
	c.Assert(err, jc.ErrorIsNil)
}

func (s *PortSetSuite) TestNewPortSet(c *gc.C) {
	portSet := network.NewPortSet(s.portRange1)
	c.Assert(portSet.IsEmpty(), jc.IsFalse)
	c.Assert(portSet.Ports(), gc.HasLen, 100)
}

func (s *PortSetSuite) TestPortSetUnion(c *gc.C) {
	portSet1 := network.NewPortSet(s.portRange2)
	portSet2 := network.NewPortSet(s.portRange3)

	result := portSet1.Union(portSet2)
	c.Assert(result.Ports(), gc.HasLen, 3)
}

func (s *PortSetSuite) TestPortSetDifference(c *gc.C) {
	s.portRange2.ToPort = 83
	portSet1 := network.NewPortSet(s.portRange2)
	portSet2 := network.NewPortSet(s.portRange3)

	result := portSet1.Difference(portSet2)
	c.Assert(result.Ports(), gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetIsEmpty(c *gc.C) {
	portSet := network.NewPortSet()
	c.Assert(portSet.IsEmpty(), jc.IsTrue)
}

func (s *PortSetSuite) TestPortSetIsNotEmpty(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2)
	c.Assert(portSet.IsEmpty(), jc.IsFalse)
}

func (s *PortSetSuite) TestPortSetAdd(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2)
	c.Check(portSet.IsEmpty(), jc.IsFalse)
	portSet.Add(network.Port{Number: 81, Protocol: "tcp"})

	c.Assert(portSet.Ports(), gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetAddRanges(c *gc.C) {
	s.portRange2.ToPort = 83
	portSet := network.NewPortSet(s.portRange2)
	c.Check(portSet.IsEmpty(), jc.IsFalse)

	portSet.AddRanges(s.portRange3)
	c.Assert(portSet.Ports(), gc.HasLen, 5)
}

func (s *PortSetSuite) TestPortSetProtocols(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2, s.portRange4)
	protocols := portSet.Protocols()
	c.Assert(protocols, gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetPorts(c *gc.C) {
	portSet := network.NewPortSet(s.portRange3)
	ports := portSet.Ports()
	c.Assert(ports, gc.HasLen, 3)
}

func (s *PortSetSuite) TestPortSetPortStrings(c *gc.C) {
	portSet := network.NewPortSet(s.portRange3)
	ports := portSet.PortStrings("tcp")
	c.Assert(ports, gc.HasLen, 3)
}
<commit_msg>ParsePortRangePorts -> ParsePortRange.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package network_test

import (
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/network"
	"github.com/juju/juju/testing"
)

type PortSetSuite struct {
	testing.BaseSuite

	portRange1 network.PortRange
	portRange2 network.PortRange
	portRange3 network.PortRange
	portRange4 network.PortRange
}

var _ = gc.Suite(&PortSetSuite{})

func (s *PortSetSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	portRange1, err := network.ParsePortRange("8000-8099/tcp")
	c.Assert(err, jc.ErrorIsNil)
	portRange2, err := network.ParsePortRange("80/tcp")
	c.Assert(err, jc.ErrorIsNil)
	portRange3, err := network.ParsePortRange("79-81/tcp")
	c.Assert(err, jc.ErrorIsNil)
	portRange4, err := network.ParsePortRange("5000-5123/udp")
	c.Assert(err, jc.ErrorIsNil)

	s.portRange1 = *portRange1
	s.portRange2 = *portRange2
	s.portRange3 = *portRange3
	s.portRange4 = *portRange4
}

func (s *PortSetSuite) TestNewPortSet(c *gc.C) {
	portSet := network.NewPortSet(s.portRange1)
	c.Assert(portSet.IsEmpty(), jc.IsFalse)
	c.Assert(portSet.Ports(), gc.HasLen, 100)
}

func (s *PortSetSuite) TestPortSetUnion(c *gc.C) {
	portSet1 := network.NewPortSet(s.portRange2)
	portSet2 := network.NewPortSet(s.portRange3)

	result := portSet1.Union(portSet2)
	c.Assert(result.Ports(), gc.HasLen, 3)
}

func (s *PortSetSuite) TestPortSetDifference(c *gc.C) {
	s.portRange2.ToPort = 83
	portSet1 := network.NewPortSet(s.portRange2)
	portSet2 := network.NewPortSet(s.portRange3)

	result := portSet1.Difference(portSet2)
	c.Assert(result.Ports(), gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetIsEmpty(c *gc.C) {
	portSet := network.NewPortSet()
	c.Assert(portSet.IsEmpty(), jc.IsTrue)
}

func (s *PortSetSuite) TestPortSetIsNotEmpty(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2)
	c.Assert(portSet.IsEmpty(), jc.IsFalse)
}

func (s *PortSetSuite) TestPortSetAdd(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2)
	c.Check(portSet.IsEmpty(), jc.IsFalse)
	portSet.Add(network.Port{Number: 81, Protocol: "tcp"})

	c.Assert(portSet.Ports(), gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetAddRanges(c *gc.C) {
	s.portRange2.ToPort = 83
	portSet := network.NewPortSet(s.portRange2)
	c.Check(portSet.IsEmpty(), jc.IsFalse)

	portSet.AddRanges(s.portRange3)
	c.Assert(portSet.Ports(), gc.HasLen, 5)
}

func (s *PortSetSuite) TestPortSetProtocols(c *gc.C) {
	portSet := network.NewPortSet(s.portRange2, s.portRange4)
	protocols := portSet.Protocols()
	c.Assert(protocols, gc.HasLen, 2)
}

func (s *PortSetSuite) TestPortSetPorts(c *gc.C) {
	portSet := network.NewPortSet(s.portRange3)
	ports := portSet.Ports()
	c.Assert(ports, gc.HasLen, 3)
}

func (s *PortSetSuite) TestPortSetPortStrings(c *gc.C) {
	portSet := network.NewPortSet(s.portRange3)
	ports := portSet.PortStrings("tcp")
	c.Assert(ports, gc.HasLen, 3)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
)

type Container struct {
	Id         string
	Name       string `json:"name"`
	Dockerfile string `json:"dockerfile"`
	Image      string `json:"image"`
	Run        RunParameters
}

type RunParameters struct {
	Cidfile     string   `json:"cidfile"`
	CpuShares   int      `json:"cpu-shares"`
	Detach      bool     `json:"detach"`
	Dns         []string `json:"dns"`
	Entrypoint  string   `json:"entrypoint"`
	Env         []string `json:"env"`
	Expose      []string `json:"expose"`
	Host        string   `json:"host"`
	Interactive bool     `json:"interactive"`
	Link        []string `json:"link"`
	LxcConf     []string `json:"lxc-conf"`
	Memory      string   `json:"memory"`
	Privileged  bool     `json:"privileged"`
	Publish     []string `json:"publish"`
	PublishAll  bool     `json:"publish-all"`
	Rm          bool     `json:"rm"`
	Tty         bool     `json:"tty"`
	User        string   `json:"user"`
	Volume      []string `json:"volume"`
	VolumesFrom []string `json:"volumes-from"`
	Workdir     string   `json:"workdir"`
	Command     string   `json:"cmd"`
}

func (container *Container) getId() (id string, err error) {
	if len(container.Id) > 0 {
		id = container.Id
	} else {
		// Inspect container, extracting the ID.
		// This will return gibberish if no container is found.
		args := []string{"inspect", "-format={{.ID}}", container.Name}
		output, outErr := commandOutput("docker", args)
		if err == nil {
			id = output
			container.Id = output
		} else {
			err = outErr
		}
	}
	return
}

func (container *Container) exists() bool {
	// `ps -a` returns all existant containers
	id, err := container.getId()
	if err != nil || len(id) == 0 {
		return false
	}
	dockerCmd := []string{"docker", "ps", "-q", "-a", "-notrunc"}
	grepCmd := []string{"grep", "-wF", id}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

func (container *Container) running() bool {
	// `ps` returns all running containers
	id, err := container.getId()
	if err != nil || len(id) == 0 {
		return false
	}
	dockerCmd := []string{"docker", "ps", "-q", "-notrunc"}
	grepCmd := []string{"grep", "-wF", id}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

func (container *Container) imageExists() bool {
	dockerCmd := []string{"docker", "images", "-notrunc"}
	grepCmd := []string{"grep", "-wF", container.Image}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

// Pull image for container
func (container *Container) pullImage() {
	fmt.Printf("Pulling image %s ... ", container.Image)
	args := []string{"pull", container.Image}
	executeCommand("docker", args)
}

// Build image for container
func (container *Container) buildImage() {
	fmt.Printf("Building image %s ... ", container.Image)
	args := []string{"build", "-rm", "-t=" + container.Image, container.Dockerfile}
	executeCommand("docker", args)
}

func (container Container) provision(force bool) {
	if force || !container.imageExists() {
		if len(container.Dockerfile) > 0 {
			container.buildImage()
		} else {
			container.pullImage()
		}
	}
}

// Run or start container
func (container Container) runOrStart() {
	if container.exists() {
		container.start()
	} else {
		container.run()
	}
}

// Run container
func (container Container) run() {
	if container.exists() {
		fmt.Printf(" ! Container %s does already exist. Use --force to recreate.\n", container.Name)
	} else {
		fmt.Printf("Running container %s ... ", container.Name)
		// Assemble command arguments
		args := []string{"run"}
		// Cidfile
		if len(container.Run.Cidfile) > 0 {
			args = append(args, "--cidfile", container.Run.Cidfile)
		}
		// CPU shares
		if container.Run.CpuShares > 0 {
			args = append(args, "--cpu-shares", strconv.Itoa(container.Run.CpuShares))
		}
		// Detach
		if container.Run.Detach {
			args = append(args, "--detach")
		}
		// Dns
		for _, dns := range container.Run.Dns {
			args = append(args, "--dns", dns)
		}
		// Entrypoint
		if len(container.Run.Entrypoint) > 0 {
			args = append(args, "--workdir", container.Run.Entrypoint)
		}
		// Env
		for _, env := range container.Run.Env {
			args = append(args, "--env", env)
		}
		// Expose
		for _, expose := range container.Run.Expose {
			args = append(args, "--expose", expose)
		}
		// Host
		if len(container.Run.Host) > 0 {
			args = append(args, "--host", container.Run.Host)
		}
		// Interactive
		if container.Run.Interactive {
			args = append(args, "--interactive")
		}
		// Link
		for _, link := range container.Run.Link {
			args = append(args, "--link", link)
		}
		// LxcConf
		for _, lxcConf := range container.Run.LxcConf {
			args = append(args, "--lxc-conf", lxcConf)
		}
		// Memory
		if len(container.Run.Memory) > 0 {
			args = append(args, "--memory", container.Run.Memory)
		}
		// Privileged
		if container.Run.Privileged {
			args = append(args, "--privileged")
		}
		// Publish
		for _, port := range container.Run.Publish {
			args = append(args, "--publish", port)
		}
		// PublishAll
		if container.Run.PublishAll {
			args = append(args, "--publish-all")
		}
		// Rm
		if container.Run.Rm {
			args = append(args, "--rm")
		}
		// Tty
		if container.Run.Tty {
			args = append(args, "--tty")
		}
		// User
		if len(container.Run.User) > 0 {
			args = append(args, "--user", container.Run.User)
		}
		// Volumes
		for _, volume := range container.Run.Volume {
			paths := strings.Split(volume, ":")
			if !path.IsAbs(paths[0]) {
				cwd, _ := os.Getwd()
				paths[0] = cwd + "/" + paths[0]
			}
			args = append(args, "--volume", strings.Join(paths, ":"))
		}
		// VolumesFrom
		for _, volumeFrom := range container.Run.VolumesFrom {
			args = append(args, "--volumes-from", volumeFrom)
		}
		// Workdir
		if len(container.Run.Workdir) > 0 {
			args = append(args, "--workdir", container.Run.Workdir)
		}

		// Name
		args = append(args, "--name", container.Name)
		// Image
		args = append(args, container.Image)
		// Command
		if len(container.Run.Command) > 0 {
			args = append(args, container.Run.Command)
		}
		// Execute command
		executeCommand("docker", args)
	}
}

// Start container
func (container Container) start() {
	if container.exists() {
		if !container.running() {
			fmt.Printf("Starting container %s ... ", container.Name)
			args := []string{"start", container.Name}
			executeCommand("docker", args)
		}
	} else {
		fmt.Printf(" ! Container %s does not exist.\n", container.Name)
	}
}

// Kill container
func (container Container) kill() {
	if container.running() {
		fmt.Printf("Killing container %s ... ", container.Name)
		args := []string{"kill", container.Name}
		executeCommand("docker", args)
	}
}

// Stop container
func (container Container) stop() {
	if container.running() {
		fmt.Printf("Stopping container %s ... ", container.Name)
		args := []string{"stop", container.Name}
		executeCommand("docker", args)
	}
}

// Remove container
func (container Container) rm() {
	if container.exists() {
		if container.running() {
			fmt.Printf(" ! Container %s is running and cannot be removed.\n", container.Name)
		} else {
			fmt.Printf("Removing container %s ... ", container.Name)
			args := []string{"rm", container.Name}
			executeCommand("docker", args)
		}
	}
}
<commit_msg>Add note when running provision for existing images<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
)

type Container struct {
	Id         string
	Name       string `json:"name"`
	Dockerfile string `json:"dockerfile"`
	Image      string `json:"image"`
	Run        RunParameters
}

type RunParameters struct {
	Cidfile     string   `json:"cidfile"`
	CpuShares   int      `json:"cpu-shares"`
	Detach      bool     `json:"detach"`
	Dns         []string `json:"dns"`
	Entrypoint  string   `json:"entrypoint"`
	Env         []string `json:"env"`
	Expose      []string `json:"expose"`
	Host        string   `json:"host"`
	Interactive bool     `json:"interactive"`
	Link        []string `json:"link"`
	LxcConf     []string `json:"lxc-conf"`
	Memory      string   `json:"memory"`
	Privileged  bool     `json:"privileged"`
	Publish     []string `json:"publish"`
	PublishAll  bool     `json:"publish-all"`
	Rm          bool     `json:"rm"`
	Tty         bool     `json:"tty"`
	User        string   `json:"user"`
	Volume      []string `json:"volume"`
	VolumesFrom []string `json:"volumes-from"`
	Workdir     string   `json:"workdir"`
	Command     string   `json:"cmd"`
}

func (container *Container) getId() (id string, err error) {
	if len(container.Id) > 0 {
		id = container.Id
	} else {
		// Inspect container, extracting the ID.
		// This will return gibberish if no container is found.
		args := []string{"inspect", "-format={{.ID}}", container.Name}
		output, outErr := commandOutput("docker", args)
		if err == nil {
			id = output
			container.Id = output
		} else {
			err = outErr
		}
	}
	return
}

func (container *Container) exists() bool {
	// `ps -a` returns all existant containers
	id, err := container.getId()
	if err != nil || len(id) == 0 {
		return false
	}
	dockerCmd := []string{"docker", "ps", "-q", "-a", "-notrunc"}
	grepCmd := []string{"grep", "-wF", id}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

func (container *Container) running() bool {
	// `ps` returns all running containers
	id, err := container.getId()
	if err != nil || len(id) == 0 {
		return false
	}
	dockerCmd := []string{"docker", "ps", "-q", "-notrunc"}
	grepCmd := []string{"grep", "-wF", id}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

func (container *Container) imageExists() bool {
	dockerCmd := []string{"docker", "images", "-notrunc"}
	grepCmd := []string{"grep", "-wF", container.Image}
	output, err := pipedCommandOutput(dockerCmd, grepCmd)
	if err != nil {
		return false
	}
	result := string(output)
	if len(result) > 0 {
		return true
	} else {
		return false
	}
}

// Pull image for container
func (container *Container) pullImage() {
	fmt.Printf("Pulling image %s ... ", container.Image)
	args := []string{"pull", container.Image}
	executeCommand("docker", args)
}

// Build image for container
func (container *Container) buildImage() {
	fmt.Printf("Building image %s ... ", container.Image)
	args := []string{"build", "-rm", "-t=" + container.Image, container.Dockerfile}
	executeCommand("docker", args)
}

func (container Container) provision(force bool) {
	if force || !container.imageExists() {
		if len(container.Dockerfile) > 0 {
			container.buildImage()
		} else {
			container.pullImage()
		}
	} else {
		fmt.Printf(" ! Image %s does already exist. Use --force to recreate.\n", container.Image)
	}
}

// Run or start container
func (container Container) runOrStart() {
	if container.exists() {
		container.start()
	} else {
		container.run()
	}
}

// Run container
func (container Container) run() {
	if container.exists() {
		fmt.Printf(" ! Container %s does already exist. Use --force to recreate.\n", container.Name)
	} else {
		fmt.Printf("Running container %s ... ", container.Name)
		// Assemble command arguments
		args := []string{"run"}
		// Cidfile
		if len(container.Run.Cidfile) > 0 {
			args = append(args, "--cidfile", container.Run.Cidfile)
		}
		// CPU shares
		if container.Run.CpuShares > 0 {
			args = append(args, "--cpu-shares", strconv.Itoa(container.Run.CpuShares))
		}
		// Detach
		if container.Run.Detach {
			args = append(args, "--detach")
		}
		// Dns
		for _, dns := range container.Run.Dns {
			args = append(args, "--dns", dns)
		}
		// Entrypoint
		if len(container.Run.Entrypoint) > 0 {
			args = append(args, "--workdir", container.Run.Entrypoint)
		}
		// Env
		for _, env := range container.Run.Env {
			args = append(args, "--env", env)
		}
		// Expose
		for _, expose := range container.Run.Expose {
			args = append(args, "--expose", expose)
		}
		// Host
		if len(container.Run.Host) > 0 {
			args = append(args, "--host", container.Run.Host)
		}
		// Interactive
		if container.Run.Interactive {
			args = append(args, "--interactive")
		}
		// Link
		for _, link := range container.Run.Link {
			args = append(args, "--link", link)
		}
		// LxcConf
		for _, lxcConf := range container.Run.LxcConf {
			args = append(args, "--lxc-conf", lxcConf)
		}
		// Memory
		if len(container.Run.Memory) > 0 {
			args = append(args, "--memory", container.Run.Memory)
		}
		// Privileged
		if container.Run.Privileged {
			args = append(args, "--privileged")
		}
		// Publish
		for _, port := range container.Run.Publish {
			args = append(args, "--publish", port)
		}
		// PublishAll
		if container.Run.PublishAll {
			args = append(args, "--publish-all")
		}
		// Rm
		if container.Run.Rm {
			args = append(args, "--rm")
		}
		// Tty
		if container.Run.Tty {
			args = append(args, "--tty")
		}
		// User
		if len(container.Run.User) > 0 {
			args = append(args, "--user", container.Run.User)
		}
		// Volumes
		for _, volume := range container.Run.Volume {
			paths := strings.Split(volume, ":")
			if !path.IsAbs(paths[0]) {
				cwd, _ := os.Getwd()
				paths[0] = cwd + "/" + paths[0]
			}
			args = append(args, "--volume", strings.Join(paths, ":"))
		}
		// VolumesFrom
		for _, volumeFrom := range container.Run.VolumesFrom {
			args = append(args, "--volumes-from", volumeFrom)
		}
		// Workdir
		if len(container.Run.Workdir) > 0 {
			args = append(args, "--workdir", container.Run.Workdir)
		}

		// Name
		args = append(args, "--name", container.Name)
		// Image
		args = append(args, container.Image)
		// Command
		if len(container.Run.Command) > 0 {
			args = append(args, container.Run.Command)
		}
		// Execute command
		executeCommand("docker", args)
	}
}

// Start container
func (container Container) start() {
	if container.exists() {
		if !container.running() {
			fmt.Printf("Starting container %s ... ", container.Name)
			args := []string{"start", container.Name}
			executeCommand("docker", args)
		}
	} else {
		fmt.Printf(" ! Container %s does not exist.\n", container.Name)
	}
}

// Kill container
func (container Container) kill() {
	if container.running() {
		fmt.Printf("Killing container %s ... ", container.Name)
		args := []string{"kill", container.Name}
		executeCommand("docker", args)
	}
}

// Stop container
func (container Container) stop() {
	if container.running() {
		fmt.Printf("Stopping container %s ... ", container.Name)
		args := []string{"stop", container.Name}
		executeCommand("docker", args)
	}
}

// Remove container
func (container Container) rm() {
	if container.exists() {
		if container.running() {
			fmt.Printf(" ! Container %s is running and cannot be removed.\n", container.Name)
		} else {
			fmt.Printf("Removing container %s ... ", container.Name)
			args := []string{"rm", container.Name}
			executeCommand("docker", args)
		}
	}
}
<|endoftext|>


<commit_before>/*
Package contextio provides a simple way to sign API requests for http://Context.IO.

The simplest usage is to use DoJSON() to return a json byte array that you can use elsewhere in your code.
For more advanced usage, you can use Do() and parse through the http.Response struct yourself. It is not
specific to an API version, so you can use it to make any request you would make through http://console.Context.IO.
*/
package contextio

import (
	"bytes"
	"flag"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/garyburd/go-oauth/oauth"
)

// ContextIO is a struct containing the authentication information and a pointer to the oauth client
type ContextIO struct {
	key    string
	secret string
	client *oauth.Client
}

// NewContextIO returns a ContextIO struct based on your CIO User and Secret
func NewContextIO(key, secret string) *ContextIO {
	c := &oauth.Client{
		Credentials: oauth.Credentials{
			Token:  key,
			Secret: secret,
		},
	}

	return &ContextIO{
		key:    key,
		secret: secret,
		client: c,
	}
}

var apiHost = flag.String("apiHost", "api.context.io", "Use a specific host for the API")

// Do signs the request and returns an *http.Response. The body is a standard response.
// Body and must have defer response.Body.close().
// This is 2 legged authentication, and will not currently work with 3 legged authentication.
func (c *ContextIO) Do(method, q string, params url.Values, body *string) (response *http.Response, err error) {
	// make sure q has a slash in front of it
	if q[0:1] != "/" {
		q = "/" + q
	}

	req, _ := http.NewRequest(method, "https://"+*apiHost+q, bytes.NewBufferString(*body))
	req.URL.Opaque = q
	req.Header.Set("User-Agent", "GoContextIO Simple Library v. 0.1")
	v := url.Values{}
	switch method {
	case "PUT", "POST", "DELETE":
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		v, err = url.ParseQuery(*body)
		if err != nil {
			return
		}
	}

	err = c.client.SetAuthorizationHeader(req.Header, nil, req.Method, req.URL, v)
	if err != nil {
		return
	}
	return http.DefaultClient.Do(req)
}

// DoJSON passes the request to Do and then returns the json in a []byte array
func (c *ContextIO) DoJSON(method, q string, params url.Values, body *string) (json []byte, err error) {
	response, err := c.Do(method, q, params, body)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	json, err = ioutil.ReadAll(response.Body)
	return json, err
}
<commit_msg>forgot to handle query params<commit_after>/*
Package contextio provides a simple way to sign API requests for http://Context.IO.

The simplest usage is to use DoJSON() to return a json byte array that you can use elsewhere in your code.
For more advanced usage, you can use Do() and parse through the http.Response struct yourself. It is not
specific to an API version, so you can use it to make any request you would make through http://console.Context.IO.
*/
package contextio

import (
	"bytes"
	"flag"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/garyburd/go-oauth/oauth"
)

// ContextIO is a struct containing the authentication information and a pointer to the oauth client
type ContextIO struct {
	key    string
	secret string
	client *oauth.Client
}

// NewContextIO returns a ContextIO struct based on your CIO User and Secret
func NewContextIO(key, secret string) *ContextIO {
	c := &oauth.Client{
		Credentials: oauth.Credentials{
			Token:  key,
			Secret: secret,
		},
	}

	return &ContextIO{
		key:    key,
		secret: secret,
		client: c,
	}
}

var apiHost = flag.String("apiHost", "api.context.io", "Use a specific host for the API")

// Do signs the request and returns an *http.Response. The body is a standard response.
// Body and must have defer response.Body.close().
// This is 2 legged authentication, and will not currently work with 3 legged authentication.
func (c *ContextIO) Do(method, q string, params url.Values, body *string) (response *http.Response, err error) {
	// make sure q has a slash in front of it
	if q[0:1] != "/" {
		q = "/" + q
	}

	query := *apiHost + q
	if len(params) > 0 {
		query = query + "?" + params.Encode()
	}
	req, _ := http.NewRequest(method, "https://"+query, bytes.NewBufferString(*body))
	req.URL.Opaque = q
	req.Header.Set("User-Agent", "GoContextIO Simple Library v. 0.1")
	v := url.Values{}
	switch method {
	case "PUT", "POST", "DELETE":
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		v, err = url.ParseQuery(*body)
		if err != nil {
			return
		}
	}

	err = c.client.SetAuthorizationHeader(req.Header, nil, req.Method, req.URL, v)
	if err != nil {
		return
	}
	return http.DefaultClient.Do(req)
}

// DoJSON passes the request to Do and then returns the json in a []byte array
func (c *ContextIO) DoJSON(method, q string, params url.Values, body *string) (json []byte, err error) {
	response, err := c.Do(method, q, params, body)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	json, err = ioutil.ReadAll(response.Body)
	return json, err
}
<|endoftext|>