<commit_before>package builder

import (
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/kballard/go-shellquote"
	log "github.com/sirupsen/logrus"
	"mynewt.apache.org/newt/newt/stage"
	"mynewt.apache.org/newt/util"
)

// replaceArtifactsIfChanged compares the artifacts just produced (temp
// directory) to those from the previous build (user bin directory).  If they
// are different, it replaces the old with the new so that they get relinked
// during this build.
func replaceArtifactsIfChanged(oldDir string, newDir string) error {
	eq, err := util.DirsAreEqual(oldDir, newDir)
	if err != nil {
		return err
	}

	if eq {
		// No changes detected.
		return nil
	}

	log.Debugf("changes detected; replacing %s with %s", oldDir, newDir)
	os.RemoveAll(oldDir)
	if err := os.Rename(newDir, oldDir); err != nil {
		return util.ChildNewtError(err)
	}

	return nil
}

// createTempUserDirs creates a set of temporary directories for holding build
// inputs.  It returns:
//     * base-dir
//     * src-dir
//     * include-dir
func createTempUserDirs(label string) (string, string, string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user-"+label)
	if err != nil {
		return "", "", "", util.ChildNewtError(err)
	}
	log.Debugf("created user %s dir: %s", label, tmpDir)

	tmpSrcDir := UserTempSrcDir(tmpDir)
	log.Debugf("creating user %s src dir: %s", label, tmpSrcDir)
	if err := os.MkdirAll(tmpSrcDir, 0755); err != nil {
		os.RemoveAll(tmpDir)
		return "", "", "", util.ChildNewtError(err)
	}

	tmpIncDir := UserTempIncludeDir(tmpDir)
	log.Debugf("creating user %s include dir: %s", label, tmpIncDir)
	if err := os.MkdirAll(tmpIncDir, 0755); err != nil {
		os.RemoveAll(tmpDir)
		return "", "", "", util.ChildNewtError(err)
	}

	return tmpDir, tmpSrcDir, tmpIncDir, nil
}

// envVarsForCmd calculates the set of environment variables to export for the
// specified external command.
func (t *TargetBuilder) envVarsForCmd(sf stage.StageFunc, userSrcDir string,
	userIncDir string, workDir string) (map[string]string, error) {

	// Determine whether the owning package is part of the loader or the app.
	slot := 0
	buildName := "app"

	if t.LoaderBuilder != nil {
		rpkg := t.res.LpkgRpkgMap[sf.Pkg]
		if rpkg == nil {
			return nil, util.FmtNewtError(
				"resolution missing expected package: %s", sf.Pkg.FullName())
		}

		if t.LoaderBuilder.PkgMap[rpkg] != nil {
			buildName = "loader"
		} else {
			slot = 1
		}
	}

	env, err := t.AppBuilder.EnvVars(slot)
	if err != nil {
		return nil, err
	}

	p := UserEnvParams{
		Lpkg:       sf.Pkg,
		TargetName: t.target.FullName(),
		AppName:    t.appPkg.FullName(),
		BuildName:  buildName,
		UserSrcDir: userSrcDir,
		UserIncDir: userIncDir,
		WorkDir:    workDir,
	}
	uenv := UserEnvVars(p)

	for k, v := range uenv {
		env[k] = v
	}

	return env, nil
}

// execExtCmds executes a set of user scripts.
func (t *TargetBuilder) execExtCmds(sf stage.StageFunc, userSrcDir string,
	userIncDir string, workDir string) error {

	env, err := t.envVarsForCmd(sf, userSrcDir, userIncDir, workDir)
	if err != nil {
		return err
	}

	envs := EnvVarsToSlice(env)
	toks, err := shellquote.Split(sf.Name)
	if err != nil {
		return util.FmtNewtError(
			"invalid command string: \"%s\": %s", sf.Name, err.Error())
	}

	// If the command is in the user's PATH, expand it to its real location.
	cmd, err := exec.LookPath(toks[0])
	if err == nil {
		toks[0] = cmd
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Executing %s\n", sf.Name)
	if err := util.ShellInteractiveCommand(toks, envs, true); err != nil {
		return err
	}

	return nil
}

// execPreBuildCmds runs the target's set of pre-build user commands.  It is an
// error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPreBuildCmds(workDir string) error {
	// Create temporary directories where scripts can put build inputs.
	tmpDir, tmpSrcDir, tmpIncDir, err := createTempUserDirs("pre-build")
	if err != nil {
		return err
	}
	defer func() {
		log.Debugf("removing user pre-build dir: %s", tmpDir)
		os.RemoveAll(tmpDir)
	}()

	for _, sf := range t.res.PreBuildCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, tmpSrcDir, tmpIncDir, workDir); err != nil {
			return err
		}
	}

	srcDir := UserPreBuildSrcDir(t.target.FullName())
	if err := replaceArtifactsIfChanged(srcDir, tmpSrcDir); err != nil {
		return err
	}

	incDir := UserPreBuildIncludeDir(t.target.FullName())
	if err := replaceArtifactsIfChanged(incDir, tmpIncDir); err != nil {
		return err
	}

	return nil
}

// execPreLinkCmds runs the target's set of post-build user commands.  It is
// an error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPreLinkCmds(workDir string) error {
	// Create temporary directories where scripts can put build inputs.
	tmpDir, tmpSrcDir, _, err := createTempUserDirs("pre-link")
	if err != nil {
		return err
	}
	defer func() {
		log.Debugf("removing user pre-link dir: %s", tmpDir)
		os.RemoveAll(tmpDir)
	}()

	for _, sf := range t.res.PreLinkCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, tmpSrcDir, "", workDir); err != nil {
			return err
		}
	}

	srcDir := UserPreLinkSrcDir(t.target.FullName())
	err = replaceArtifactsIfChanged(srcDir, tmpSrcDir)
	if err != nil {
		return err
	}

	return nil
}

// execPostLinkCmds runs the target's set of post-build user commands.  It is
// an error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPostLinkCmds(workDir string) error {
	for _, sf := range t.res.PostLinkCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, "", "", workDir); err != nil {
			return err
		}
	}

	return nil
}

// makeUserDir creates a temporary directory where scripts can put build
// inputs.
func makeUserDir() (string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user")
	if err != nil {
		return "", util.ChildNewtError(err)
	}
	log.Debugf("created user dir: %s", tmpDir)

	return tmpDir, nil
}

func makeUserWorkDir() (string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user-work")
	if err != nil {
		return "", util.ChildNewtError(err)
	}
	log.Debugf("created user work dir: %s", tmpDir)

	return tmpDir, nil
}
<commit_msg>Execute custom commands from pkg directory<commit_after>package builder

import (
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/kballard/go-shellquote"
	log "github.com/sirupsen/logrus"
	"mynewt.apache.org/newt/newt/stage"
	"mynewt.apache.org/newt/util"
)

// replaceArtifactsIfChanged compares the artifacts just produced (temp
// directory) to those from the previous build (user bin directory).  If they
// are different, it replaces the old with the new so that they get relinked
// during this build.
func replaceArtifactsIfChanged(oldDir string, newDir string) error {
	eq, err := util.DirsAreEqual(oldDir, newDir)
	if err != nil {
		return err
	}

	if eq {
		// No changes detected.
		return nil
	}

	log.Debugf("changes detected; replacing %s with %s", oldDir, newDir)
	os.RemoveAll(oldDir)
	if err := os.Rename(newDir, oldDir); err != nil {
		return util.ChildNewtError(err)
	}

	return nil
}

// createTempUserDirs creates a set of temporary directories for holding build
// inputs.  It returns:
//     * base-dir
//     * src-dir
//     * include-dir
func createTempUserDirs(label string) (string, string, string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user-"+label)
	if err != nil {
		return "", "", "", util.ChildNewtError(err)
	}
	log.Debugf("created user %s dir: %s", label, tmpDir)

	tmpSrcDir := UserTempSrcDir(tmpDir)
	log.Debugf("creating user %s src dir: %s", label, tmpSrcDir)
	if err := os.MkdirAll(tmpSrcDir, 0755); err != nil {
		os.RemoveAll(tmpDir)
		return "", "", "", util.ChildNewtError(err)
	}

	tmpIncDir := UserTempIncludeDir(tmpDir)
	log.Debugf("creating user %s include dir: %s", label, tmpIncDir)
	if err := os.MkdirAll(tmpIncDir, 0755); err != nil {
		os.RemoveAll(tmpDir)
		return "", "", "", util.ChildNewtError(err)
	}

	return tmpDir, tmpSrcDir, tmpIncDir, nil
}

// envVarsForCmd calculates the set of environment variables to export for the
// specified external command.
func (t *TargetBuilder) envVarsForCmd(sf stage.StageFunc, userSrcDir string,
	userIncDir string, workDir string) (map[string]string, error) {

	// Determine whether the owning package is part of the loader or the app.
	slot := 0
	buildName := "app"

	if t.LoaderBuilder != nil {
		rpkg := t.res.LpkgRpkgMap[sf.Pkg]
		if rpkg == nil {
			return nil, util.FmtNewtError(
				"resolution missing expected package: %s", sf.Pkg.FullName())
		}

		if t.LoaderBuilder.PkgMap[rpkg] != nil {
			buildName = "loader"
		} else {
			slot = 1
		}
	}

	env, err := t.AppBuilder.EnvVars(slot)
	if err != nil {
		return nil, err
	}

	p := UserEnvParams{
		Lpkg:       sf.Pkg,
		TargetName: t.target.FullName(),
		AppName:    t.appPkg.FullName(),
		BuildName:  buildName,
		UserSrcDir: userSrcDir,
		UserIncDir: userIncDir,
		WorkDir:    workDir,
	}
	uenv := UserEnvVars(p)

	for k, v := range uenv {
		env[k] = v
	}

	return env, nil
}

// execExtCmds executes a set of user scripts.
func (t *TargetBuilder) execExtCmds(sf stage.StageFunc, userSrcDir string,
	userIncDir string, workDir string) error {

	env, err := t.envVarsForCmd(sf, userSrcDir, userIncDir, workDir)
	if err != nil {
		return err
	}

	envs := EnvVarsToSlice(env)
	toks, err := shellquote.Split(sf.Name)
	if err != nil {
		return util.FmtNewtError(
			"invalid command string: \"%s\": %s", sf.Name, err.Error())
	}

	// If the command is in the user's PATH, expand it to its real location.
	cmd, err := exec.LookPath(toks[0])
	if err == nil {
		toks[0] = cmd
	}

	// Execute the commands from the package's directory.
	pwd, err := os.Getwd()
	if err != nil {
		return util.ChildNewtError(err)
	}
	if err := os.Chdir(sf.Pkg.BasePath()); err != nil {
		return util.ChildNewtError(err)
	}
	defer os.Chdir(pwd)

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Executing %s\n", sf.Name)
	if err := util.ShellInteractiveCommand(toks, envs, true); err != nil {
		return err
	}

	return nil
}

// execPreBuildCmds runs the target's set of pre-build user commands.  It is an
// error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPreBuildCmds(workDir string) error {
	// Create temporary directories where scripts can put build inputs.
	tmpDir, tmpSrcDir, tmpIncDir, err := createTempUserDirs("pre-build")
	if err != nil {
		return err
	}
	defer func() {
		log.Debugf("removing user pre-build dir: %s", tmpDir)
		os.RemoveAll(tmpDir)
	}()

	for _, sf := range t.res.PreBuildCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, tmpSrcDir, tmpIncDir, workDir); err != nil {
			return err
		}
	}

	srcDir := UserPreBuildSrcDir(t.target.FullName())
	if err := replaceArtifactsIfChanged(srcDir, tmpSrcDir); err != nil {
		return err
	}

	incDir := UserPreBuildIncludeDir(t.target.FullName())
	if err := replaceArtifactsIfChanged(incDir, tmpIncDir); err != nil {
		return err
	}

	return nil
}

// execPreLinkCmds runs the target's set of post-build user commands.  It is
// an error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPreLinkCmds(workDir string) error {
	// Create temporary directories where scripts can put build inputs.
	tmpDir, tmpSrcDir, _, err := createTempUserDirs("pre-link")
	if err != nil {
		return err
	}
	defer func() {
		log.Debugf("removing user pre-link dir: %s", tmpDir)
		os.RemoveAll(tmpDir)
	}()

	for _, sf := range t.res.PreLinkCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, tmpSrcDir, "", workDir); err != nil {
			return err
		}
	}

	srcDir := UserPreLinkSrcDir(t.target.FullName())
	err = replaceArtifactsIfChanged(srcDir, tmpSrcDir)
	if err != nil {
		return err
	}

	return nil
}

// execPostLinkCmds runs the target's set of post-build user commands.  It is
// an error if any command fails (exits with a nonzero status).
func (t *TargetBuilder) execPostLinkCmds(workDir string) error {
	for _, sf := range t.res.PostLinkCmdCfg.StageFuncs {
		if err := t.execExtCmds(sf, "", "", workDir); err != nil {
			return err
		}
	}

	return nil
}

// makeUserDir creates a temporary directory where scripts can put build
// inputs.
func makeUserDir() (string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user")
	if err != nil {
		return "", util.ChildNewtError(err)
	}
	log.Debugf("created user dir: %s", tmpDir)

	return tmpDir, nil
}

func makeUserWorkDir() (string, error) {
	tmpDir, err := ioutil.TempDir("", "mynewt-user-work")
	if err != nil {
		return "", util.ChildNewtError(err)
	}
	log.Debugf("created user work dir: %s", tmpDir)

	return tmpDir, nil
}
<|endoftext|>


<commit_before><commit_msg>ms_action_api Removed Issues already fixed<commit_after><|endoftext|>


<commit_before><commit_msg>log level<commit_after><|endoftext|>


<commit_before>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/shared/api"
)

// Internal copy of the instance interface.
type instance interface {
	Name() string
	Project() string
	Operation() *operations.Operation
}

// InstanceAction represents a lifecycle event action for instances.
type InstanceAction string

// All supported lifecycle events for instances.
const (
	InstanceCreated          = InstanceAction("created")
	InstanceStarted          = InstanceAction("started")
	InstanceStopped          = InstanceAction("stopped")
	InstanceShutdown         = InstanceAction("shutdown")
	InstanceRestarted        = InstanceAction("restarted")
	InstancePaused           = InstanceAction("paused")
	InstanceResumed          = InstanceAction("resumed")
	InstanceRestored         = InstanceAction("restored")
	InstanceDeleted          = InstanceAction("deleted")
	InstanceRenamed          = InstanceAction("renamed")
	InstanceUpdated          = InstanceAction("updated")
	InstanceExec             = InstanceAction("exec")
	InstanceConsole          = InstanceAction("console")
	InstanceConsoleRetrieved = InstanceAction("console-retrieved")
	InstanceConsoleReset     = InstanceAction("console-reset")
	InstanceFileRetrieved    = InstanceAction("file-retrieved")
	InstanceFilePushed       = InstanceAction("file-pushed")
	InstanceFileDeleted      = InstanceAction("file-deleted")
)

// Event creates the lifecycle event for an action on an instance.
func (a InstanceAction) Event(inst instance, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("instance-%s", a)
	u := fmt.Sprintf("/1.0/instances/%s", url.PathEscape(inst.Name()))

	if inst.Project() != project.Default {
		u = fmt.Sprintf("%s?project=%s", u, url.QueryEscape(inst.Project()))
	}

	var requestor *api.EventLifecycleRequestor
	if inst.Operation() != nil {
		requestor = inst.Operation().Requestor()
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<commit_msg>lxd/lifecycle/instance: Use URL builder in Event<commit_after>package lifecycle

import (
	"fmt"

	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

// Internal copy of the instance interface.
type instance interface {
	Name() string
	Project() string
	Operation() *operations.Operation
}

// InstanceAction represents a lifecycle event action for instances.
type InstanceAction string

// All supported lifecycle events for instances.
const (
	InstanceCreated          = InstanceAction("created")
	InstanceStarted          = InstanceAction("started")
	InstanceStopped          = InstanceAction("stopped")
	InstanceShutdown         = InstanceAction("shutdown")
	InstanceRestarted        = InstanceAction("restarted")
	InstancePaused           = InstanceAction("paused")
	InstanceResumed          = InstanceAction("resumed")
	InstanceRestored         = InstanceAction("restored")
	InstanceDeleted          = InstanceAction("deleted")
	InstanceRenamed          = InstanceAction("renamed")
	InstanceUpdated          = InstanceAction("updated")
	InstanceExec             = InstanceAction("exec")
	InstanceConsole          = InstanceAction("console")
	InstanceConsoleRetrieved = InstanceAction("console-retrieved")
	InstanceConsoleReset     = InstanceAction("console-reset")
	InstanceFileRetrieved    = InstanceAction("file-retrieved")
	InstanceFilePushed       = InstanceAction("file-pushed")
	InstanceFileDeleted      = InstanceAction("file-deleted")
)

// Event creates the lifecycle event for an action on an instance.
func (a InstanceAction) Event(inst instance, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("instance-%s", a)
	url := api.NewURL().Path(version.APIVersion, "instances", inst.Name()).Project(inst.Project())

	var requestor *api.EventLifecycleRequestor
	if inst.Operation() != nil {
		requestor = inst.Operation().Requestor()
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    url.String(),
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This LevelDB Go implementation is based on LevelDB C++ implementation.
// Which contains the following header:
//   Copyright (c) 2011 The LevelDB Authors. All rights reserved.
//   Use of this source code is governed by a BSD-style license that can be
//   found in the LEVELDBCPP_LICENSE file. See the LEVELDBCPP_AUTHORS file
//   for names of contributors.

package db

import (
	"bytes"
	"testing"
)

func TestBatch(t *testing.T) {
	b1 := new(Batch)
	b1.sequence = 10009
	b1.Put([]byte("key1"), []byte("value1"))
	b1.Put([]byte("key2"), []byte("value2"))
	b1.Delete([]byte("key1"))
	b1.Put([]byte("k"), []byte(""))
	b1.Put([]byte("zzzzzzzzzzz"), []byte("zzzzzzzzzzzzzzzzzzzzzzzz"))
	b1.Delete([]byte("key10000"))
	b1.Delete([]byte("k"))
	buf := b1.encode()
	b2 := new(Batch)
	var n uint32
	err := decodeBatchHeader(buf, &b2.sequence, &n)
	if err != nil {
		t.Error("error when decoding batch header: ", err)
	}
	if b1.sequence != b2.sequence {
		t.Errorf("invalid sequence number want %d, got %d", b1.sequence, b2.sequence)
	}
	if len(b1.rec) != int(n) {
		t.Errorf("invalid record length (in header) want %d, got %d", len(b1.rec), n)
	}
	n2, err := replayBatch(buf, b2)
	if err != nil {
		t.Error("error when replaying batch header: ", err)
	}
	if uint64(n) != n2-b2.sequence {
		t.Errorf("invalid record length (replayBatch ret) want %d, got %d", n, n2-b2.sequence)
	}
	if len(b1.rec) != len(b2.rec) {
		t.Errorf("invalid record length want %d, got %d", len(b1.rec), len(b2.rec))
		return
	}
	for i := range b1.rec {
		r1, r2 := &(b1.rec[i]), &(b2.rec[i])
		if r1.t != r2.t {
			t.Errorf("invalid type on record '%d' want %d, got %d", i, r1.t, r2.t)
		}
		if !bytes.Equal(r1.key, r2.key) {
			t.Errorf("invalid key on record '%d' want %s, got %s", i, string(r1.key), string(r2.key))
		}
		if r1.t == tVal {
			if !bytes.Equal(r1.value, r2.value) {
				t.Errorf("invalid value on record '%d' want %s, got %s", i, string(r1.value), string(r2.value))
			}
		}
	}
}
<commit_msg>db: fix typo<commit_after>// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This LevelDB Go implementation is based on LevelDB C++ implementation.
// Which contains the following header:
//   Copyright (c) 2011 The LevelDB Authors. All rights reserved.
//   Use of this source code is governed by a BSD-style license that can be
//   found in the LEVELDBCPP_LICENSE file. See the LEVELDBCPP_AUTHORS file
//   for names of contributors.

package db

import (
	"bytes"
	"testing"
)

func TestBatch(t *testing.T) {
	b1 := new(Batch)
	b1.sequence = 10009
	b1.Put([]byte("key1"), []byte("value1"))
	b1.Put([]byte("key2"), []byte("value2"))
	b1.Delete([]byte("key1"))
	b1.Put([]byte("k"), []byte(""))
	b1.Put([]byte("zzzzzzzzzzz"), []byte("zzzzzzzzzzzzzzzzzzzzzzzz"))
	b1.Delete([]byte("key10000"))
	b1.Delete([]byte("k"))
	buf := b1.encode()
	b2 := new(Batch)
	var n uint32
	err := decodeBatchHeader(buf, &b2.sequence, &n)
	if err != nil {
		t.Error("error when decoding batch header: ", err)
	}
	if b1.sequence != b2.sequence {
		t.Errorf("invalid sequence number want %d, got %d", b1.sequence, b2.sequence)
	}
	if len(b1.rec) != int(n) {
		t.Errorf("invalid record length (in header) want %d, got %d", len(b1.rec), n)
	}
	n2, err := replayBatch(buf, b2)
	if err != nil {
		t.Error("error when replaying batch: ", err)
	}
	if uint64(n) != n2-b2.sequence {
		t.Errorf("invalid record length (replayBatch ret) want %d, got %d", n, n2-b2.sequence)
	}
	if len(b1.rec) != len(b2.rec) {
		t.Errorf("invalid record length want %d, got %d", len(b1.rec), len(b2.rec))
		return
	}
	for i := range b1.rec {
		r1, r2 := &(b1.rec[i]), &(b2.rec[i])
		if r1.t != r2.t {
			t.Errorf("invalid type on record '%d' want %d, got %d", i, r1.t, r2.t)
		}
		if !bytes.Equal(r1.key, r2.key) {
			t.Errorf("invalid key on record '%d' want %s, got %s", i, string(r1.key), string(r2.key))
		}
		if r1.t == tVal {
			if !bytes.Equal(r1.value, r2.value) {
				t.Errorf("invalid value on record '%d' want %s, got %s", i, string(r1.value), string(r2.value))
			}
		}
	}
}
<|endoftext|>


<commit_before>package websocketApi

import (
	"encoding/json"
	"strings"
	"sync"
	"time"
	"errors"

	"github.com/apex/log"

	"golang.org/x/net/websocket"
	"github.com/jxc6698/bitcoin-exchange-api/bitmex"
)

const wsURL = "wss://www.bitmex.com/realtime"

//WS - websocket connection object
type WS struct {
	sync.Mutex
	conn       *websocket.Conn
	log        *log.Logger
	nonce      int64
	key        string
	secret     string
	chTrade    map[chan WSTrade][]bitmex.Contracts
	chQuote    map[chan WSQuote][]bitmex.Contracts
	chOrder    map[chan WSOrder][]bitmex.Contracts
	chPosition map[chan WSPosition][]bitmex.Contracts
	chWallet   chan bitmex.WSWallet
	chSucc     map[string][]chan struct{}

	chStart    chan int64
}

//NewWS - creates new websocket object
func NewWS() *WS {
	return &WS{
		nonce:      time.Now().Unix(),
		chTrade:    make(map[chan WSTrade][]bitmex.Contracts, 0),
		chQuote:    make(map[chan WSQuote][]bitmex.Contracts, 0),
		chOrder:    make(map[chan WSOrder][]bitmex.Contracts, 0),
		chPosition: make(map[chan WSPosition][]bitmex.Contracts, 0),
		chSucc:     make(map[string][]chan struct{}, 0),
	}
}

//Connect - connects
func (ws *WS) Connect() error {
	conn, err := websocket.Dial(wsURL, "", "http://localhost/")

	if err != nil {
		return err
	}

	log.Info("Connected")

	ws.conn = conn

	go ws.read()

	return nil
}

//Disconnect - Disconnects from websocket
func (ws *WS) Disconnect() error {
	log.Info("Disconnecting")
	//TODO Close all channels
	return ws.conn.Close()
}

func (ws *WS) read() {
	for {
		var msg string
		websocket.Message.Receive(ws.conn, &msg)

		log.Debugf("Raw: %v", msg)

		switch {
		case strings.HasPrefix(msg, `{"success"`):
			var success wsSuccess
			json.Unmarshal([]byte(msg), &success)
			log.Debugf("Success: %#v", success)

			if channels, found := ws.chSucc[success.Request["op"]]; found {
				for _, ch := range channels {
					select {
					case ch <- struct{}{}:
					default:
					}
				}
			}

			if channels, found := ws.chSucc[success.Request["args"]]; found {
				for _, ch := range channels {
					select {
					case ch <- struct{}{}:
					default:
					}
				}
			}

		case strings.HasPrefix(msg, `{"info"`):
			var info wsInfo
			json.Unmarshal([]byte(msg), &info)
			log.Infof("Info: %v", info)

		case strings.Contains(msg, `{"table"`):
			var table wsData
			json.Unmarshal([]byte(msg), &table)
			log.Debugf("Table: %#v", table)

			switch table.Table {

			case "trade":
				var trades []WSTrade
				json.Unmarshal(table.Data, &trades)

				log.Debugf("Trades: %#v", trades)

				for _, one := range trades {
					ws.trade(one)
				}

			case "quote":
				var quotes []WSQuote
				json.Unmarshal(table.Data, &quotes)

				log.Debugf("Quotes: %#v", quotes)

				for _, one := range quotes {
					ws.quote(one)
				}

			case "order":
				var orders []WSOrder
				json.Unmarshal(table.Data, &orders)

				log.Debugf("Orders: %#v", orders)

				for _, one := range orders {
					ws.order(one)
				}

			case "position":
				var positions []WSPosition
				json.Unmarshal(table.Data, &positions)

				log.Debugf("Positions: %#v", positions)

				for _, one := range positions {
					ws.position(one)
				}

			case "wallet":
				var wallets []bitmex.WSWallet
				json.Unmarshal(table.Data, &wallets)

				for _, one := range wallets {
					ws.wallet(one)
				}

			default:
				log.Infof("%v", msg)
			}

		default:
			log.Infof("%v", msg)
			log.Info("unknown WS message")
			if nil == ws.chStart {
				ws.fatal(errors.New("Unset restart channel"))
			} else {
				log.Info("restart")
				if len(ws.chStart) == 0 {
					ws.chStart <- 1
				}
			}
		}
	}
}

func (ws *WS) sendTrade(ch chan WSTrade, trade WSTrade) {
	select {
	case ch <- trade:
		log.Debugf("Trade sent: %#v - %#v", ch, trade)
	default:
		log.Debugf("Trade channel busy: %#v", ch)
	}
}

func (ws *WS) sendOrder(ch chan WSOrder, order WSOrder) {
	select {
	case ch <- order:
		log.Debugf("Order sent: %#v - %#v", ch, order)
	default:
		log.Debugf("Order channel busy: %#v", ch)
	}
}

func (ws *WS) sendQuote(ch chan WSQuote, quote WSQuote) {
	select {
	case ch <- quote:
		log.Debugf("Quote sent: %#v - %#v", ch, quote)
	default:
		log.Debugf("Quote channel busy: %#v", ch)
	}
}

func (ws *WS) sendPosition(ch chan WSPosition, position WSPosition) {
	select {
	case ch <- position:
		log.Debugf("Position sent: %#v - %#v", ch, position)
	default:
		log.Debugf("Position channel busy: %#v", ch)
	}
}

func (ws *WS) sendWallet(ch chan bitmex.WSWallet, wallet bitmex.WSWallet) {
	select {
	case ch <- wallet:
		log.Debugf("Wallet sent: %#v - %#v", ch, wallet)
	default:
		log.Debugf("Wallet channel busy: %#v", ch)
	}
}

func (ws *WS) trade(trade WSTrade) {
	for ch, symbols := range ws.chTrade {
		if len(symbols) == 0 {
			ws.sendTrade(ch, trade)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(trade.Symbol) {
				ws.sendTrade(ch, trade)
			}
		}
	}
}

func (ws *WS) order(order WSOrder) {
	for ch, symbols := range ws.chOrder {
		if len(symbols) == 0 {
			ws.sendOrder(ch, order)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(order.Symbol) {
				ws.sendOrder(ch, order)
			}
		}
	}
}

func (ws *WS) position(position WSPosition) {
	for ch, symbols := range ws.chPosition {
		if len(symbols) == 0 {
			ws.sendPosition(ch, position)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(position.Symbol) {
				ws.sendPosition(ch, position)
			}
		}
	}
}

func (ws *WS) quote(quote WSQuote) {
	for ch, symbols := range ws.chQuote {
		if len(symbols) == 0 {
			ws.sendQuote(ch, quote)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(quote.Symbol) {
				ws.sendQuote(ch, quote)
			}
		}
	}
}

func (ws *WS) wallet(wallet bitmex.WSWallet) {
	ws.sendWallet(ws.chWallet, wallet)
}

func (ws *WS) send(msg string) {
	defer ws.Unlock()

	log.Debugf("Writing WS: %#v", string(msg))
	ws.Lock()

	if _, err := ws.conn.Write([]byte(msg)); err != nil {
		ws.fatal(err)
	}
}

func (ws *WS) fatal(err error) {
	ws.Disconnect()
	log.Fatalf("%v", err.Error())
}

//SubTrade - subscribes channel to trades
func (ws *WS) SubTrade(ch chan WSTrade, contracts []bitmex.Contracts) {
	ws.Lock()

	if _, ok := ws.chTrade[ch]; !ok {
		ws.chTrade[ch] = contracts
	} else {
		ws.chTrade[ch] = append(ws.chTrade[ch], contracts...)
	}

	ws.Unlock()

	for _, one := range contracts {
		ws.send(`{"op": "subscribe", "args": "trade:` + string(one) + `"}`)
	}
}

//SubQuote - subscribes to quotes
func (ws *WS) SubQuote(ch chan WSQuote, contracts []bitmex.Contracts) {

	ws.Lock()

	if _, ok := ws.chQuote[ch]; !ok {
		ws.chQuote[ch] = contracts
	} else {
		ws.chQuote[ch] = append(ws.chQuote[ch], contracts...)
	}

	ws.Unlock()

	for _, one := range contracts {
		ws.send(`{"op": "subscribe", "args": "quote:` + string(one) + `"}`)
	}
}

func (ws *WS) RegisterReStart(ch chan int64) {
	ws.chStart = ch
}<commit_msg>FIX BUG: when receive unknown WS message: 	stop the for loop for receviing message, disconnect the ws 	connection and return beyond the Read() function<commit_after>package websocketApi

import (
	"encoding/json"
	"strings"
	"sync"
	"time"
	"errors"

	"github.com/apex/log"

	"golang.org/x/net/websocket"
	"github.com/jxc6698/bitcoin-exchange-api/bitmex"
)

const wsURL = "wss://www.bitmex.com/realtime"

//WS - websocket connection object
type WS struct {
	sync.Mutex
	conn       *websocket.Conn
	log        *log.Logger
	nonce      int64
	key        string
	secret     string
	chTrade    map[chan WSTrade][]bitmex.Contracts
	chQuote    map[chan WSQuote][]bitmex.Contracts
	chOrder    map[chan WSOrder][]bitmex.Contracts
	chPosition map[chan WSPosition][]bitmex.Contracts
	chWallet   chan bitmex.WSWallet
	chSucc     map[string][]chan struct{}

	chStart    chan int64
}

//NewWS - creates new websocket object
func NewWS() *WS {
	return &WS{
		nonce:      time.Now().Unix(),
		chTrade:    make(map[chan WSTrade][]bitmex.Contracts, 0),
		chQuote:    make(map[chan WSQuote][]bitmex.Contracts, 0),
		chOrder:    make(map[chan WSOrder][]bitmex.Contracts, 0),
		chPosition: make(map[chan WSPosition][]bitmex.Contracts, 0),
		chSucc:     make(map[string][]chan struct{}, 0),
	}
}

//Connect - connects
func (ws *WS) Connect() error {
	conn, err := websocket.Dial(wsURL, "", "http://localhost/")

	if err != nil {
		return err
	}

	log.Info("Connected")

	ws.conn = conn

	go ws.read()

	return nil
}

//Disconnect - Disconnects from websocket
func (ws *WS) Disconnect() error {
	log.Info("Disconnecting")
	//TODO Close all channels
	return ws.conn.Close()
}

func (ws *WS) read() {
	for {
		var msg string
		websocket.Message.Receive(ws.conn, &msg)

		log.Debugf("Raw: %v", msg)

		switch {
		case strings.HasPrefix(msg, `{"success"`):
			var success wsSuccess
			json.Unmarshal([]byte(msg), &success)
			log.Debugf("Success: %#v", success)

			if channels, found := ws.chSucc[success.Request["op"]]; found {
				for _, ch := range channels {
					select {
					case ch <- struct{}{}:
					default:
					}
				}
			}

			if channels, found := ws.chSucc[success.Request["args"]]; found {
				for _, ch := range channels {
					select {
					case ch <- struct{}{}:
					default:
					}
				}
			}

		case strings.HasPrefix(msg, `{"info"`):
			var info wsInfo
			json.Unmarshal([]byte(msg), &info)
			log.Infof("Info: %v", info)

		case strings.Contains(msg, `{"table"`):
			var table wsData
			json.Unmarshal([]byte(msg), &table)
			log.Debugf("Table: %#v", table)

			switch table.Table {

			case "trade":
				var trades []WSTrade
				json.Unmarshal(table.Data, &trades)

				log.Debugf("Trades: %#v", trades)

				for _, one := range trades {
					ws.trade(one)
				}

			case "quote":
				var quotes []WSQuote
				json.Unmarshal(table.Data, &quotes)

				log.Debugf("Quotes: %#v", quotes)

				for _, one := range quotes {
					ws.quote(one)
				}

			case "order":
				var orders []WSOrder
				json.Unmarshal(table.Data, &orders)

				log.Debugf("Orders: %#v", orders)

				for _, one := range orders {
					ws.order(one)
				}

			case "position":
				var positions []WSPosition
				json.Unmarshal(table.Data, &positions)

				log.Debugf("Positions: %#v", positions)

				for _, one := range positions {
					ws.position(one)
				}

			case "wallet":
				var wallets []bitmex.WSWallet
				json.Unmarshal(table.Data, &wallets)

				for _, one := range wallets {
					ws.wallet(one)
				}

			default:
				log.Infof("%v", msg)
			}

		default:
			log.Infof("%v", msg)
			log.Info("unknown WS message")
			if nil == ws.chStart {
				ws.fatal(errors.New("Unset restart channel"))
			} else {
				log.Info("restart")
				if len(ws.chStart) == 0 {
					ws.chStart <- 1

					ws.Disconnect()
					return
				}
			}
		}
	}
}

func (ws *WS) sendTrade(ch chan WSTrade, trade WSTrade) {
	select {
	case ch <- trade:
		log.Debugf("Trade sent: %#v - %#v", ch, trade)
	default:
		log.Debugf("Trade channel busy: %#v", ch)
	}
}

func (ws *WS) sendOrder(ch chan WSOrder, order WSOrder) {
	select {
	case ch <- order:
		log.Debugf("Order sent: %#v - %#v", ch, order)
	default:
		log.Debugf("Order channel busy: %#v", ch)
	}
}

func (ws *WS) sendQuote(ch chan WSQuote, quote WSQuote) {
	select {
	case ch <- quote:
		log.Debugf("Quote sent: %#v - %#v", ch, quote)
	default:
		log.Debugf("Quote channel busy: %#v", ch)
	}
}

func (ws *WS) sendPosition(ch chan WSPosition, position WSPosition) {
	select {
	case ch <- position:
		log.Debugf("Position sent: %#v - %#v", ch, position)
	default:
		log.Debugf("Position channel busy: %#v", ch)
	}
}

func (ws *WS) sendWallet(ch chan bitmex.WSWallet, wallet bitmex.WSWallet) {
	select {
	case ch <- wallet:
		log.Debugf("Wallet sent: %#v - %#v", ch, wallet)
	default:
		log.Debugf("Wallet channel busy: %#v", ch)
	}
}

func (ws *WS) trade(trade WSTrade) {
	for ch, symbols := range ws.chTrade {
		if len(symbols) == 0 {
			ws.sendTrade(ch, trade)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(trade.Symbol) {
				ws.sendTrade(ch, trade)
			}
		}
	}
}

func (ws *WS) order(order WSOrder) {
	for ch, symbols := range ws.chOrder {
		if len(symbols) == 0 {
			ws.sendOrder(ch, order)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(order.Symbol) {
				ws.sendOrder(ch, order)
			}
		}
	}
}

func (ws *WS) position(position WSPosition) {
	for ch, symbols := range ws.chPosition {
		if len(symbols) == 0 {
			ws.sendPosition(ch, position)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(position.Symbol) {
				ws.sendPosition(ch, position)
			}
		}
	}
}

func (ws *WS) quote(quote WSQuote) {
	for ch, symbols := range ws.chQuote {
		if len(symbols) == 0 {
			ws.sendQuote(ch, quote)
			continue
		}

		for _, oneSymbol := range symbols {
			if oneSymbol == bitmex.Contracts(quote.Symbol) {
				ws.sendQuote(ch, quote)
			}
		}
	}
}

func (ws *WS) wallet(wallet bitmex.WSWallet) {
	ws.sendWallet(ws.chWallet, wallet)
}

func (ws *WS) send(msg string) {
	defer ws.Unlock()

	log.Debugf("Writing WS: %#v", string(msg))
	ws.Lock()

	if _, err := ws.conn.Write([]byte(msg)); err != nil {
		ws.fatal(err)
	}
}

func (ws *WS) fatal(err error) {
	ws.Disconnect()
	log.Fatalf("%v", err.Error())
}

//SubTrade - subscribes channel to trades
func (ws *WS) SubTrade(ch chan WSTrade, contracts []bitmex.Contracts) {
	ws.Lock()

	if _, ok := ws.chTrade[ch]; !ok {
		ws.chTrade[ch] = contracts
	} else {
		ws.chTrade[ch] = append(ws.chTrade[ch], contracts...)
	}

	ws.Unlock()

	for _, one := range contracts {
		ws.send(`{"op": "subscribe", "args": "trade:` + string(one) + `"}`)
	}
}

//SubQuote - subscribes to quotes
func (ws *WS) SubQuote(ch chan WSQuote, contracts []bitmex.Contracts) {

	ws.Lock()

	if _, ok := ws.chQuote[ch]; !ok {
		ws.chQuote[ch] = contracts
	} else {
		ws.chQuote[ch] = append(ws.chQuote[ch], contracts...)
	}

	ws.Unlock()

	for _, one := range contracts {
		ws.send(`{"op": "subscribe", "args": "quote:` + string(one) + `"}`)
	}
}

func (ws *WS) RegisterReStart(ch chan int64) {
	ws.chStart = ch
}<|endoftext|>


<commit_before>package main

import (
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
)

type cursor_context struct {
	decl    *decl
	partial string
}

type token_item struct {
	off int
	tok token.Token
	lit string
}

type bytes_iterator struct {
	tokens      []token_item
	token_index int
}

func (i token_item) Literal() string {
	if i.tok.IsLiteral() {
		return i.lit
	} else {
		return i.tok.String()
	}
}

func (this *bytes_iterator) token() token_item {
	return this.tokens[this.token_index]
}

func (this *bytes_iterator) previous_token() bool {
	if this.token_index <= 0 {
		return false
	}
	this.token_index--
	return true
}

var g_bracket_pairs = map[token.Token]token.Token{
	token.RPAREN: token.LPAREN,
	token.RBRACK: token.LBRACK,
}

// when the cursor is at the ')' or ']', move the cursor to an opposite bracket
// pair, this functions takes inner bracker pairs into account
func (this *bytes_iterator) skip_to_bracket_pair() bool {
	right := this.token().tok
	left := g_bracket_pairs[right]
	return this.skip_to_left_bracket(left, right)
}

func (this *bytes_iterator) skip_to_left_bracket(left, right token.Token) bool {
	// TODO: Make this functin recursive.
	if this.token().tok == left {
		return true
	}
	balance := 1
	for balance != 0 {
		this.previous_token()
		if this.token_index == 0 {
			return false
		}
		switch this.token().tok {
		case right:
			balance++
		case left:
			balance--
		}
	}
	return true
}

// Move the cursor to the open brace of the current block, taking inner blocks
// into account.
func (this *bytes_iterator) skip_to_open_brace() bool {
	return this.skip_to_left_bracket(token.LBRACE, token.RBRACE)
}

// try_extract_struct_init_expr tries to match the current cursor position as being inside a struct
// initialization expression of the form:
// &X{
// 	Xa: 1,
// 	Xb: 2,
// }
// Nested struct initialization expressions are handled correctly.
func (this *bytes_iterator) try_extract_struct_init_expr() []byte {
	for this.token_index >= 0 {
		if !this.skip_to_open_brace() {
			return nil
		}

		if !this.previous_token() {
			return nil
		}

		return []byte(this.token().Literal())
	}
	return nil
}

// starting from the end of the 'file', move backwards and return a slice of a
// valid Go expression
func (this *bytes_iterator) extract_go_expr() []byte {
	// TODO: Make this function recursive.
	last := token.ILLEGAL
	orig := this.token_index
loop:
	for {
		if this.token_index == 0 {
			return make_expr(this.tokens[:orig])
		}
		r := this.token().tok
		switch r {
		case token.PERIOD:
			this.previous_token()
			last = r
		case token.RPAREN, token.RBRACK:
			if last == token.IDENT {
				// ")ident" or "]ident".
				break loop
			}
			this.skip_to_bracket_pair()
			this.previous_token()
			last = r
		case token.SEMICOLON, token.LPAREN, token.LBRACE, token.COLON, token.COMMA:
			// If we reach one of these tokens, the expression is definitely over.
			break loop
		default:
			this.previous_token()
			last = r
		}
	}
	return make_expr(this.tokens[this.token_index+1 : orig])
}

// Given a slice of token_item, reassembles them into the original literal expression.
func make_expr(tokens []token_item) []byte {
	e := ""
	for _, t := range tokens {
		e += t.Literal()
	}
	return []byte(e)
}

// this function is called when the cursor is at the '.' and you need to get the
// declaration before that dot
func (c *auto_complete_context) deduce_cursor_decl(iter *bytes_iterator) *decl {
	e := string(iter.extract_go_expr())
	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil
	}
	return expr_to_decl(expr, c.current.scope)
}

func new_bytes_iterator(src []byte, cursor int) bytes_iterator {
	tokens := make([]token_item, 0, 1000)
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, 0)
	token_index := 0
	for {
		pos, tok, lit := s.Scan()
		if tok == token.EOF {
			break
		}
		off := fset.Position(pos).Offset
		tokens = append(tokens, token_item{
			off: off,
			tok: tok,
			lit: lit,
		})
		if cursor > off {
			token_index++
		}
	}
	return bytes_iterator{
		tokens:      tokens,
		token_index: token_index,
	}
}

// deduce cursor context, it includes the declaration under the cursor and partial identifier
// (usually a part of the name of the child declaration)
func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) (cursor_context, bool) {
	if cursor <= 0 {
		return cursor_context{nil, ""}, true
	}

	iter := new_bytes_iterator(file, cursor)

	// figure out what is just before the cursor
	iter.previous_token()
	if iter.token().tok == token.PERIOD {
		// we're '<whatever>.'
		// figure out decl, Parital is ""
		decl := c.deduce_cursor_decl(&iter)
		return cursor_context{decl, ""}, decl != nil
	}

	// TODO: Merge with above case.
	r := iter.token()
	if (r.tok == token.IDENT) || (r.tok == token.VAR) {
		// we're '<whatever>.<ident>'
		// parse <ident> as Partial and figure out decl
		partial := iter.token().Literal()
		iter.previous_token()
		if iter.token().tok == token.PERIOD {
			decl := c.deduce_cursor_decl(&iter)
			return cursor_context{decl, partial}, decl != nil
		} else {
			return cursor_context{nil, partial}, true
		}
	}

	if (r.tok == token.COMMA) || (r.tok == token.LBRACE) {
		// Try to parse the current expression as a structure initialization.
		data := iter.try_extract_struct_init_expr()
		if data == nil {
			return cursor_context{nil, ""}, true
		}

		expr, err := parser.ParseExpr(string(data))
		if err != nil {
			return cursor_context{nil, ""}, true
		}
		decl := expr_to_decl(expr, c.current.scope)
		if decl == nil {
			return cursor_context{nil, ""}, true
		}

		switch decl.typ.(type) {
		case *ast.StructType:
			// TODO: Return partial.
			return cursor_context{struct_members_only(decl), ""}, true
		}
	}

	return cursor_context{nil, ""}, true
}

// struct_members_only returns a copy of decl with all its children of type function stripped out.
// This is used when returning matches for struct initialization expressions, for which it does not
// make sense to suggest a function name associated with the struct.
func struct_members_only(decl *decl) *decl {
	new_decl := *decl
	for k, d := range new_decl.children {
		switch d.typ.(type) {
		case *ast.FuncType:
			// Strip functions from the list.
			delete(new_decl.children, k)
		}
	}
	return &new_decl
}

// deduce the type of the expression under the cursor, a bit of copy & paste from the method
// above, returns true if deduction was successful (even if the result of it is nil)
func (c *auto_complete_context) deduce_cursor_type_pkg(file []byte, cursor int) (ast.Expr, string, bool) {
	if cursor <= 0 {
		return nil, "", true
	}

	iter := new_bytes_iterator(file, cursor)

	// read backwards to extract expression
	e := string(iter.extract_go_expr())

	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil, "", false
	} else {
		t, scope, _ := infer_type(expr, c.current.scope, -1)
		return t, lookup_pkg(get_type_path(t), scope), t != nil
	}
}
<commit_msg>Rename bytes_iterator into token_iterator<commit_after>package main

import (
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
)

type cursor_context struct {
	decl    *decl
	partial string
}

type token_iterator struct {
	tokens      []token_item
	token_index int
}

type token_item struct {
	off int
	tok token.Token
	lit string
}

func (i token_item) Literal() string {
	if i.tok.IsLiteral() {
		return i.lit
	} else {
		return i.tok.String()
	}
}

func (this *token_iterator) token() token_item {
	return this.tokens[this.token_index]
}

func (this *token_iterator) previous_token() bool {
	if this.token_index <= 0 {
		return false
	}
	this.token_index--
	return true
}

var g_bracket_pairs = map[token.Token]token.Token{
	token.RPAREN: token.LPAREN,
	token.RBRACK: token.LBRACK,
}

// when the cursor is at the ')' or ']', move the cursor to an opposite bracket
// pair, this functions takes inner bracker pairs into account
func (this *token_iterator) skip_to_bracket_pair() bool {
	right := this.token().tok
	left := g_bracket_pairs[right]
	return this.skip_to_left_bracket(left, right)
}

func (this *token_iterator) skip_to_left_bracket(left, right token.Token) bool {
	// TODO: Make this functin recursive.
	if this.token().tok == left {
		return true
	}
	balance := 1
	for balance != 0 {
		this.previous_token()
		if this.token_index == 0 {
			return false
		}
		switch this.token().tok {
		case right:
			balance++
		case left:
			balance--
		}
	}
	return true
}

// Move the cursor to the open brace of the current block, taking inner blocks
// into account.
func (this *token_iterator) skip_to_open_brace() bool {
	return this.skip_to_left_bracket(token.LBRACE, token.RBRACE)
}

// try_extract_struct_init_expr tries to match the current cursor position as being inside a struct
// initialization expression of the form:
// &X{
// 	Xa: 1,
// 	Xb: 2,
// }
// Nested struct initialization expressions are handled correctly.
func (this *token_iterator) try_extract_struct_init_expr() []byte {
	for this.token_index >= 0 {
		if !this.skip_to_open_brace() {
			return nil
		}

		if !this.previous_token() {
			return nil
		}

		return []byte(this.token().Literal())
	}
	return nil
}

// starting from the end of the 'file', move backwards and return a slice of a
// valid Go expression
func (this *token_iterator) extract_go_expr() []byte {
	// TODO: Make this function recursive.
	last := token.ILLEGAL
	orig := this.token_index
loop:
	for {
		if this.token_index == 0 {
			return make_expr(this.tokens[:orig])
		}
		r := this.token().tok
		switch r {
		case token.PERIOD:
			this.previous_token()
			last = r
		case token.RPAREN, token.RBRACK:
			if last == token.IDENT {
				// ")ident" or "]ident".
				break loop
			}
			this.skip_to_bracket_pair()
			this.previous_token()
			last = r
		case token.SEMICOLON, token.LPAREN, token.LBRACE, token.COLON, token.COMMA:
			// If we reach one of these tokens, the expression is definitely over.
			break loop
		default:
			this.previous_token()
			last = r
		}
	}
	return make_expr(this.tokens[this.token_index+1 : orig])
}

// Given a slice of token_item, reassembles them into the original literal expression.
func make_expr(tokens []token_item) []byte {
	e := ""
	for _, t := range tokens {
		e += t.Literal()
	}
	return []byte(e)
}

// this function is called when the cursor is at the '.' and you need to get the
// declaration before that dot
func (c *auto_complete_context) deduce_cursor_decl(iter *token_iterator) *decl {
	e := string(iter.extract_go_expr())
	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil
	}
	return expr_to_decl(expr, c.current.scope)
}

func new_token_iterator(src []byte, cursor int) token_iterator {
	tokens := make([]token_item, 0, 1000)
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, 0)
	token_index := 0
	for {
		pos, tok, lit := s.Scan()
		if tok == token.EOF {
			break
		}
		off := fset.Position(pos).Offset
		tokens = append(tokens, token_item{
			off: off,
			tok: tok,
			lit: lit,
		})
		if cursor > off {
			token_index++
		}
	}
	return token_iterator{
		tokens:      tokens,
		token_index: token_index,
	}
}

// deduce cursor context, it includes the declaration under the cursor and partial identifier
// (usually a part of the name of the child declaration)
func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) (cursor_context, bool) {
	if cursor <= 0 {
		return cursor_context{nil, ""}, true
	}

	iter := new_token_iterator(file, cursor)

	// figure out what is just before the cursor
	iter.previous_token()
	if iter.token().tok == token.PERIOD {
		// we're '<whatever>.'
		// figure out decl, Parital is ""
		decl := c.deduce_cursor_decl(&iter)
		return cursor_context{decl, ""}, decl != nil
	}

	// TODO: Merge with above case.
	r := iter.token()
	if (r.tok == token.IDENT) || (r.tok == token.VAR) {
		// we're '<whatever>.<ident>'
		// parse <ident> as Partial and figure out decl
		partial := iter.token().Literal()
		iter.previous_token()
		if iter.token().tok == token.PERIOD {
			decl := c.deduce_cursor_decl(&iter)
			return cursor_context{decl, partial}, decl != nil
		} else {
			return cursor_context{nil, partial}, true
		}
	}

	if (r.tok == token.COMMA) || (r.tok == token.LBRACE) {
		// Try to parse the current expression as a structure initialization.
		data := iter.try_extract_struct_init_expr()
		if data == nil {
			return cursor_context{nil, ""}, true
		}

		expr, err := parser.ParseExpr(string(data))
		if err != nil {
			return cursor_context{nil, ""}, true
		}
		decl := expr_to_decl(expr, c.current.scope)
		if decl == nil {
			return cursor_context{nil, ""}, true
		}

		switch decl.typ.(type) {
		case *ast.StructType:
			// TODO: Return partial.
			return cursor_context{struct_members_only(decl), ""}, true
		}
	}

	return cursor_context{nil, ""}, true
}

// struct_members_only returns a copy of decl with all its children of type function stripped out.
// This is used when returning matches for struct initialization expressions, for which it does not
// make sense to suggest a function name associated with the struct.
func struct_members_only(decl *decl) *decl {
	new_decl := *decl
	for k, d := range new_decl.children {
		switch d.typ.(type) {
		case *ast.FuncType:
			// Strip functions from the list.
			delete(new_decl.children, k)
		}
	}
	return &new_decl
}

// deduce the type of the expression under the cursor, a bit of copy & paste from the method
// above, returns true if deduction was successful (even if the result of it is nil)
func (c *auto_complete_context) deduce_cursor_type_pkg(file []byte, cursor int) (ast.Expr, string, bool) {
	if cursor <= 0 {
		return nil, "", true
	}

	iter := new_token_iterator(file, cursor)

	// read backwards to extract expression
	e := string(iter.extract_go_expr())

	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil, "", false
	} else {
		t, scope, _ := infer_type(expr, c.current.scope, -1)
		return t, lookup_pkg(get_type_path(t), scope), t != nil
	}
}
<|endoftext|>


<commit_before>package constraints

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

// Value describes a user's requirements of the hardware on which units
// of a service will run. Constraints are used to choose an existing machine
// onto which a unit will be deployed, or to provision a new machine if no
// existing one satisfies the requirements.
type Value struct {

	// Arch, if not nil or empty, indicates that a machine must run the named
	// architecture.
	Arch *string `json:"arch,omitempty" yaml:"arch,omitempty"`

	// CpuCores, if not nil, indicates that a machine must have at least that
	// number of effective cores available.
	CpuCores *uint64 `json:"cpu-cores,omitempty" yaml:"cpu-cores,omitempty"`

	// CpuPower, if not nil, indicates that a machine must have at least that
	// amount of CPU power available, where 100 CpuPower is considered to be
	// equivalent to 1 Amazon ECU (or, roughly, a single 2007-era Xeon).
	CpuPower *uint64 `json:"cpu-power,omitempty" yaml:"cpu-power,omitempty"`

	// Mem, if not nil, indicates that a machine must have at least that many
	// megabytes of RAM.
	Mem *uint64 `json:"mem,omitempty" yaml:"mem,omitempty"`
}

// String expresses a constraints.Value in the language in which it was specified.
func (c Value) String() string {
	var strs []string
	if c.Arch != nil {
		strs = append(strs, "arch="+*c.Arch)
	}
	if c.CpuCores != nil {
		strs = append(strs, "cpu-cores="+uintStr(*c.CpuCores))
	}
	if c.CpuPower != nil {
		strs = append(strs, "cpu-power="+uintStr(*c.CpuPower))
	}
	if c.Mem != nil {
		s := uintStr(*c.Mem)
		if s != "" {
			s += "M"
		}
		strs = append(strs, "mem="+s)
	}
	return strings.Join(strs, " ")
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

// ParseConstraints constructs a constraint.Value from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseConstraints(args ...string) (Value, error) {
	cons := Value{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := cons.setRaw(raw); err != nil {
				return Value{}, err
			}
		}
	}
	return cons, nil
}

// Constraints implements gnuflag.Value for a Constraints.
type ConstraintsValue struct {
	Target *Constraints
}

func (v ConstraintsValue) Set(s string) error {
	cons, err := ParseConstraints(s)
	if err != nil {
		return err
	}
	*v.Target = cons
	return nil
}

func (v ConstraintsValue) String() string {
	return v.Target.String()
}

// setRaw interprets a name=value string and sets the supplied value.
func (c *Value) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed constraint %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = c.setArch(str)
	case "cpu-cores":
		err = c.setCpuCores(str)
	case "cpu-power":
		err = c.setCpuPower(str)
	case "mem":
		err = c.setMem(str)
	default:
		return fmt.Errorf("unknown constraint %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q constraint: %v", name, err)
	}
	return nil
}

func (c *Value) setArch(str string) error {
	if c.Arch != nil {
		return fmt.Errorf("already set")
	}
	switch str {
	case "":
	case "amd64", "i386", "arm":
	default:
		return fmt.Errorf("%q not recognized", str)
	}
	c.Arch = &str
	return nil
}

func (c *Value) setCpuCores(str string) (err error) {
	if c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	c.CpuCores, err = parseUint64(str)
	return
}

func (c *Value) setCpuPower(str string) (err error) {
	if c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	c.CpuPower, err = parseUint64(str)
	return
}

func (c *Value) setMem(str string) error {
	if c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	c.Mem = &value
	return nil
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<commit_msg>more review changes<commit_after>package constraints

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

// Value describes a user's requirements of the hardware on which units
// of a service will run. Constraints are used to choose an existing machine
// onto which a unit will be deployed, or to provision a new machine if no
// existing one satisfies the requirements.
type Value struct {

	// Arch, if not nil or empty, indicates that a machine must run the named
	// architecture.
	Arch *string `json:"arch,omitempty" yaml:"arch,omitempty"`

	// CpuCores, if not nil, indicates that a machine must have at least that
	// number of effective cores available.
	CpuCores *uint64 `json:"cpu-cores,omitempty" yaml:"cpu-cores,omitempty"`

	// CpuPower, if not nil, indicates that a machine must have at least that
	// amount of CPU power available, where 100 CpuPower is considered to be
	// equivalent to 1 Amazon ECU (or, roughly, a single 2007-era Xeon).
	CpuPower *uint64 `json:"cpu-power,omitempty" yaml:"cpu-power,omitempty"`

	// Mem, if not nil, indicates that a machine must have at least that many
	// megabytes of RAM.
	Mem *uint64 `json:"mem,omitempty" yaml:"mem,omitempty"`
}

func (c Value) String() string {
	var strs []string
	if c.Arch != nil {
		strs = append(strs, "arch="+*c.Arch)
	}
	if c.CpuCores != nil {
		strs = append(strs, "cpu-cores="+uintStr(*c.CpuCores))
	}
	if c.CpuPower != nil {
		strs = append(strs, "cpu-power="+uintStr(*c.CpuPower))
	}
	if c.Mem != nil {
		s := uintStr(*c.Mem)
		if s != "" {
			s += "M"
		}
		strs = append(strs, "mem="+s)
	}
	return strings.Join(strs, " ")
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

// ParseConstraints constructs a constraint.Value from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseConstraints(args ...string) (Value, error) {
	cons := Value{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := cons.setRaw(raw); err != nil {
				return Value{}, err
			}
		}
	}
	return cons, nil
}

// Constraints implements gnuflag.Value for a Constraints.
type ConstraintsValue struct {
	Target *Constraints
}

func (v ConstraintsValue) Set(s string) error {
	cons, err := ParseConstraints(s)
	if err != nil {
		return err
	}
	*v.Target = cons
	return nil
}

func (v ConstraintsValue) String() string {
	return v.Target.String()
}

// setRaw interprets a name=value string and sets the supplied value.
func (c *Value) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed constraint %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = c.setArch(str)
	case "cpu-cores":
		err = c.setCpuCores(str)
	case "cpu-power":
		err = c.setCpuPower(str)
	case "mem":
		err = c.setMem(str)
	default:
		return fmt.Errorf("unknown constraint %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q constraint: %v", name, err)
	}
	return nil
}

func (c *Value) setArch(str string) error {
	if c.Arch != nil {
		return fmt.Errorf("already set")
	}
	switch str {
	case "":
	case "amd64", "i386", "arm":
	default:
		return fmt.Errorf("%q not recognized", str)
	}
	c.Arch = &str
	return nil
}

func (c *Value) setCpuCores(str string) (err error) {
	if c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	c.CpuCores, err = parseUint64(str)
	return
}

func (c *Value) setCpuPower(str string) (err error) {
	if c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	c.CpuPower, err = parseUint64(str)
	return
}

func (c *Value) setMem(str string) error {
	if c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	c.Mem = &value
	return nil
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<|endoftext|>


<commit_before>package ccv3_test

import (
	"fmt"
	"net/http"

	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/ghttp"
)

var _ = Describe("Info", func() {
	var client *Client

	BeforeEach(func() {
		client = NewTestClient()
	})

	Describe("Info", func() {
		BeforeEach(func() {
			server.Reset()

			serverURL := server.URL()
			rootResponse := fmt.Sprintf(`
{
  "links": {
    "self": {
      "href": "%s"
    },
    "cloud_controller_v2": {
      "href": "%s/v2",
      "meta": {
        "version": "2.64.0"
      }
    },
    "cloud_controller_v3": {
      "href": "%s/v3",
      "meta": {
        "version": "3.0.0-alpha.5"
      }
    }
  }
}
`, serverURL, serverURL, serverURL)

			server.AppendHandlers(
				CombineHandlers(
					VerifyRequest(http.MethodGet, "/"),
					RespondWith(
						http.StatusOK,
						rootResponse,
						http.Header{"X-Cf-Warnings": {"warning 1"}}),
				),
			)

			v3Response := fmt.Sprintf(`
{
  "links": {
    "self": {
      "href": "%s/v3"
    },
    "tasks": {
      "href": "%s/v3/tasks"
    },
    "uaa": {
      "href": "https://uaa.bosh-lite.com"
    }
  }
}
`, serverURL, serverURL)

			server.AppendHandlers(
				CombineHandlers(
					VerifyRequest(http.MethodGet, "/v3"),
					RespondWith(
						http.StatusOK,
						v3Response,
						http.Header{"X-Cf-Warnings": {"warning 2"}}),
				),
			)
		})

		It("returns back the CC Information", func() {
			info, _, err := client.Info()
			Expect(err).NotTo(HaveOccurred())
			Expect(info.UAA()).To(Equal("https://uaa.bosh-lite.com"))
		})

		It("returns all warnings", func() {
			_, warnings, err := client.Info()
			Expect(err).NotTo(HaveOccurred())
			Expect(warnings).To(ConsistOf("warning 1", "warning 2"))
		})

		Context("when the uaa endpoint does not exist", func() {
			BeforeEach(func() {
				response := `{
   "links": {
      "self": {
         "href": "https://api.bosh-lite.com/v3"
      },
      "tasks": {
         "href": "https://api.bosh-lite.com/v3/tasks"
      }
   }
}`

				server.SetHandler(1,
					CombineHandlers(
						VerifyRequest(http.MethodGet, "/v3"),
						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
					),
				)
			})

			It("returns an empty endpoint", func() {
				info, _, err := client.Info()
				Expect(err).NotTo(HaveOccurred())

				Expect(info.UAA()).To(BeEmpty())
			})
		})

		Context("when the cloud controller encounters an error", func() {
			Context("when the error occurs making a request to '/'", func() {
				BeforeEach(func() {
					server.SetHandler(0,
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/"),
							RespondWith(
								http.StatusNotFound,
								`{"errors": [{}]}`,
								http.Header{"X-Cf-Warnings": {"this is a warning"}}),
						),
					)
				})

				It("returns the same error", func() {
					_, warnings, err := client.Info()
					Expect(err).To(MatchError(ResourceNotFoundError{}))
					Expect(warnings).To(ConsistOf("this is a warning"))
				})
			})

			Context("when the error occurs making a request to '/v3'", func() {
				BeforeEach(func() {
					server.SetHandler(1,
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/v3"),
							RespondWith(
								http.StatusNotFound,
								`{"errors": [{}]}`,
								http.Header{"X-Cf-Warnings": {"this is a warning"}}),
						),
					)
				})

				It("returns the same error", func() {
					_, warnings, err := client.Info()
					Expect(err).To(MatchError(ResourceNotFoundError{}))
					Expect(warnings).To(ConsistOf("warning 1", "this is a warning"))
				})
			})
		})
	})
})
<commit_msg>refactor ccv3 info test to reduce flakiness<commit_after>package ccv3_test

import (
	"fmt"
	"net/http"

	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/ghttp"
)

var _ = Describe("Info", func() {
	var (
		client          *Client
		rootRespondWith http.HandlerFunc
		v3RespondWith   http.HandlerFunc
	)

	JustBeforeEach(func() {
		client = NewTestClient()

		server.AppendHandlers(
			CombineHandlers(
				VerifyRequest(http.MethodGet, "/"),
				rootRespondWith,
			),
			CombineHandlers(
				VerifyRequest(http.MethodGet, "/v3"),
				v3RespondWith,
			))
	})

	Describe("when all requests are successful", func() {
		BeforeEach(func() {
			rootResponse := fmt.Sprintf(`{
				"links": {
					"self": {
						"href": "%s"
					},
					"cloud_controller_v2": {
						"href": "%s/v2",
						"meta": {
							"version": "2.64.0"
						}
					},
					"cloud_controller_v3": {
						"href": "%s/v3",
						"meta": {
							"version": "3.0.0-alpha.5"
						}
					}
				}
			}
			`, server.URL(), server.URL(), server.URL())

			rootRespondWith = RespondWith(
				http.StatusOK,
				rootResponse,
				http.Header{"X-Cf-Warnings": {"warning 1"}})

			v3Response := fmt.Sprintf(`{
				"links": {
					"self": {
						"href": "%s/v3"
					},
					"tasks": {
						"href": "%s/v3/tasks"
					},
					"uaa": {
						"href": "https://uaa.bosh-lite.com"
					}
				}
			}
			`, server.URL(), server.URL())

			v3RespondWith = RespondWith(
				http.StatusOK,
				v3Response,
				http.Header{"X-Cf-Warnings": {"warning 2"}})
		})

		It("returns back the CC Information", func() {
			info, _, err := client.Info()
			Expect(err).NotTo(HaveOccurred())
			Expect(info.UAA()).To(Equal("https://uaa.bosh-lite.com"))
		})

		It("returns all warnings", func() {
			_, warnings, err := client.Info()
			Expect(err).NotTo(HaveOccurred())
			Expect(warnings).To(ConsistOf("warning 1", "warning 2"))
		})
	})

	Context("when the uaa endpoint does not exist", func() {
		BeforeEach(func() {
			response := `{
				 "links": {
						"self": {
							 "href": "https://api.bosh-lite.com/v3"
						},
						"tasks": {
							 "href": "https://api.bosh-lite.com/v3/tasks"
						}
				 }
			}`

			v3RespondWith = RespondWith(
				http.StatusOK,
				response,
				http.Header{"X-Cf-Warnings": {"this is a warning"}})
		})

		It("returns an empty endpoint", func() {
			info, _, err := client.Info()
			Expect(err).NotTo(HaveOccurred())

			Expect(info.UAA()).To(BeEmpty())
		})
	})

	Context("when the cloud controller encounters an error", func() {
		Context("when the error occurs making a request to '/'", func() {
			BeforeEach(func() {
				rootRespondWith = RespondWith(
					http.StatusNotFound,
					`{"errors": [{}]}`,
					http.Header{"X-Cf-Warnings": {"this is a warning"}})
			})

			It("returns the same error", func() {
				_, warnings, err := client.Info()
				Expect(err).To(MatchError(ResourceNotFoundError{}))
				Expect(warnings).To(ConsistOf("this is a warning"))
			})
		})

		Context("when the error occurs making a request to '/v3'", func() {
			BeforeEach(func() {
				v3RespondWith = RespondWith(
					http.StatusNotFound,
					`{"errors": [{}]}`,
					http.Header{"X-Cf-Warnings": {"this is a warning"}})
			})

			It("returns the same error", func() {
				_, warnings, err := client.Info()
				Expect(err).To(MatchError(ResourceNotFoundError{}))
				Expect(warnings).To(ConsistOf("this is a warning"))
			})
		})
	})
})
<|endoftext|>


<commit_before>package nsqlookup

import (
	"net"
	"sort"
	"strconv"
)

// The NodeInfo structure carries information about a node referenced by a
// nsqlookup server.
type NodeInfo struct {
	// RemoteAddress is the address that the node connected from.
	RemoteAddress string `json:"remote_address"`

	// Hostname of the nsqd node.
	Hostname string `json:"hostname"`

	// BroadcastAddress is the address advertized by the nsqd node.
	BroadcastAddress string `json:"broadcast_address"`

	// TcpPort is the port on which the nsqd node is listening for incoming TCP
	// connections.
	TcpPort int `json:"tcp_port"`

	// HttpPort is the port on which the nsqd node accepts HTTP requests.
	HttpPort int `json:"http_port"`

	// Version represents the version of nsqd ran by the node.
	Version string `json:"version"`
}

// The EngineInfo structure carries information about a nsqlookup engine.
type EngineInfo struct {
	// Version represents the version of the nsqlookup engine.
	Version string `json:"version"`
}

// The Engine interface must be implemented by types that are intended to be
// used to power nsqlookup servers.
type Engine interface {
	// Close should release all internal state maintained by the engine, it is
	// called when the nsqlookup server using the engine is shutting down.
	Close() error

	// RegisterNode is called by nsqlookup servers when a new node is attempting
	// to register.
	RegisterNode(node NodeInfo) error

	// UnregisterNode is called by nsqlookup servers when a node that had
	// previously registered is going away.
	UnregisterNode(node NodeInfo) error

	// PingNode is called by nsqlookup servers when a registered node sends a
	// ping command to inform that it is still alive.
	PingNode(node NodeInfo) error

	// TomstonNode marks topic as tombstoned on node.
	TombstoneNode(node NodeInfo, topic string) error

	// RegisterTopic is called by nsqlookup servers when topic is being
	// registered on node.
	RegisterTopic(node NodeInfo, topic string) error

	// UnregisterTopic is called by nsqlookup servers when topic is being
	// unregistered from node.
	UnregisterTopic(node NodeInfo, topic string) error

	// RegisterChannel is called by nsqlookup servers when channel from topic is
	// being registered on node.
	RegisterChannel(node NodeInfo, topic string, channel string) error

	// UnregisterChannel is called by nsqlookup servers when channel from topic
	// is being unregistered from node.
	UnregisterChannel(node NodeInfo, topic string, channel string) error

	// LookupNodes must return a list of of all nodes registered on the engine.
	LookupNodes() ([]NodeInfo, error)

	// LookupProducers must return a list of all nodes for which topic has been
	// registered on the engine and were not tombstoned.
	LookupProducers(topic string) ([]NodeInfo, error)

	// LookupTopics must return a list of all topics registered on the engine.
	LookupTopics() ([]string, error)

	// LookupChannels must return a list of all channels registerd for topic on
	// the engine.
	LookupChannels(topic string) ([]string, error)

	// LookupInfo must return information about the engine.
	LookupInfo() (EngineInfo, error)

	// CheckHealth is called by nsqlookup servers to evaluate the health of the
	// engine.
	CheckHealth() error
}

type byNode []NodeInfo

func (n byNode) Len() int {
	return len(n)
}

func (n byNode) Swap(i int, j int) {
	n[i], n[j] = n[j], n[i]
}

func (n byNode) Less(i int, j int) bool {
	n1 := &n[i]
	n2 := &n[j]
	return (n1.BroadcastAddress < n2.BroadcastAddress) ||
		(n1.BroadcastAddress == n2.BroadcastAddress && n1.TcpPort < n2.TcpPort)
}

func sortedNodes(n []NodeInfo) []NodeInfo {
	sort.Sort(byNode(n))
	return n
}

func sortedStrings(s []string) []string {
	sort.Strings(s)
	return s
}

func httpBroadcastAddress(info NodeInfo) string {
	return makeBroadcastAddress(info.BroadcastAddress, info.HttpPort)
}

func tcpBroadcastAddress(info NodeInfo) string {
	return makeBroadcastAddress(info.BroadcastAddress, info.TcpPort)
}

func makeBroadcastAddress(addr string, port int) string {
	host, _, _ := net.SplitHostPort(addr)
	if len(host) == 0 {
		host = addr // no port in addr
	}
	return net.JoinHostPort(host, strconv.Itoa(port))
}
<commit_msg>[skip ci] fix comment typo<commit_after>package nsqlookup

import (
	"net"
	"sort"
	"strconv"
)

// The NodeInfo structure carries information about a node referenced by a
// nsqlookup server.
type NodeInfo struct {
	// RemoteAddress is the address that the node connected from.
	RemoteAddress string `json:"remote_address"`

	// Hostname of the nsqd node.
	Hostname string `json:"hostname"`

	// BroadcastAddress is the address advertized by the nsqd node.
	BroadcastAddress string `json:"broadcast_address"`

	// TcpPort is the port on which the nsqd node is listening for incoming TCP
	// connections.
	TcpPort int `json:"tcp_port"`

	// HttpPort is the port on which the nsqd node accepts HTTP requests.
	HttpPort int `json:"http_port"`

	// Version represents the version of nsqd ran by the node.
	Version string `json:"version"`
}

// The EngineInfo structure carries information about a nsqlookup engine.
type EngineInfo struct {
	// Version represents the version of the nsqlookup engine.
	Version string `json:"version"`
}

// The Engine interface must be implemented by types that are intended to be
// used to power nsqlookup servers.
type Engine interface {
	// Close should release all internal state maintained by the engine, it is
	// called when the nsqlookup server using the engine is shutting down.
	Close() error

	// RegisterNode is called by nsqlookup servers when a new node is attempting
	// to register.
	RegisterNode(node NodeInfo) error

	// UnregisterNode is called by nsqlookup servers when a node that had
	// previously registered is going away.
	UnregisterNode(node NodeInfo) error

	// PingNode is called by nsqlookup servers when a registered node sends a
	// ping command to inform that it is still alive.
	PingNode(node NodeInfo) error

	// TombstoneNode marks topic as tombstoned on node.
	TombstoneNode(node NodeInfo, topic string) error

	// RegisterTopic is called by nsqlookup servers when topic is being
	// registered on node.
	RegisterTopic(node NodeInfo, topic string) error

	// UnregisterTopic is called by nsqlookup servers when topic is being
	// unregistered from node.
	UnregisterTopic(node NodeInfo, topic string) error

	// RegisterChannel is called by nsqlookup servers when channel from topic is
	// being registered on node.
	RegisterChannel(node NodeInfo, topic string, channel string) error

	// UnregisterChannel is called by nsqlookup servers when channel from topic
	// is being unregistered from node.
	UnregisterChannel(node NodeInfo, topic string, channel string) error

	// LookupNodes must return a list of of all nodes registered on the engine.
	LookupNodes() ([]NodeInfo, error)

	// LookupProducers must return a list of all nodes for which topic has been
	// registered on the engine and were not tombstoned.
	LookupProducers(topic string) ([]NodeInfo, error)

	// LookupTopics must return a list of all topics registered on the engine.
	LookupTopics() ([]string, error)

	// LookupChannels must return a list of all channels registerd for topic on
	// the engine.
	LookupChannels(topic string) ([]string, error)

	// LookupInfo must return information about the engine.
	LookupInfo() (EngineInfo, error)

	// CheckHealth is called by nsqlookup servers to evaluate the health of the
	// engine.
	CheckHealth() error
}

type byNode []NodeInfo

func (n byNode) Len() int {
	return len(n)
}

func (n byNode) Swap(i int, j int) {
	n[i], n[j] = n[j], n[i]
}

func (n byNode) Less(i int, j int) bool {
	n1 := &n[i]
	n2 := &n[j]
	return (n1.BroadcastAddress < n2.BroadcastAddress) ||
		(n1.BroadcastAddress == n2.BroadcastAddress && n1.TcpPort < n2.TcpPort)
}

func sortedNodes(n []NodeInfo) []NodeInfo {
	sort.Sort(byNode(n))
	return n
}

func sortedStrings(s []string) []string {
	sort.Strings(s)
	return s
}

func httpBroadcastAddress(info NodeInfo) string {
	return makeBroadcastAddress(info.BroadcastAddress, info.HttpPort)
}

func tcpBroadcastAddress(info NodeInfo) string {
	return makeBroadcastAddress(info.BroadcastAddress, info.TcpPort)
}

func makeBroadcastAddress(addr string, port int) string {
	host, _, _ := net.SplitHostPort(addr)
	if len(host) == 0 {
		host = addr // no port in addr
	}
	return net.JoinHostPort(host, strconv.Itoa(port))
}
<|endoftext|>