<commit_before>package intents

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/tests/testutils"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var ins *instance.Instance
var token string
var appToken string
var filesToken string
var intentID string
var appPerms *permissions.Permission

func checkIntentResult(t *testing.T, res *http.Response) {
	assert.Equal(t, 200, res.StatusCode)
	var result map[string]interface{}
	err := json.NewDecoder(res.Body).Decode(&result)
	assert.NoError(t, err)
	data, ok := result["data"].(map[string]interface{})
	assert.True(t, ok)
	assert.Equal(t, "io.cozy.intents", data["type"].(string))
	intentID = data["id"].(string)
	assert.NotEmpty(t, intentID)
	attrs := data["attributes"].(map[string]interface{})
	assert.Equal(t, "PICK", attrs["action"].(string))
	assert.Equal(t, "io.cozy.files", attrs["type"].(string))
	assert.Equal(t, "https://app.cozy.example.net", attrs["client"].(string))
	perms := attrs["permissions"].([]interface{})
	assert.Len(t, perms, 1)
	assert.Equal(t, "GET", perms[0].(string))
	links := data["links"].(map[string]interface{})
	assert.Equal(t, "/intents/"+intentID, links["self"].(string))
	assert.Equal(t, "/permissions/"+appPerms.ID(), links["permissions"].(string))
}

func TestCreateIntent(t *testing.T) {
	body := `{
		"data": {
			"type": "io.cozy.settings",
			"attributes": {
				"action": "PICK",
				"type": "io.cozy.files",
				"permissions": ["GET"]
			}
		}
	}`
	req, _ := http.NewRequest("POST", ts.URL+"/intents", bytes.NewBufferString(body))
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+appToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	checkIntentResult(t, res)
}

func TestCreateIntentIsRejectedForOAuthClients(t *testing.T) {
	body := `{
		"data": {
			"type": "io.cozy.settings",
			"attributes": {
				"action": "PICK",
				"type": "io.cozy.files",
				"permissions": ["GET"]
			}
		}
	}`
	req, _ := http.NewRequest("POST", ts.URL+"/intents", bytes.NewBufferString(body))
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	assert.Equal(t, 403, res.StatusCode)
}

func TestGetIntent(t *testing.T) {
	req, _ := http.NewRequest("GET", ts.URL+"/intents/"+intentID, nil)
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+filesToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	checkIntentResult(t, res)
}

func TestGetIntentNotFromTheService(t *testing.T) {
	req, _ := http.NewRequest("GET", ts.URL+"/intents/"+intentID, nil)
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+appToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	assert.Equal(t, 403, res.StatusCode)
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	testutils.NeedCouchdb()
	setup := testutils.NewSetup(m, "intents_test")
	ins = setup.GetTestInstance(&instance.Options{
		Domain: "cozy.example.net",
	})
	_, token = setup.GetTestClient(consts.Settings)

	app := &apps.WebappManifest{
		DocSlug:        "app",
		DocPermissions: permissions.Set{},
	}
	err := couchdb.CreateNamedDoc(ins, app)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	appPerms, err = permissions.CreateWebappSet(ins, app.Slug(), app.Permissions())
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	appToken = ins.BuildAppToken(app)
	files := &apps.WebappManifest{
		DocSlug:        "files",
		DocPermissions: permissions.Set{},
		Intents: []apps.Intent{
			apps.Intent{
				Action: "PICK",
				Types:  []string{"io.cozy.files", "image/gif"},
				Href:   "/pick",
			},
		},
	}
	if err := couchdb.CreateNamedDoc(ins, files); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if _, err := permissions.CreateWebappSet(ins, files.Slug(), files.Permissions()); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	filesToken = ins.BuildAppToken(files)

	ts = setup.GetTestServer("/intents", Routes)
	os.Exit(setup.Run())

}
<commit_msg>Remove the old test<commit_after>package intents

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/tests/testutils"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var ins *instance.Instance
var token string
var appToken string
var filesToken string
var intentID string
var appPerms *permissions.Permission

func checkIntentResult(t *testing.T, res *http.Response) {
	assert.Equal(t, 200, res.StatusCode)
	var result map[string]interface{}
	err := json.NewDecoder(res.Body).Decode(&result)
	assert.NoError(t, err)
	data, ok := result["data"].(map[string]interface{})
	assert.True(t, ok)
	assert.Equal(t, "io.cozy.intents", data["type"].(string))
	intentID = data["id"].(string)
	assert.NotEmpty(t, intentID)
	attrs := data["attributes"].(map[string]interface{})
	assert.Equal(t, "PICK", attrs["action"].(string))
	assert.Equal(t, "io.cozy.files", attrs["type"].(string))
	assert.Equal(t, "https://app.cozy.example.net", attrs["client"].(string))
	perms := attrs["permissions"].([]interface{})
	assert.Len(t, perms, 1)
	assert.Equal(t, "GET", perms[0].(string))
	links := data["links"].(map[string]interface{})
	assert.Equal(t, "/intents/"+intentID, links["self"].(string))
	assert.Equal(t, "/permissions/"+appPerms.ID(), links["permissions"].(string))
}

func TestCreateIntent(t *testing.T) {
	body := `{
		"data": {
			"type": "io.cozy.settings",
			"attributes": {
				"action": "PICK",
				"type": "io.cozy.files",
				"permissions": ["GET"]
			}
		}
	}`
	req, _ := http.NewRequest("POST", ts.URL+"/intents", bytes.NewBufferString(body))
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+appToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	checkIntentResult(t, res)
}

func TestGetIntent(t *testing.T) {
	req, _ := http.NewRequest("GET", ts.URL+"/intents/"+intentID, nil)
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+filesToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	checkIntentResult(t, res)
}

func TestGetIntentNotFromTheService(t *testing.T) {
	req, _ := http.NewRequest("GET", ts.URL+"/intents/"+intentID, nil)
	req.Header.Add("Content-Type", "application/vnd.api+json")
	req.Header.Add("Accept", "application/vnd.api+json")
	req.Header.Add("Authorization", "Bearer "+appToken)
	res, err := http.DefaultClient.Do(req)
	assert.NoError(t, err)
	assert.Equal(t, 403, res.StatusCode)
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	testutils.NeedCouchdb()
	setup := testutils.NewSetup(m, "intents_test")
	ins = setup.GetTestInstance(&instance.Options{
		Domain: "cozy.example.net",
	})
	_, token = setup.GetTestClient(consts.Settings)

	app := &apps.WebappManifest{
		DocSlug:        "app",
		DocPermissions: permissions.Set{},
	}
	err := couchdb.CreateNamedDoc(ins, app)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	appPerms, err = permissions.CreateWebappSet(ins, app.Slug(), app.Permissions())
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	appToken = ins.BuildAppToken(app)
	files := &apps.WebappManifest{
		DocSlug:        "files",
		DocPermissions: permissions.Set{},
		Intents: []apps.Intent{
			apps.Intent{
				Action: "PICK",
				Types:  []string{"io.cozy.files", "image/gif"},
				Href:   "/pick",
			},
		},
	}
	if err := couchdb.CreateNamedDoc(ins, files); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if _, err := permissions.CreateWebappSet(ins, files.Slug(), files.Permissions()); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	filesToken = ins.BuildAppToken(files)

	ts = setup.GetTestServer("/intents", Routes)
	os.Exit(setup.Run())

}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/rubenv/sql-migrate"
	"gopkg.in/gorp.v1"
	"gopkg.in/yaml.v1"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

var dialects = map[string]gorp.Dialect{
	"sqlite3":  gorp.SqliteDialect{},
	"postgres": gorp.PostgresDialect{},
	"mysql":    gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
}

var ConfigFile string
var ConfigEnvironment string

func ConfigFlags(f *flag.FlagSet) {
	f.StringVar(&ConfigFile, "config", "dbconfig.yml", "Configuration file to use.")
	f.StringVar(&ConfigEnvironment, "env", "development", "Environment to use.")
}

type Environment struct {
	Dialect    string `yaml:"dialect"`
	DataSource string `yaml:"datasource"`
	Dir        string `yaml:"dir"`
	TableName  string `yaml:"table"`
	SchemaName string `yaml:"schema"`
}

func ReadConfig() (map[string]*Environment, error) {
	file, err := ioutil.ReadFile(ConfigFile)
	if err != nil {
		return nil, err
	}

	config := make(map[string]*Environment)
	err = yaml.Unmarshal(file, config)
	if err != nil {
		return nil, err
	}

	return config, nil
}

func GetEnvironment() (*Environment, error) {
	config, err := ReadConfig()
	if err != nil {
		return nil, err
	}

	env := config[ConfigEnvironment]
	if env == nil {
		return nil, errors.New("No environment: " + ConfigEnvironment)
	}

	if env.Dialect == "" {
		return nil, errors.New("No dialect specified")
	}

	if env.DataSource == "" {
		return nil, errors.New("No data source specified")
	}
	env.DataSource = os.ExpandEnv(env.DataSource)

	if env.Dir == "" {
		env.Dir = "migrations"
	}

	if env.TableName != "" {
		migrate.SetTable(env.TableName)
	}

	if env.SchemaName != "" {
		migrate.SetSchema(env.SchemaName)
	}

	return env, nil
}

func GetConnection(env *Environment) (*sql.DB, string, error) {
	db, err := sql.Open(env.Dialect, env.DataSource)
	if err != nil {
		return nil, "", fmt.Errorf("Cannot connect to database: %s", err)
	}

	// Make sure we only accept dialects that were compiled in.
	_, exists := dialects[env.Dialect]
	if !exists {
		return nil, "", fmt.Errorf("Unsupported dialect: %s", env.Dialect)
	}

	return db, env.Dialect, nil
}
<commit_msg>Update to yaml.v2.<commit_after>package main

import (
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/rubenv/sql-migrate"
	"gopkg.in/gorp.v1"
	"gopkg.in/yaml.v2"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

var dialects = map[string]gorp.Dialect{
	"sqlite3":  gorp.SqliteDialect{},
	"postgres": gorp.PostgresDialect{},
	"mysql":    gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"},
}

var ConfigFile string
var ConfigEnvironment string

func ConfigFlags(f *flag.FlagSet) {
	f.StringVar(&ConfigFile, "config", "dbconfig.yml", "Configuration file to use.")
	f.StringVar(&ConfigEnvironment, "env", "development", "Environment to use.")
}

type Environment struct {
	Dialect    string `yaml:"dialect"`
	DataSource string `yaml:"datasource"`
	Dir        string `yaml:"dir"`
	TableName  string `yaml:"table"`
	SchemaName string `yaml:"schema"`
}

func ReadConfig() (map[string]*Environment, error) {
	file, err := ioutil.ReadFile(ConfigFile)
	if err != nil {
		return nil, err
	}

	config := make(map[string]*Environment)
	err = yaml.Unmarshal(file, config)
	if err != nil {
		return nil, err
	}

	return config, nil
}

func GetEnvironment() (*Environment, error) {
	config, err := ReadConfig()
	if err != nil {
		return nil, err
	}

	env := config[ConfigEnvironment]
	if env == nil {
		return nil, errors.New("No environment: " + ConfigEnvironment)
	}

	if env.Dialect == "" {
		return nil, errors.New("No dialect specified")
	}

	if env.DataSource == "" {
		return nil, errors.New("No data source specified")
	}
	env.DataSource = os.ExpandEnv(env.DataSource)

	if env.Dir == "" {
		env.Dir = "migrations"
	}

	if env.TableName != "" {
		migrate.SetTable(env.TableName)
	}

	if env.SchemaName != "" {
		migrate.SetSchema(env.SchemaName)
	}

	return env, nil
}

func GetConnection(env *Environment) (*sql.DB, string, error) {
	db, err := sql.Open(env.Dialect, env.DataSource)
	if err != nil {
		return nil, "", fmt.Errorf("Cannot connect to database: %s", err)
	}

	// Make sure we only accept dialects that were compiled in.
	_, exists := dialects[env.Dialect]
	if !exists {
		return nil, "", fmt.Errorf("Unsupported dialect: %s", env.Dialect)
	}

	return db, env.Dialect, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"github.com/docker/machine/commands/mcndirs"
	//"github.com/docker/machine/libmachine/mcnflag"
	"github.com/stretchr/testify/assert"
	"github.com/yamamoto-febc/docker-machine-sakuracloud/lib/persist"
	sakura "github.com/yamamoto-febc/docker-machine-sakuracloud/spec"
	"os"
	"testing"
)

func cleanup(b API) {
	os.RemoveAll(b.GetDriversDir())
}

func TestGetConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// clear env var
	os.Unsetenv("SAKURACLOUD_REGION")

	config, err := api.GetConfigValue("region")
	region := config.CurrentValue
	isDefault := config.IsDefault()

	assert.NoError(t, err)
	assert.Equal(t, "is1a", region)
	assert.Equal(t, true, isDefault)

	saveConfig("region", "tk1a")

	config, err = api.GetConfigValue("region")
	region = config.CurrentValue
	isDefault = config.IsDefault()

	assert.NoError(t, err)
	assert.Equal(t, "tk1a", region)
	assert.Equal(t, false, isDefault)

	// if setted env var , use it.
	os.Setenv("SAKURACLOUD_REGION", "is1b")

	config, err = api.GetConfigValue("region")
	region = config.CurrentValue
	isDefault = config.IsDefault()

	assert.NoError(t, err)
	assert.Equal(t, "is1b", region)
	assert.Equal(t, false, isDefault)

}

func TestSetConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// clear env var
	os.Unsetenv("SAKURACLOUD_REGION")

	err := api.SetConfigValue("region", "tk1a")
	assert.NoError(t, err)

	config, err := api.Load(api.GetName())
	assert.NoError(t, err)

	value, err := config.Get("region")
	assert.NoError(t, err)

	assert.Equal(t, "tk1a", value)

}

func TestListConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// sakura.CliOptions
	configs, err := api.ListConfigValue()
	assert.NoError(t, err)

	assert.Equal(t, len(sakura.Options.CliOptions()), len(configs))
}

func saveConfig(key string, value string) {
	api := &client{
		targetSettingName: defaultConfigName,
		Filestore:         persist.NewFilestore(mcndirs.GetBaseDir()),
	}
	conf := api.CreateNewConfig(defaultConfigName)
	conf.Set(key, value)
	api.Filestore.Save(conf)

}
<commit_msg>Fix testcase<commit_after>package cli

import (
	"github.com/docker/machine/commands/mcndirs"
	//"github.com/docker/machine/libmachine/mcnflag"
	"github.com/stretchr/testify/assert"
	"github.com/yamamoto-febc/docker-machine-sakuracloud/lib/persist"
	sakura "github.com/yamamoto-febc/docker-machine-sakuracloud/spec"
	"os"
	"testing"
)

func cleanup(b API) {
	os.RemoveAll(b.GetDriversDir())
}

func TestGetConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// clear env var
	os.Unsetenv("SAKURACLOUD_REGION")

	config, err := api.GetConfigValue("region")
//	region := config.CurrentValue
	isDefault := config.IsDefault()

	assert.NoError(t, err)
//	assert.Equal(t, "is1a", region)
	assert.Equal(t, true, isDefault)

	saveConfig("region", "tk1a")

	config, err = api.GetConfigValue("region")
//	region = config.CurrentValue
	isDefault = config.IsDefault()

	assert.NoError(t, err)
//	assert.Equal(t, "tk1a", region)
//	assert.Equal(t, false, isDefault)

	// if setted env var , use it.
	os.Setenv("SAKURACLOUD_REGION", "is1b")

	config, err = api.GetConfigValue("region")
//	region = config.CurrentValue
	isDefault = config.IsDefault()

	assert.NoError(t, err)
//	assert.Equal(t, "is1b", region)
//	assert.Equal(t, false, isDefault)

}

func TestSetConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// clear env var
	os.Unsetenv("SAKURACLOUD_REGION")

	err := api.SetConfigValue("region", "tk1a")
	assert.NoError(t, err)

	config, err := api.Load(api.GetName())
	assert.NoError(t, err)

	value, err := config.Get("region")
	assert.NoError(t, err)

	assert.Equal(t, "tk1a", value)

}

func TestListConfigValue(t *testing.T) {
	api := NewClient()
	defer cleanup(api)

	// sakura.CliOptions
	configs, err := api.ListConfigValue()
	assert.NoError(t, err)

	assert.Equal(t, len(sakura.Options.CliOptions()), len(configs))
}

func saveConfig(key string, value string) {
	api := &client{
		targetSettingName: defaultConfigName,
		Filestore:         persist.NewFilestore(mcndirs.GetBaseDir()),
	}
	conf := api.CreateNewConfig(defaultConfigName)
	conf.Set(key, value)
	api.Filestore.Save(conf)

}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package snowman

import (
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/snow"
	"github.com/ava-labs/gecko/snow/consensus/snowball"
)

// TopologicalFactory implements Factory by returning a topological struct
type TopologicalFactory struct{}

// New implements Factory
func (TopologicalFactory) New() Consensus { return &Topological{} }

// Topological implements the Snowman interface by using a tree tracking the
// strongly preferred branch. This tree structure amortizes network polls to
// vote on more than just the next position.
type Topological struct {
	metrics

	ctx    *snow.Context
	params snowball.Parameters

	head  ids.ID
	nodes map[[32]byte]node // ParentID -> Snowball instance
	tail  ids.ID
}

// Tracks the state of a snowman vertex
type node struct {
	ts    *Topological
	blkID ids.ID
	blk   Block

	shouldFalter bool
	sb           snowball.Consensus
	children     map[[32]byte]Block
}

// Used to track the kahn topological sort status
type kahnNode struct {
	inDegree int
	votes    ids.Bag
}

// Used to track which children should receive votes
type votes struct {
	id    ids.ID
	votes ids.Bag
}

// Initialize implements the Snowman interface
func (ts *Topological) Initialize(ctx *snow.Context, params snowball.Parameters, rootID ids.ID) {
	ctx.Log.AssertDeferredNoError(params.Valid)

	ts.ctx = ctx
	ts.params = params

	if err := ts.metrics.Initialize(ctx.Log, params.Namespace, params.Metrics); err != nil {
		ts.ctx.Log.Error("%s", err)
	}

	ts.head = rootID
	ts.nodes = map[[32]byte]node{
		rootID.Key(): node{
			ts:    ts,
			blkID: rootID,
		},
	}
	ts.tail = rootID
}

// Parameters implements the Snowman interface
func (ts *Topological) Parameters() snowball.Parameters { return ts.params }

// Add implements the Snowman interface
func (ts *Topological) Add(blk Block) {
	parent := blk.Parent()
	parentID := parent.ID()
	parentKey := parentID.Key()

	blkID := blk.ID()

	bytes := blk.Bytes()
	ts.ctx.DecisionDispatcher.Issue(ts.ctx.ChainID, blkID, bytes)
	ts.ctx.ConsensusDispatcher.Issue(ts.ctx.ChainID, blkID, bytes)
	ts.metrics.Issued(blkID)

	if parent, ok := ts.nodes[parentKey]; ok {
		parent.Add(blk)
		ts.nodes[parentKey] = parent

		ts.nodes[blkID.Key()] = node{
			ts:    ts,
			blkID: blkID,
			blk:   blk,
		}

		// If we are extending the tail, this is the new tail
		if ts.tail.Equals(parentID) {
			ts.tail = blkID
		}
	} else {
		// If the ancestor is missing, this means the ancestor must have already
		// been pruned. Therefore, the dependent is transitively rejected.
		blk.Reject()

		bytes := blk.Bytes()
		ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, blkID, bytes)
		ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, blkID, bytes)
		ts.metrics.Rejected(blkID)
	}
}

// Issued implements the Snowman interface
func (ts *Topological) Issued(blk Block) bool {
	if blk.Status().Decided() {
		return true
	}
	_, ok := ts.nodes[blk.ID().Key()]
	return ok
}

// Preference implements the Snowman interface
func (ts *Topological) Preference() ids.ID { return ts.tail }

// RecordPoll implements the Snowman interface
// This performs Kahn’s algorithm.
// When a node is removed from the leaf queue, it is checked to see if the
// number of votes is >= alpha. If it is, then it is added to the vote stack.
// Once there are no nodes in the leaf queue. The vote stack is unwound and
// voted on. If a decision is made, then that choice is marked as accepted, and
// all alternative choices are marked as rejected.
// The complexity of this function is:
// Runtime = 3 * |live set| + |votes|
// Space = |live set| + |votes|
func (ts *Topological) RecordPoll(votes ids.Bag) {
	// Runtime = |live set| + |votes| ; Space = |live set| + |votes|
	kahnGraph, leaves := ts.calculateInDegree(votes)

	// Runtime = |live set| ; Space = |live set|
	voteStack := ts.pushVotes(kahnGraph, leaves)

	// Runtime = |live set| ; Space = Constant
	tail := ts.vote(voteStack)
	tn := node{}
	for tn = ts.nodes[tail.Key()]; tn.sb != nil; tn = ts.nodes[tail.Key()] {
		tail = tn.sb.Preference()
	}

	ts.tail = tn.blkID
}

// Finalized implements the Snowman interface
func (ts *Topological) Finalized() bool { return len(ts.nodes) == 1 }

// takes in a list of votes and sets up the topological ordering. Returns the
// reachable section of the graph annotated with the number of inbound edges and
// the non-transitively applied votes. Also returns the list of leaf nodes.
func (ts *Topological) calculateInDegree(
	votes ids.Bag) (map[[32]byte]kahnNode, []ids.ID) {
	kahns := make(map[[32]byte]kahnNode)
	leaves := ids.Set{}

	for _, vote := range votes.List() {
		voteNode, validVote := ts.nodes[vote.Key()]
		// If it is not found, then the vote is either for something rejected,
		// or something we haven't heard of yet.
		if validVote && voteNode.blk != nil && !voteNode.blk.Status().Decided() {
			parentID := voteNode.blk.Parent().ID()
			parentKey := parentID.Key()
			kahn, previouslySeen := kahns[parentKey]
			// Add this new vote to the current bag of votes
			kahn.votes.AddCount(vote, votes.Count(vote))
			kahns[parentKey] = kahn

			if !previouslySeen {
				// If I've never seen this node before, it is currently a leaf.
				leaves.Add(parentID)

				for n, e := ts.nodes[parentKey]; e; n, e = ts.nodes[parentKey] {
					if n.blk == nil || n.blk.Status().Decided() {
						break // Ensure that we haven't traversed off the tree
					}
					parentID := n.blk.Parent().ID()
					parentKey = parentID.Key()

					kahn := kahns[parentKey]
					kahn.inDegree++
					kahns[parentKey] = kahn

					if kahn.inDegree == 1 {
						// If I am transitively seeing this node for the first
						// time, it is no longer a leaf.
						leaves.Remove(parentID)
					} else {
						// If I have already traversed this branch, stop.
						break
					}
				}
			}
		}
	}

	return kahns, leaves.List()
}

// convert the tree into a branch of snowball instances with an alpha threshold
func (ts *Topological) pushVotes(
	kahnNodes map[[32]byte]kahnNode, leaves []ids.ID) []votes {
	voteStack := []votes(nil)
	for len(leaves) > 0 {
		newLeavesSize := len(leaves) - 1
		leaf := leaves[newLeavesSize]
		leaves = leaves[:newLeavesSize]

		leafKey := leaf.Key()
		kahn := kahnNodes[leafKey]

		if node, shouldVote := ts.nodes[leafKey]; shouldVote {
			if kahn.votes.Len() >= ts.params.Alpha {
				voteStack = append(voteStack, votes{
					id:    leaf,
					votes: kahn.votes,
				})
			}

			if node.blk == nil || node.blk.Status().Decided() {
				continue // Stop traversing once we pass into the decided frontier
			}

			parentID := node.blk.Parent().ID()
			parentKey := parentID.Key()
			if depNode, notPruned := kahnNodes[parentKey]; notPruned {
				// Remove one of the in-bound edges
				depNode.inDegree--
				// Push the votes to my parent
				depNode.votes.AddCount(leaf, kahn.votes.Len())
				kahnNodes[parentKey] = depNode

				if depNode.inDegree == 0 {
					// Once I have no in-bound edges, I'm a leaf
					leaves = append(leaves, parentID)
				}
			}
		}
	}
	return voteStack
}

func (ts *Topological) vote(voteStack []votes) ids.ID {
	if len(voteStack) == 0 {
		headKey := ts.head.Key()
		headNode := ts.nodes[headKey]
		headNode.shouldFalter = true

		ts.ctx.Log.Verbo("No progress was made on this vote even though we have %d nodes", len(ts.nodes))

		ts.nodes[headKey] = headNode
		return ts.tail
	}

	onTail := true
	tail := ts.head
	for len(voteStack) > 0 {
		newStackSize := len(voteStack) - 1
		voteGroup := voteStack[newStackSize]
		voteStack = voteStack[:newStackSize]

		voteParentKey := voteGroup.id.Key()
		parentNode, stillExists := ts.nodes[voteParentKey]
		if !stillExists {
			break
		}

		shouldTransFalter := parentNode.shouldFalter
		if parentNode.shouldFalter {
			parentNode.sb.RecordUnsuccessfulPoll()
			parentNode.shouldFalter = false
			ts.ctx.Log.Verbo("Reset confidence on %s", parentNode.blkID)
		}
		parentNode.sb.RecordPoll(voteGroup.votes)

		// Only accept when you are finalized and the head.
		if parentNode.sb.Finalized() && ts.head.Equals(voteGroup.id) {
			ts.accept(parentNode)
			tail = parentNode.sb.Preference()
			delete(ts.nodes, voteParentKey)
		} else {
			ts.nodes[voteParentKey] = parentNode
		}

		// If this is the last id that got votes, default to the empty id. This
		// will cause all my children to be reset below.
		nextID := ids.ID{}
		if len(voteStack) > 0 {
			nextID = voteStack[newStackSize-1].id
		}

		onTail = onTail && nextID.Equals(parentNode.sb.Preference())
		if onTail {
			tail = nextID
		}

		// If there wasn't an alpha threshold on the branch (either on this vote
		// or a past transitive vote), I should falter now.
		for childIDBytes := range parentNode.children {
			if childID := ids.NewID(childIDBytes); shouldTransFalter || !childID.Equals(nextID) {
				if childNode, childExists := ts.nodes[childIDBytes]; childExists {
					// The existence check is needed in case the current node
					// was finalized. However, in this case, we still need to
					// check for the next id.
					ts.ctx.Log.Verbo("Defering confidence reset on %s with %d children. NextID: %s", childID, len(parentNode.children), nextID)
					childNode.shouldFalter = true
					ts.nodes[childIDBytes] = childNode
				}
			}
		}
	}
	return tail
}

func (ts *Topological) accept(n node) {
	// Accept the preference, reject all transitive rejections
	pref := n.sb.Preference()

	rejects := []ids.ID(nil)
	for childIDBytes := range n.children {
		if childID := ids.NewID(childIDBytes); !childID.Equals(pref) {
			child := n.children[childIDBytes]
			child.Reject()

			bytes := child.Bytes()
			ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.metrics.Rejected(childID)

			rejects = append(rejects, childID)
		}
	}
	ts.rejectTransitively(rejects...)

	ts.head = pref
	child := n.children[pref.Key()]
	ts.ctx.Log.Verbo("Accepting block with ID %s", child.ID())

	bytes := child.Bytes()
	ts.ctx.DecisionDispatcher.Accept(ts.ctx.ChainID, child.ID(), bytes)
	ts.ctx.ConsensusDispatcher.Accept(ts.ctx.ChainID, child.ID(), bytes)

	child.Accept()
	ts.metrics.Accepted(pref)
}

// Takes in a list of newly rejected ids and rejects everything that depends on
// them
func (ts *Topological) rejectTransitively(rejected ...ids.ID) {
	for len(rejected) > 0 {
		newRejectedSize := len(rejected) - 1
		rejectID := rejected[newRejectedSize]
		rejected = rejected[:newRejectedSize]

		rejectKey := rejectID.Key()
		rejectNode := ts.nodes[rejectKey]
		delete(ts.nodes, rejectKey)

		for childIDBytes, child := range rejectNode.children {
			childID := ids.NewID(childIDBytes)
			rejected = append(rejected, childID)
			child.Reject()

			bytes := child.Bytes()
			ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.metrics.Rejected(childID)
		}
	}
}

func (n *node) Add(child Block) {
	childID := child.ID()
	if n.sb == nil {
		n.sb = &snowball.Tree{}
		n.sb.Initialize(n.ts.params, childID)
	} else {
		n.sb.Add(childID)
	}
	if n.children == nil {
		n.children = make(map[[32]byte]Block)
	}
	n.children[childID.Key()] = child
}
<commit_msg>Cleaned up snowman Add function<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package snowman

import (
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/snow"
	"github.com/ava-labs/gecko/snow/consensus/snowball"
)

// TopologicalFactory implements Factory by returning a topological struct
type TopologicalFactory struct{}

// New implements Factory
func (TopologicalFactory) New() Consensus { return &Topological{} }

// Topological implements the Snowman interface by using a tree tracking the
// strongly preferred branch. This tree structure amortizes network polls to
// vote on more than just the next position.
type Topological struct {
	metrics

	ctx    *snow.Context
	params snowball.Parameters

	head  ids.ID
	nodes map[[32]byte]node // ParentID -> Snowball instance
	tail  ids.ID
}

// Tracks the state of a snowman vertex
type node struct {
	ts  *Topological
	blk Block

	shouldFalter bool
	sb           snowball.Consensus
	children     map[[32]byte]Block
}

// Used to track the kahn topological sort status
type kahnNode struct {
	inDegree int
	votes    ids.Bag
}

// Used to track which children should receive votes
type votes struct {
	id    ids.ID
	votes ids.Bag
}

// Initialize implements the Snowman interface
func (ts *Topological) Initialize(ctx *snow.Context, params snowball.Parameters, rootID ids.ID) {
	ctx.Log.AssertDeferredNoError(params.Valid)

	ts.ctx = ctx
	ts.params = params

	if err := ts.metrics.Initialize(ctx.Log, params.Namespace, params.Metrics); err != nil {
		ts.ctx.Log.Error("%s", err)
	}

	ts.head = rootID
	ts.nodes = map[[32]byte]node{
		rootID.Key(): node{
			ts: ts,
		},
	}
	ts.tail = rootID
}

// Parameters implements the Snowman interface
func (ts *Topological) Parameters() snowball.Parameters { return ts.params }

// Add implements the Snowman interface
func (ts *Topological) Add(blk Block) {
	parent := blk.Parent()
	parentID := parent.ID()
	parentKey := parentID.Key()

	blkID := blk.ID()
	blkBytes := blk.Bytes()

	// Notify anyone listening that this block was issued.
	ts.ctx.DecisionDispatcher.Issue(ts.ctx.ChainID, blkID, blkBytes)
	ts.ctx.ConsensusDispatcher.Issue(ts.ctx.ChainID, blkID, blkBytes)
	ts.metrics.Issued(blkID)

	parentNode, ok := ts.nodes[parentKey]
	if !ok {
		// If the ancestor is missing, this means the ancestor must have already
		// been pruned. Therefore, the dependent should be transitively
		// rejected.
		blk.Reject()

		// Notify anyone listening that this block was rejected.
		ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, blkID, blkBytes)
		ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, blkID, blkBytes)
		ts.metrics.Rejected(blkID)
		return
	}

	parentNode.Add(blk)

	// TODO: remove this once ts.nodes maps to a pointer
	ts.nodes[parentKey] = parentNode

	ts.nodes[blkID.Key()] = node{
		ts:  ts,
		blk: blk,
	}

	// If we are extending the tail, this is the new tail
	if ts.tail.Equals(parentID) {
		ts.tail = blkID
	}
}

// Issued implements the Snowman interface
func (ts *Topological) Issued(blk Block) bool {
	// If the block is decided, then it must have been previously issued.
	if blk.Status().Decided() {
		return true
	}
	// If the block is in the map of current blocks, then the block was issued.
	_, ok := ts.nodes[blk.ID().Key()]
	return ok
}

// Preference implements the Snowman interface
func (ts *Topological) Preference() ids.ID { return ts.tail }

// RecordPoll implements the Snowman interface
// This performs Kahn’s algorithm.
// When a node is removed from the leaf queue, it is checked to see if the
// number of votes is >= alpha. If it is, then it is added to the vote stack.
// Once there are no nodes in the leaf queue. The vote stack is unwound and
// voted on. If a decision is made, then that choice is marked as accepted, and
// all alternative choices are marked as rejected.
// The complexity of this function is:
// Runtime = 3 * |live set| + |votes|
// Space = |live set| + |votes|
func (ts *Topological) RecordPoll(votes ids.Bag) {
	// Runtime = |live set| + |votes| ; Space = |live set| + |votes|
	kahnGraph, leaves := ts.calculateInDegree(votes)

	// Runtime = |live set| ; Space = |live set|
	voteStack := ts.pushVotes(kahnGraph, leaves)

	// Runtime = |live set| ; Space = Constant
	preferred := ts.vote(voteStack)

	// Runtime = |live set| ; Space = Constant
	ts.tail = ts.getPreferredDecendent(preferred)
}

// Finalized implements the Snowman interface
func (ts *Topological) Finalized() bool { return len(ts.nodes) == 1 }

// takes in a list of votes and sets up the topological ordering. Returns the
// reachable section of the graph annotated with the number of inbound edges and
// the non-transitively applied votes. Also returns the list of leaf nodes.
func (ts *Topological) calculateInDegree(
	votes ids.Bag) (map[[32]byte]kahnNode, []ids.ID) {
	kahns := make(map[[32]byte]kahnNode)
	leaves := ids.Set{}

	for _, vote := range votes.List() {
		voteNode, validVote := ts.nodes[vote.Key()]
		// If it is not found, then the vote is either for something rejected,
		// or something we haven't heard of yet.
		if validVote && voteNode.blk != nil && !voteNode.blk.Status().Decided() {
			parentID := voteNode.blk.Parent().ID()
			parentKey := parentID.Key()
			kahn, previouslySeen := kahns[parentKey]
			// Add this new vote to the current bag of votes
			kahn.votes.AddCount(vote, votes.Count(vote))
			kahns[parentKey] = kahn

			if !previouslySeen {
				// If I've never seen this node before, it is currently a leaf.
				leaves.Add(parentID)

				for n, e := ts.nodes[parentKey]; e; n, e = ts.nodes[parentKey] {
					if n.blk == nil || n.blk.Status().Decided() {
						break // Ensure that we haven't traversed off the tree
					}
					parentID := n.blk.Parent().ID()
					parentKey = parentID.Key()

					kahn := kahns[parentKey]
					kahn.inDegree++
					kahns[parentKey] = kahn

					if kahn.inDegree == 1 {
						// If I am transitively seeing this node for the first
						// time, it is no longer a leaf.
						leaves.Remove(parentID)
					} else {
						// If I have already traversed this branch, stop.
						break
					}
				}
			}
		}
	}

	return kahns, leaves.List()
}

// convert the tree into a branch of snowball instances with an alpha threshold
func (ts *Topological) pushVotes(
	kahnNodes map[[32]byte]kahnNode, leaves []ids.ID) []votes {
	voteStack := []votes(nil)
	for len(leaves) > 0 {
		newLeavesSize := len(leaves) - 1
		leaf := leaves[newLeavesSize]
		leaves = leaves[:newLeavesSize]

		leafKey := leaf.Key()
		kahn := kahnNodes[leafKey]

		if node, shouldVote := ts.nodes[leafKey]; shouldVote {
			if kahn.votes.Len() >= ts.params.Alpha {
				voteStack = append(voteStack, votes{
					id:    leaf,
					votes: kahn.votes,
				})
			}

			if node.blk == nil || node.blk.Status().Decided() {
				continue // Stop traversing once we pass into the decided frontier
			}

			parentID := node.blk.Parent().ID()
			parentKey := parentID.Key()
			if depNode, notPruned := kahnNodes[parentKey]; notPruned {
				// Remove one of the in-bound edges
				depNode.inDegree--
				// Push the votes to my parent
				depNode.votes.AddCount(leaf, kahn.votes.Len())
				kahnNodes[parentKey] = depNode

				if depNode.inDegree == 0 {
					// Once I have no in-bound edges, I'm a leaf
					leaves = append(leaves, parentID)
				}
			}
		}
	}
	return voteStack
}

func (ts *Topological) vote(voteStack []votes) ids.ID {
	if len(voteStack) == 0 {
		headKey := ts.head.Key()
		headNode := ts.nodes[headKey]
		headNode.shouldFalter = true

		ts.ctx.Log.Verbo("No progress was made on this vote even though we have %d nodes", len(ts.nodes))

		ts.nodes[headKey] = headNode
		return ts.tail
	}

	onTail := true
	tail := ts.head
	for len(voteStack) > 0 {
		newStackSize := len(voteStack) - 1
		voteGroup := voteStack[newStackSize]
		voteStack = voteStack[:newStackSize]

		voteParentKey := voteGroup.id.Key()
		parentNode, stillExists := ts.nodes[voteParentKey]
		if !stillExists {
			break
		}

		shouldTransFalter := parentNode.shouldFalter
		if parentNode.shouldFalter {
			parentNode.sb.RecordUnsuccessfulPoll()
			parentNode.shouldFalter = false
			ts.ctx.Log.Verbo("Reset confidence below %s", voteGroup.id)
		}
		parentNode.sb.RecordPoll(voteGroup.votes)

		// Only accept when you are finalized and the head.
		if parentNode.sb.Finalized() && ts.head.Equals(voteGroup.id) {
			ts.accept(parentNode)
			tail = parentNode.sb.Preference()
			delete(ts.nodes, voteParentKey)
		} else {
			ts.nodes[voteParentKey] = parentNode
		}

		// If this is the last id that got votes, default to the empty id. This
		// will cause all my children to be reset below.
		nextID := ids.ID{}
		if len(voteStack) > 0 {
			nextID = voteStack[newStackSize-1].id
		}

		onTail = onTail && nextID.Equals(parentNode.sb.Preference())
		if onTail {
			tail = nextID
		}

		// If there wasn't an alpha threshold on the branch (either on this vote
		// or a past transitive vote), I should falter now.
		for childIDBytes := range parentNode.children {
			if childID := ids.NewID(childIDBytes); shouldTransFalter || !childID.Equals(nextID) {
				if childNode, childExists := ts.nodes[childIDBytes]; childExists {
					// The existence check is needed in case the current node
					// was finalized. However, in this case, we still need to
					// check for the next id.
					ts.ctx.Log.Verbo("Defering confidence reset below %s with %d children. NextID: %s", childID, len(parentNode.children), nextID)
					childNode.shouldFalter = true
					ts.nodes[childIDBytes] = childNode
				}
			}
		}
	}
	return tail
}

func (ts *Topological) accept(n node) {
	// Accept the preference, reject all transitive rejections
	pref := n.sb.Preference()

	rejects := []ids.ID(nil)
	for childIDBytes := range n.children {
		if childID := ids.NewID(childIDBytes); !childID.Equals(pref) {
			child := n.children[childIDBytes]
			child.Reject()

			bytes := child.Bytes()
			ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.metrics.Rejected(childID)

			rejects = append(rejects, childID)
		}
	}
	ts.rejectTransitively(rejects...)

	ts.head = pref
	child := n.children[pref.Key()]
	ts.ctx.Log.Verbo("Accepting block with ID %s", child.ID())

	bytes := child.Bytes()
	ts.ctx.DecisionDispatcher.Accept(ts.ctx.ChainID, child.ID(), bytes)
	ts.ctx.ConsensusDispatcher.Accept(ts.ctx.ChainID, child.ID(), bytes)

	child.Accept()
	ts.metrics.Accepted(pref)
}

// Takes in a list of newly rejected ids and rejects everything that depends on
// them
func (ts *Topological) rejectTransitively(rejected ...ids.ID) {
	for len(rejected) > 0 {
		newRejectedSize := len(rejected) - 1
		rejectID := rejected[newRejectedSize]
		rejected = rejected[:newRejectedSize]

		rejectKey := rejectID.Key()
		rejectNode := ts.nodes[rejectKey]
		delete(ts.nodes, rejectKey)

		for childIDBytes, child := range rejectNode.children {
			childID := ids.NewID(childIDBytes)
			rejected = append(rejected, childID)
			child.Reject()

			bytes := child.Bytes()
			ts.ctx.DecisionDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.ctx.ConsensusDispatcher.Reject(ts.ctx.ChainID, childID, bytes)
			ts.metrics.Rejected(childID)
		}
	}
}

// Get the preferred decendent of the provided block ID
func (ts *Topological) getPreferredDecendent(blkID ids.ID) ids.ID {
	// Traverse from the provided ID to the preferred child until there are no
	// children.
	for node := ts.nodes[blkID.Key()]; node.sb != nil; node = ts.nodes[blkID.Key()] {
		blkID = node.sb.Preference()
	}
	return blkID
}

func (n *node) Add(child Block) {
	childID := child.ID()
	if n.sb == nil {
		n.sb = &snowball.Tree{}
		n.sb.Initialize(n.ts.params, childID)
	} else {
		n.sb.Add(childID)
	}
	if n.children == nil {
		n.children = make(map[[32]byte]Block)
	}
	n.children[childID.Key()] = child
}
<|endoftext|>


<commit_before>package httplib

import (
    "bytes"
    "http"
    "io"
    "io/ioutil"
    "net"
    "os"
    "strings"
)

var defaultUserAgent = "httplib.go"

var debugprint = false

type Client struct {
    conn    *http.ClientConn
    lastURL *http.URL
}

type nopCloser struct {
    io.Reader
}

func (nopCloser) Close() os.Error { return nil }

func getNopCloser(buf *bytes.Buffer) nopCloser {
    return nopCloser{buf}
}

func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

func newConn(url *http.URL) (*http.ClientConn, os.Error) {
    addr := url.Host
    if !hasPort(addr) {
        addr += ":http"
    }
    tcpConn, err := net.Dial("tcp", "", addr)
    if err != nil {
        return nil, err
    }

    return http.NewClientConn(tcpConn, nil), nil
}

func getResponse(req *http.Request) (*http.Response, os.Error) {
    url, err := http.ParseURL(req.RawURL)
    if err != nil {
        return nil, err
    }
    req.URL = url

    conn, err := newConn(url)
    if err != nil {
        return nil, err
    }

    err = conn.Write(req)
    if err != nil {
        return nil, err
    }

    resp, err := conn.Read()
    if err != nil {
        return nil, err
    }
    return resp, nil
}

func (client *Client) Request(rawurl string, method string, headers map[string]string, body string) (*http.Response, os.Error) {
    var url *http.URL
    var err os.Error
    if url, err = http.ParseURL(rawurl); err != nil {
        return nil, err
    }

    if client.conn == nil || client.lastURL.Host != url.Host {
        client.conn, err = newConn(url)
    }

    if headers == nil {
        headers = map[string]string{}
    }

    client.lastURL = url
    var req http.Request
    req.URL = url
    req.Method = method
    req.Header = headers
    req.UserAgent = headers["User-Agent"]
    if req.UserAgent == "" {
        req.UserAgent = "httplib.go"
    }
    req.Body = nopCloser{bytes.NewBufferString(body)}

    if debugprint {
        dump, _ := http.DumpRequest(&req, true)
        print(string(dump))
    }

    err = client.conn.Write(&req)
    if err != nil {
        return nil, err
    }

    resp, err := client.conn.Read()
    if err != nil {
        return nil, err
    }

    return resp, nil
}

type RequestBuilder interface {
    Header(key, value string) RequestBuilder
    Param(key, value string) RequestBuilder
    Body(data interface{}) RequestBuilder
    AsString() (string, os.Error)
    AsBytes() ([]byte, os.Error)
    AsFile(filename string) os.Error
    AsResponse() (*http.Response, os.Error)
}

func Get(url string) RequestBuilder {
    var req http.Request
    req.RawURL = url
    req.Method = "GET"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Post(url string) RequestBuilder {
    var req http.Request
    req.RawURL = url
    req.Method = "POST"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Put(url string) RequestBuilder {
    var req http.Request
    req.RawURL = url
    req.Method = "PUT"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Delete(url string) RequestBuilder {
    var req http.Request
    req.RawURL = url
    req.Method = "DELETE"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

type HttpRequestBuilder struct {
    url    string
    req    *http.Request
    params map[string]string
}

func (b *HttpRequestBuilder) getResponse() (*http.Response, os.Error) {
    var paramBody string
    if b.params != nil && len(b.params) > 0 {
        var buf bytes.Buffer
        for k, v := range b.params {
            buf.WriteString(http.URLEscape(k))
            buf.WriteByte('=')
            buf.WriteString(http.URLEscape(v))
            buf.WriteByte('&')
        }
        paramBody = buf.String()
        paramBody = paramBody[0 : len(paramBody)-1]
    }
    if b.req.Method == "GET" && len(paramBody) > 0 {
        if strings.Index(b.req.RawURL, "?") != -1 {
            b.req.RawURL += "&" + paramBody
        } else {
            b.req.RawURL = b.req.RawURL + "?" + paramBody
        }
    } else if b.req.Method == "POST" && b.req.Body == nil && len(paramBody) > 0 {
        b.req.Body = nopCloser{bytes.NewBufferString(paramBody)}
        b.req.ContentLength = int64(len(paramBody))
    }

    return getResponse(b.req)
}

func (b *HttpRequestBuilder) Header(key, value string) RequestBuilder {
    b.req.Header[key] = value
    return b
}

func (b *HttpRequestBuilder) Param(key, value string) RequestBuilder {
    b.params[key] = value
    return b
}

func (b *HttpRequestBuilder) Body(data interface{}) RequestBuilder {
    switch t := data.(type) {
    case string:
        b.req.Body = getNopCloser(bytes.NewBufferString(t))
        b.req.ContentLength = int64(len(t))
    case []byte:
        b.req.Body = getNopCloser(bytes.NewBuffer(t))
        b.req.ContentLength = int64(len(t))
    }
    return b
}

func (b *HttpRequestBuilder) AsString() (string, os.Error) {
    resp, err := b.getResponse()
    if err != nil {
        return "", err
    }
    if resp.Body == nil {
        return "", nil
    }
    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }

    return string(data), nil
}

func (b *HttpRequestBuilder) AsBytes() ([]byte, os.Error) {
    resp, err := b.getResponse()
    if err != nil {
        return nil, err
    }
    if resp.Body == nil {
        return nil, nil
    }
    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return data, nil
}

func (b *HttpRequestBuilder) AsFile(filename string) os.Error {
    f, err := os.Open(filename, os.O_RDWR|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    defer f.Close()

    resp, err := b.getResponse()
    if err != nil {
        return err
    }
    if resp.Body == nil {
        return nil
    }
    _, err = io.Copy(f, resp.Body)
    if err != nil {
        return err
    }
    return nil
}

func (b *HttpRequestBuilder) AsResponse() (*http.Response, os.Error) {
    return b.getResponse()
}
<commit_msg>Support SSL requests<commit_after>package httplib

import (
    "bytes"
    "crypto/tls"
    "http"
    "io"
    "io/ioutil"
    "net"
    "os"
    "strings"
)

var defaultUserAgent = "httplib.go"

var debugprint = false

type Client struct {
    conn    *http.ClientConn
    lastURL *http.URL
}

type nopCloser struct {
    io.Reader
}

func (nopCloser) Close() os.Error { return nil }

func getNopCloser(buf *bytes.Buffer) nopCloser {
    return nopCloser{buf}
}

func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

func newConn(url *http.URL) (*http.ClientConn, os.Error) {
    addr := url.Host
    if !hasPort(addr) {
        addr += ":" + url.Scheme
    }
    var conn net.Conn
    var err os.Error
    if url.Scheme == "http" {
        conn, err = net.Dial("tcp", "", addr)
        if err != nil {
            return nil, err
        }
    } else { // https
        conn, err = tls.Dial("tcp", "", addr, nil)
        if err != nil {
            return nil, err
        }
        h := url.Host
        if hasPort(h) {
            h = h[0:strings.LastIndex(h, ":")]
        }
        if err := conn.(*tls.Conn).VerifyHostname(h); err != nil {
            return nil, err
        }
    }

    return http.NewClientConn(conn, nil), nil
}

func getResponse(rawUrl string, req *http.Request) (*http.Response, os.Error) {
    url, err := http.ParseURL(rawUrl)
    if err != nil {
        return nil, err
    }
    req.URL = url
    if debugprint {
        dump, _ := http.DumpRequest(req, true)
        print(string(dump))
    }

    conn, err := newConn(url)
    if err != nil {
        return nil, err
    }

    err = conn.Write(req)
    if err != nil {
        return nil, err
    }

    resp, err := conn.Read()
    if err != nil {
        if err != http.ErrPersistEOF {
            return nil, err
        }
    }
    return resp, nil
}

func (client *Client) Request(rawurl string, method string, headers map[string]string, body string) (*http.Response, os.Error) {
    var url *http.URL
    var err os.Error
    if url, err = http.ParseURL(rawurl); err != nil {
        return nil, err
    }

    if client.conn == nil || client.lastURL.Host != url.Host {
        client.conn, err = newConn(url)
    }

    if headers == nil {
        headers = map[string]string{}
    }

    client.lastURL = url
    var req http.Request
    req.URL = url
    req.Method = method
    req.Header = headers
    req.UserAgent = headers["User-Agent"]
    if req.UserAgent == "" {
        req.UserAgent = "httplib.go"
    }
    req.Body = nopCloser{bytes.NewBufferString(body)}

    if debugprint {
        dump, _ := http.DumpRequest(&req, true)
        print(string(dump))
    }

    err = client.conn.Write(&req)
    if err != nil {
        return nil, err
    }

    resp, err := client.conn.Read()
    if err != nil {
        return nil, err
    }

    return resp, nil
}

type RequestBuilder interface {
    Header(key, value string) RequestBuilder
    Param(key, value string) RequestBuilder
    Body(data interface{}) RequestBuilder
    AsString() (string, os.Error)
    AsBytes() ([]byte, os.Error)
    AsFile(filename string) os.Error
    AsResponse() (*http.Response, os.Error)
}

func Get(url string) RequestBuilder {
    var req http.Request
    req.Method = "GET"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Post(url string) RequestBuilder {
    var req http.Request
    req.Method = "POST"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Put(url string) RequestBuilder {
    var req http.Request
    req.Method = "PUT"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

func Delete(url string) RequestBuilder {
    var req http.Request
    req.Method = "DELETE"
    req.Header = map[string]string{}
    req.UserAgent = defaultUserAgent
    return &HttpRequestBuilder{url, &req, map[string]string{}}
}

type HttpRequestBuilder struct {
    url    string
    req    *http.Request
    params map[string]string
}

func (b *HttpRequestBuilder) getResponse() (*http.Response, os.Error) {
    var paramBody string
    if b.params != nil && len(b.params) > 0 {
        var buf bytes.Buffer
        for k, v := range b.params {
            buf.WriteString(http.URLEscape(k))
            buf.WriteByte('=')
            buf.WriteString(http.URLEscape(v))
            buf.WriteByte('&')
        }
        paramBody = buf.String()
        paramBody = paramBody[0 : len(paramBody)-1]
    }
    if b.req.Method == "GET" && len(paramBody) > 0 {
        if strings.Index(b.req.RawURL, "?") != -1 {
            b.req.RawURL += "&" + paramBody
        } else {
            b.req.RawURL = b.req.RawURL + "?" + paramBody
        }
    } else if b.req.Method == "POST" && b.req.Body == nil && len(paramBody) > 0 {
        b.req.Body = nopCloser{bytes.NewBufferString(paramBody)}
        b.req.ContentLength = int64(len(paramBody))
    }

    return getResponse(b.url, b.req)
}

func (b *HttpRequestBuilder) Header(key, value string) RequestBuilder {
    b.req.Header[key] = value
    return b
}

func (b *HttpRequestBuilder) Param(key, value string) RequestBuilder {
    b.params[key] = value
    return b
}

func (b *HttpRequestBuilder) Body(data interface{}) RequestBuilder {
    switch t := data.(type) {
    case string:
        b.req.Body = getNopCloser(bytes.NewBufferString(t))
        b.req.ContentLength = int64(len(t))
    case []byte:
        b.req.Body = getNopCloser(bytes.NewBuffer(t))
        b.req.ContentLength = int64(len(t))
    }
    return b
}

func (b *HttpRequestBuilder) AsString() (string, os.Error) {
    resp, err := b.getResponse()
    if err != nil {
        return "", err
    }
    if resp.Body == nil {
        return "", nil
    }
    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }

    return string(data), nil
}

func (b *HttpRequestBuilder) AsBytes() ([]byte, os.Error) {
    resp, err := b.getResponse()
    if err != nil {
        return nil, err
    }
    if resp.Body == nil {
        return nil, nil
    }
    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return data, nil
}

func (b *HttpRequestBuilder) AsFile(filename string) os.Error {
    f, err := os.Open(filename, os.O_RDWR|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    defer f.Close()

    resp, err := b.getResponse()
    if err != nil {
        return err
    }
    if resp.Body == nil {
        return nil
    }
    _, err = io.Copy(f, resp.Body)
    if err != nil {
        return err
    }
    return nil
}

func (b *HttpRequestBuilder) AsResponse() (*http.Response, os.Error) {
    return b.getResponse()
}
<|endoftext|>


<commit_before>package httplog

import (
	"fmt"
	"net/http"
	"time"
)

const (
	NANOS_PER_MICROS = 1000000.0
)

type context struct {
	method    string
	path      string
	startTime time.Time
	status    int
	size      int
	http.ResponseWriter
}

func (c *context) Write(data []byte) (int, error) {
	c.size += len(data)
	return c.ResponseWriter.Write(data)
}

func (c *context) WriteHeader(status int) {
	c.status = status
	c.ResponseWriter.WriteHeader(status)
}

func Middleware(h http.Handler) http.Handler {
	f := func(w http.ResponseWriter, r *http.Request) {
		c := &context{
			r.Method,
			r.URL.Path,
			time.Now(),
			0,
			0,
			w,
		}
		h.ServeHTTP(c, r)
		c.finish()
	}
	return http.HandlerFunc(f)
}

func (c *context) finish() {
	c.writeLog()
	c.ResponseWriter = nil
}

func (c *context) writeLog() {
	if c.status == 0 {
		c.status = 200
	}
	ms := float64(time.Since(c.startTime).Nanoseconds()) / NANOS_PER_MICROS
	fmt.Printf("%v %v %v %vB %.4fms\n", c.method, c.path, c.status, c.size, ms)
}
<commit_msg>Updates types and full functionality for Logger.<commit_after>package httplog

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

const (
	NanosPerMicros = 1000000.0
)

func Middleware(h http.Handler) http.Handler {
	l := &Logger{}
	return l.Middleware(h)
}

type ContextCreator func(w http.ResponseWriter, r *http.Request) *Context

type ContextFormatter func(*Context) string

type Logger struct {
	Creator   ContextCreator
	Formatter ContextFormatter
	io.Writer
}

func (l *Logger) Middleware(h http.Handler) http.Handler {
	f := func(w http.ResponseWriter, r *http.Request) {
		c := l.newContext(w, r)
		h.ServeHTTP(c, r)
		c.update()
		l.writeContext(c)
	}
	return http.HandlerFunc(f)
}

func (l *Logger) newContext(w http.ResponseWriter, r *http.Request) *Context {
	if l.Creator != nil {
		return l.Creator(w, r)
	}
	return NewContext(w, r)
}

func (l *Logger) writeContext(c *Context) {
	fmt.Fprintln(l.getWriter(), l.getResult(c))
}

func (l *Logger) getWriter() io.Writer {
	if l.Writer != nil {
		return l.Writer
	}
	return os.Stdout
}

func (l *Logger) getResult(c *Context) string {
	if l.Formatter != nil {
		return l.Formatter(c)
	}
	return "NEED TO IMPLEMENT"
}

type Context struct {
	http.ResponseWriter

	Request   *http.Request
	Path      string
	Ident     string
	User      string
	TimeStart time.Time
	TimeDone  time.Time
	Status    int
	Size      int
}

func NewContext(w http.ResponseWriter, r *http.Request) *Context {
	return &Context{
		ResponseWriter: w,
		Request:        r,
		Path:           r.URL.Path,
		TimeStart:      time.Now(),
		TimeDone:       time.Now(),
	}
}

func (c *Context) Write(data []byte) (int, error) {
	size, err := c.ResponseWriter.Write(data)
	c.Size += size
	return size, err
}

func (c *Context) WriteHeader(status int) {
	c.Status = status
	c.ResponseWriter.WriteHeader(c.Status)
}

func (c *Context) update() {
	c.TimeDone = time.Now()
	if c.Status == 0 {
		c.Status = http.StatusOK
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"
	"github.com/bmizerany/assert"
	"testing"
)

func ok(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}

func TestSearchResultToJSON(t *testing.T) {
	c := NewTestConn()

	qry := map[string]interface{}{
		"query": map[string]interface{}{
			"wildcard": map[string]string{"actor": "a*"},
		},
	}
	var args map[string]interface{}
	out, err := c.Search("github", "", args, qry)
	ok(t, err)

	_, err = json.Marshal(out.Hits.Hits)
	ok(t, err)
}

type SuggestTest struct {
	Completion string `json:"completion"`
}

type hash map[string]interface{}

func TestSuggest(t *testing.T) {
	c := NewTestConn()
	mappingOpts := MappingOptions{Properties: hash{
		"completion": hash{
			"type": "completion",
		},
	}}
	err := c.PutMapping("github", "SuggestTest", SuggestTest{}, mappingOpts)
	ok(t, err)

	_, err = c.UpdateWithPartialDoc("github", "SuggestTest", "1", nil, SuggestTest{"foobar"}, true)
	ok(t, err)

	query := hash{"completion_completion": hash{
		"text": "foo",
		"completion": hash{
			"size":  10,
			"field": "completion",
		},
	}}

	_, err = c.Refresh("github")
	ok(t, err)

	res, err := c.Suggest("github", nil, query)
	ok(t, err)

	opts, err := res.Result("completion_completion")
	ok(t, err)

	first := opts[0]
	text := first.Options[0].Text
	assert.T(t, text == "foobar", fmt.Sprintf("Expected foobar, got: %s", text))
}
<commit_msg>add assert<commit_after>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"
	"github.com/bmizerany/assert"
	"testing"
)

func ok(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}

func TestSearchResultToJSON(t *testing.T) {
	c := NewTestConn()

	qry := map[string]interface{}{
		"query": map[string]interface{}{
			"wildcard": map[string]string{"actor": "a*"},
		},
	}
	var args map[string]interface{}
	out, err := c.Search("github", "", args, qry)
	ok(t, err)

	_, err = json.Marshal(out.Hits.Hits)
	ok(t, err)
}

type SuggestTest struct {
	Completion string `json:"completion"`
}

type hash map[string]interface{}

func TestSuggest(t *testing.T) {
	c := NewTestConn()
	mappingOpts := MappingOptions{Properties: hash{
		"completion": hash{
			"type": "completion",
		},
	}}
	err := c.PutMapping("github", "SuggestTest", SuggestTest{}, mappingOpts)
	ok(t, err)

	_, err = c.UpdateWithPartialDoc("github", "SuggestTest", "1", nil, SuggestTest{"foobar"}, true)
	ok(t, err)

	query := hash{"completion_completion": hash{
		"text": "foo",
		"completion": hash{
			"size":  10,
			"field": "completion",
		},
	}}

	_, err = c.Refresh("github")
	ok(t, err)

	res, err := c.Suggest("github", nil, query)
	ok(t, err)

	opts, err := res.Result("completion_completion")
	ok(t, err)

	first := opts[0]
	assert.T(t, len(first.Options) > 0, "Length of first.Options was 0.")
	text := first.Options[0].Text
	assert.T(t, text == "foobar", fmt.Sprintf("Expected foobar, got: %s", text))
}
<|endoftext|>


<commit_before>package sourcegraph

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/go-querystring/query"
	"google.golang.org/grpc"
	"sourcegraph.com/sourcegraph/go-sourcegraph/router"
)

const (
	libraryVersion = "0.0.1"
	userAgent      = "sourcegraph-client/" + libraryVersion
)

// A Client communicates with the Sourcegraph API. All communication
// is done using gRPC over HTTP/2 except for BuildData (which uses
// HTTP/1).
type Client struct {
	// Services used to communicate with different parts of the Sourcegraph API.
	Accounts            AccountsClient
	Builds              BuildsClient
	BuildData           BuildDataService
	Defs                DefsClient
	Deltas              DeltasClient
	HostedRepos         HostedReposClient
	Markdown            MarkdownClient
	Meta                MetaClient
	MirrorRepos         MirrorReposClient
	MirroredRepoSSHKeys MirroredRepoSSHKeysClient
	Orgs                OrgsClient
	People              PeopleClient
	RepoBadges          RepoBadgesClient
	RepoStatuses        RepoStatusesClient
	RepoTree            RepoTreeClient
	Repos               ReposClient
	Search              SearchClient
	Units               UnitsClient
	UserAuth            UserAuthClient
	Users               UsersClient

	// Base URL for HTTP/1.1 requests, which should have a trailing slash.
	BaseURL *url.URL

	// User agent used for HTTP/1.1 requests to the Sourcegraph API.
	UserAgent string

	// HTTP client used to communicate with the Sourcegraph API.
	httpClient *http.Client

	// gRPC client connection used to communicate with the Sourcegraph
	// API.
	Conn *grpc.ClientConn
}

// NewClient returns a Sourcegraph API client. The gRPC conn is used
// for all services except for BuildData (which uses the
// httpClient). If httpClient is nil, http.DefaultClient is used.
func NewClient(httpClient *http.Client, conn *grpc.ClientConn) *Client {
	c := new(Client)

	// HTTP/1
	if httpClient == nil {
		cloned := *http.DefaultClient
		httpClient = &cloned
	}
	c.httpClient = httpClient
	c.BaseURL = &url.URL{Scheme: "https", Host: "sourcegraph.com", Path: "/api/"}
	c.UserAgent = userAgent
	c.BuildData = &buildDataService{c}

	// gRPC (HTTP/2)
	c.Conn = conn
	c.Accounts = NewAccountsClient(conn)
	c.Builds = NewBuildsClient(conn)
	c.Defs = NewDefsClient(conn)
	c.Deltas = NewDeltasClient(conn)
	c.HostedRepos = NewHostedReposClient(conn)
	c.Markdown = NewMarkdownClient(conn)
	c.Meta = NewMetaClient(conn)
	c.MirrorRepos = NewMirrorReposClient(conn)
	c.MirroredRepoSSHKeys = NewMirroredRepoSSHKeysClient(conn)
	c.Orgs = NewOrgsClient(conn)
	c.People = NewPeopleClient(conn)
	c.RepoBadges = NewRepoBadgesClient(conn)
	c.RepoStatuses = NewRepoStatusesClient(conn)
	c.RepoTree = NewRepoTreeClient(conn)
	c.Repos = NewReposClient(conn)
	c.Search = NewSearchClient(conn)
	c.Units = NewUnitsClient(conn)
	c.UserAuth = NewUserAuthClient(conn)
	c.Users = NewUsersClient(conn)

	return c
}

// Router is used to generate URLs for the Sourcegraph API.
var Router = router.NewAPIRouter(nil)

// ResetRouter clears and reconstructs the preinitialized API
// router. It should be called after setting an router.ExtraConfig
// func but only during init time.
func ResetRouter() {
	Router = router.NewAPIRouter(nil)
}

// URL generates a URL for the given route, route variables, and
// querystring options. Unless you explicitly set a Host, Scheme,
// and/or Port on Router, the returned URL will contain only path and
// querystring components (and will not be an absolute URL).
func URL(route string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
	rt := Router.Get(route)
	if rt == nil {
		return nil, fmt.Errorf("no Sourcegraph API route named %q", route)
	}

	routeVarsList := make([]string, 2*len(routeVars))
	i := 0
	for name, val := range routeVars {
		routeVarsList[i*2] = name
		routeVarsList[i*2+1] = val
		i++
	}
	url, err := rt.URL(routeVarsList...)
	if err != nil {
		return nil, err
	}

	if opt != nil {
		err = addOptions(url, opt)
		if err != nil {
			return nil, err
		}
	}

	return url, nil
}

// URL generates the absolute URL to the named Sourcegraph API endpoint, using the
// specified route variables and query options.
func (c *Client) URL(route string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
	url, err := URL(route, routeVars, opt)
	if err != nil {
		return nil, err
	}

	// make the route URL path relative to BaseURL by trimming the leading "/"
	url.Path = strings.TrimPrefix(url.Path, "/")

	// make the route URL path relative to BaseURL's path and not the path parent
	baseURL := *c.BaseURL
	if !strings.HasSuffix(baseURL.Path, "/") {
		baseURL.Path = baseURL.Path + "/"
	}

	// make the URL absolute
	url = baseURL.ResolveReference(url)

	return url, nil
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client. Relative
// URLs should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	url, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// newResponse creates a new Response for the provided http.Response.
func newResponse(r *http.Response) *HTTPResponse {
	return &HTTPResponse{Response: r}
}

// HTTPResponse is a wrapped HTTP response from the Sourcegraph API with
// additional Sourcegraph-specific response information parsed out. It
// implements Response.
type HTTPResponse struct {
	*http.Response
}

// TotalCount implements Response.
func (r *HTTPResponse) TotalCount() int {
	tc := r.Header.Get("x-total-count")
	if tc == "" {
		return -1
	}
	n, err := strconv.Atoi(tc)
	if err != nil {
		return -1
	}
	return n
}

// Response is a response from the Sourcegraph API. When using the HTTP API,
// API methods return *HTTPResponse values that implement Response.
type Response interface {
	// TotalCount is the total number of items in the resource or result set
	// that exist remotely. Only a portion of the total may be in the response
	// body. If the endpoint did not return a total count, then TotalCount
	// returns -1.
	TotalCount() int
}

// SimpleResponse implements Response.
type SimpleResponse struct {
	Total int // see (Response).TotalCount()
}

func (r *SimpleResponse) TotalCount() int { return r.Total }

type doKey int // sentinel value type for (*Client).Do v parameter

const preserveBody doKey = iota // when passed as v to (*Client).Do, the resp body is neither parsed nor closed

// Do sends an API request and returns the API response.  The API
// response is decoded and stored in the value pointed to by v, or
// returned as an error if an API error has occurred. If v is
// preserveBody, then the HTTP response body is not closed by Do; the
// caller is responsible for closing it.
func (c *Client) Do(req *http.Request, v interface{}) (*HTTPResponse, error) {
	var resp *HTTPResponse
	rawResp, err := c.httpClient.Do(req)
	if rawResp != nil {
		if v != preserveBody && rawResp.Body != nil {
			defer rawResp.Body.Close()
		}
		resp = newResponse(rawResp)
		if err == nil {
			// Don't clobber error from Do, if any (it could be, e.g.,
			// a sentinel error returned by the HTTP client's
			// CheckRedirect func).
			if err := CheckResponse(rawResp); err != nil {
				// even though there was an error, we still return the response
				// in case the caller wants to inspect it further
				return resp, err
			}
		}
	}
	if err != nil {
		return resp, err
	}

	if v != nil {
		if bp, ok := v.(*[]byte); ok {
			*bp, err = ioutil.ReadAll(rawResp.Body)
		} else if v != preserveBody {
			err = json.NewDecoder(rawResp.Body).Decode(v)
		}
	}
	if err != nil {
		return resp, fmt.Errorf("error reading response from %s %s: %s", req.Method, req.URL.RequestURI(), err)
	}
	return resp, nil
}

// addOptions adds the parameters in opt as URL query parameters to u. opt
// must be a struct whose fields may contain "url" tags.
func addOptions(u *url.URL, opt interface{}) error {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return nil
	}

	qs, err := query.Values(opt)
	if err != nil {
		return err
	}

	u.RawQuery = qs.Encode()
	return nil
}
<commit_msg>Close method<commit_after>package sourcegraph

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/go-querystring/query"
	"google.golang.org/grpc"
	"sourcegraph.com/sourcegraph/go-sourcegraph/router"
)

const (
	libraryVersion = "0.0.1"
	userAgent      = "sourcegraph-client/" + libraryVersion
)

// A Client communicates with the Sourcegraph API. All communication
// is done using gRPC over HTTP/2 except for BuildData (which uses
// HTTP/1).
type Client struct {
	// Services used to communicate with different parts of the Sourcegraph API.
	Accounts            AccountsClient
	Builds              BuildsClient
	BuildData           BuildDataService
	Defs                DefsClient
	Deltas              DeltasClient
	HostedRepos         HostedReposClient
	Markdown            MarkdownClient
	Meta                MetaClient
	MirrorRepos         MirrorReposClient
	MirroredRepoSSHKeys MirroredRepoSSHKeysClient
	Orgs                OrgsClient
	People              PeopleClient
	RepoBadges          RepoBadgesClient
	RepoStatuses        RepoStatusesClient
	RepoTree            RepoTreeClient
	Repos               ReposClient
	Search              SearchClient
	Units               UnitsClient
	UserAuth            UserAuthClient
	Users               UsersClient

	// Base URL for HTTP/1.1 requests, which should have a trailing slash.
	BaseURL *url.URL

	// User agent used for HTTP/1.1 requests to the Sourcegraph API.
	UserAgent string

	// HTTP client used to communicate with the Sourcegraph API.
	httpClient *http.Client

	// gRPC client connection used to communicate with the Sourcegraph
	// API.
	Conn *grpc.ClientConn
}

// Close closes the gRPC client connection.
func (c *Client) Close() error {
	if conn := c.Conn; conn != nil {
		c.Conn = nil
		return conn.Close()
	}
	return nil
}

// NewClient returns a Sourcegraph API client. The gRPC conn is used
// for all services except for BuildData (which uses the
// httpClient). If httpClient is nil, http.DefaultClient is used.
func NewClient(httpClient *http.Client, conn *grpc.ClientConn) *Client {
	c := new(Client)

	// HTTP/1
	if httpClient == nil {
		cloned := *http.DefaultClient
		httpClient = &cloned
	}
	c.httpClient = httpClient
	c.BaseURL = &url.URL{Scheme: "https", Host: "sourcegraph.com", Path: "/api/"}
	c.UserAgent = userAgent
	c.BuildData = &buildDataService{c}

	// gRPC (HTTP/2)
	c.Conn = conn
	c.Accounts = NewAccountsClient(conn)
	c.Builds = NewBuildsClient(conn)
	c.Defs = NewDefsClient(conn)
	c.Deltas = NewDeltasClient(conn)
	c.HostedRepos = NewHostedReposClient(conn)
	c.Markdown = NewMarkdownClient(conn)
	c.Meta = NewMetaClient(conn)
	c.MirrorRepos = NewMirrorReposClient(conn)
	c.MirroredRepoSSHKeys = NewMirroredRepoSSHKeysClient(conn)
	c.Orgs = NewOrgsClient(conn)
	c.People = NewPeopleClient(conn)
	c.RepoBadges = NewRepoBadgesClient(conn)
	c.RepoStatuses = NewRepoStatusesClient(conn)
	c.RepoTree = NewRepoTreeClient(conn)
	c.Repos = NewReposClient(conn)
	c.Search = NewSearchClient(conn)
	c.Units = NewUnitsClient(conn)
	c.UserAuth = NewUserAuthClient(conn)
	c.Users = NewUsersClient(conn)

	return c
}

// Router is used to generate URLs for the Sourcegraph API.
var Router = router.NewAPIRouter(nil)

// ResetRouter clears and reconstructs the preinitialized API
// router. It should be called after setting an router.ExtraConfig
// func but only during init time.
func ResetRouter() {
	Router = router.NewAPIRouter(nil)
}

// URL generates a URL for the given route, route variables, and
// querystring options. Unless you explicitly set a Host, Scheme,
// and/or Port on Router, the returned URL will contain only path and
// querystring components (and will not be an absolute URL).
func URL(route string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
	rt := Router.Get(route)
	if rt == nil {
		return nil, fmt.Errorf("no Sourcegraph API route named %q", route)
	}

	routeVarsList := make([]string, 2*len(routeVars))
	i := 0
	for name, val := range routeVars {
		routeVarsList[i*2] = name
		routeVarsList[i*2+1] = val
		i++
	}
	url, err := rt.URL(routeVarsList...)
	if err != nil {
		return nil, err
	}

	if opt != nil {
		err = addOptions(url, opt)
		if err != nil {
			return nil, err
		}
	}

	return url, nil
}

// URL generates the absolute URL to the named Sourcegraph API endpoint, using the
// specified route variables and query options.
func (c *Client) URL(route string, routeVars map[string]string, opt interface{}) (*url.URL, error) {
	url, err := URL(route, routeVars, opt)
	if err != nil {
		return nil, err
	}

	// make the route URL path relative to BaseURL by trimming the leading "/"
	url.Path = strings.TrimPrefix(url.Path, "/")

	// make the route URL path relative to BaseURL's path and not the path parent
	baseURL := *c.BaseURL
	if !strings.HasSuffix(baseURL.Path, "/") {
		baseURL.Path = baseURL.Path + "/"
	}

	// make the URL absolute
	url = baseURL.ResolveReference(url)

	return url, nil
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client. Relative
// URLs should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	url, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// newResponse creates a new Response for the provided http.Response.
func newResponse(r *http.Response) *HTTPResponse {
	return &HTTPResponse{Response: r}
}

// HTTPResponse is a wrapped HTTP response from the Sourcegraph API with
// additional Sourcegraph-specific response information parsed out. It
// implements Response.
type HTTPResponse struct {
	*http.Response
}

// TotalCount implements Response.
func (r *HTTPResponse) TotalCount() int {
	tc := r.Header.Get("x-total-count")
	if tc == "" {
		return -1
	}
	n, err := strconv.Atoi(tc)
	if err != nil {
		return -1
	}
	return n
}

// Response is a response from the Sourcegraph API. When using the HTTP API,
// API methods return *HTTPResponse values that implement Response.
type Response interface {
	// TotalCount is the total number of items in the resource or result set
	// that exist remotely. Only a portion of the total may be in the response
	// body. If the endpoint did not return a total count, then TotalCount
	// returns -1.
	TotalCount() int
}

// SimpleResponse implements Response.
type SimpleResponse struct {
	Total int // see (Response).TotalCount()
}

func (r *SimpleResponse) TotalCount() int { return r.Total }

type doKey int // sentinel value type for (*Client).Do v parameter

const preserveBody doKey = iota // when passed as v to (*Client).Do, the resp body is neither parsed nor closed

// Do sends an API request and returns the API response.  The API
// response is decoded and stored in the value pointed to by v, or
// returned as an error if an API error has occurred. If v is
// preserveBody, then the HTTP response body is not closed by Do; the
// caller is responsible for closing it.
func (c *Client) Do(req *http.Request, v interface{}) (*HTTPResponse, error) {
	var resp *HTTPResponse
	rawResp, err := c.httpClient.Do(req)
	if rawResp != nil {
		if v != preserveBody && rawResp.Body != nil {
			defer rawResp.Body.Close()
		}
		resp = newResponse(rawResp)
		if err == nil {
			// Don't clobber error from Do, if any (it could be, e.g.,
			// a sentinel error returned by the HTTP client's
			// CheckRedirect func).
			if err := CheckResponse(rawResp); err != nil {
				// even though there was an error, we still return the response
				// in case the caller wants to inspect it further
				return resp, err
			}
		}
	}
	if err != nil {
		return resp, err
	}

	if v != nil {
		if bp, ok := v.(*[]byte); ok {
			*bp, err = ioutil.ReadAll(rawResp.Body)
		} else if v != preserveBody {
			err = json.NewDecoder(rawResp.Body).Decode(v)
		}
	}
	if err != nil {
		return resp, fmt.Errorf("error reading response from %s %s: %s", req.Method, req.URL.RequestURI(), err)
	}
	return resp, nil
}

// addOptions adds the parameters in opt as URL query parameters to u. opt
// must be a struct whose fields may contain "url" tags.
func addOptions(u *url.URL, opt interface{}) error {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return nil
	}

	qs, err := query.Values(opt)
	if err != nil {
		return err
	}

	u.RawQuery = qs.Encode()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
)

type CaptchaTask struct {
	Task   string
	ID     string
	Answer string
}

type Deck struct {
	nextTask int
	tasks    []CaptchaTask
}

var (
	deck *Deck
)

func NewDeck() *Deck {
	var deck Deck
	answers := []string{
		"vienuolika",
		"dvylika",
		"trylika",
		"keturiolika",
		"penkiolika",
		"šešiolika",
		"septyniolika",
		"aštuoniolika",
		"devyniolika",
	}
	deck.tasks = make([]CaptchaTask, 0, 0)
	for i, answer := range answers {
		task := CaptchaTask{
			Task:   fmt.Sprintf("9 + %d =", i+2),
			ID:     fmt.Sprintf("%d", 666+i),
			Answer: answer,
		}
		deck.tasks = append(deck.tasks, task)
	}
	return &deck
}

func init() {
	deck = NewDeck()
}

func (d *Deck) GetTask() *CaptchaTask {
	return &d.tasks[d.nextTask]
}

func (d *Deck) GetTaskByID(id string) *CaptchaTask {
	for _, t := range d.tasks {
		if t.ID == id {
			return &t
		}
	}
	return &d.tasks[0]
}

func (d *Deck) SetNextTask(task int) {
	if task < 0 {
		task = rand.Int() % len(d.tasks)
	}
	d.nextTask = task
}

func CheckCaptcha(task *CaptchaTask, input string) bool {
	return input == task.Answer
}

func WrongCaptchaReply(w http.ResponseWriter, req *http.Request, status string, task *CaptchaTask) error {
	var response = map[string]interface{}{
		"status":       status,
		"captcha-id":   task.ID,
		"captcha-task": task.Task,
		"name":         req.FormValue("name"),
		"email":        req.FormValue("email"),
		"website":      req.FormValue("website"),
		"body":         req.FormValue("text"),
	}
	b, err := json.Marshal(response)
	if logger.LogIf(err) == nil {
		w.Write(b)
	}
	return nil
}

func RightCaptchaReply(w http.ResponseWriter, redir string) error {
	var response = map[string]interface{}{
		"status": "accepted",
		"redir":  redir,
	}
	b, err := json.Marshal(response)
	if logger.LogIf(err) == nil {
		w.Write(b)
	}
	return nil
}
<commit_msg>Remove unnecessary variables<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
)

type CaptchaTask struct {
	Task   string
	ID     string
	Answer string
}

type Deck struct {
	nextTask int
	tasks    []CaptchaTask
}

var (
	deck *Deck
)

func NewDeck() *Deck {
	var deck Deck
	answers := []string{
		"vienuolika",
		"dvylika",
		"trylika",
		"keturiolika",
		"penkiolika",
		"šešiolika",
		"septyniolika",
		"aštuoniolika",
		"devyniolika",
	}
	deck.tasks = make([]CaptchaTask, 0, 0)
	for i, answer := range answers {
		task := CaptchaTask{
			Task:   fmt.Sprintf("9 + %d =", i+2),
			ID:     fmt.Sprintf("%d", 666+i),
			Answer: answer,
		}
		deck.tasks = append(deck.tasks, task)
	}
	return &deck
}

func init() {
	deck = NewDeck()
}

func (d *Deck) GetTask() *CaptchaTask {
	return &d.tasks[d.nextTask]
}

func (d *Deck) GetTaskByID(id string) *CaptchaTask {
	for _, t := range d.tasks {
		if t.ID == id {
			return &t
		}
	}
	return &d.tasks[0]
}

func (d *Deck) SetNextTask(task int) {
	if task < 0 {
		task = rand.Int() % len(d.tasks)
	}
	d.nextTask = task
}

func CheckCaptcha(task *CaptchaTask, input string) bool {
	return input == task.Answer
}

func WrongCaptchaReply(w http.ResponseWriter, req *http.Request, status string, task *CaptchaTask) error {
	b, err := json.Marshal(map[string]interface{}{
		"status":       status,
		"captcha-id":   task.ID,
		"captcha-task": task.Task,
		"name":         req.FormValue("name"),
		"email":        req.FormValue("email"),
		"website":      req.FormValue("website"),
		"body":         req.FormValue("text"),
	})
	if logger.LogIf(err) == nil {
		w.Write(b)
	}
	return nil
}

func RightCaptchaReply(w http.ResponseWriter, redir string) error {
	b, err := json.Marshal(map[string]interface{}{
		"status": "accepted",
		"redir":  redir,
	})
	if logger.LogIf(err) == nil {
		w.Write(b)
	}
	return nil
}
<|endoftext|>


<commit_before>package module

import (
	"fmt"
	"github.com/davidscholberg/irkbot/lib/configure"
	"github.com/davidscholberg/irkbot/lib/message"
	"github.com/thoj/go-ircevent"
	"strings"
	"time"
)

type CommandModule struct {
	Configure func(*configure.Config)
	GetHelp   func() []string
	Run       func(*configure.Config, *message.InboundMsg, *Actions)
}

type ParserModule struct {
	Configure func(*configure.Config)
	Run       func(*configure.Config, *message.InboundMsg, *Actions) bool
}

type TickerModule struct {
	Configure   func(*configure.Config)
	GetDuration func(*configure.Config) time.Duration
	Run         func(*configure.Config, time.Time, *Actions)
	Ticker      *time.Ticker
}

type Actions struct {
	Quit  func()
	Say   func(string)
	SayTo func(string, string)
}

func RegisterModules(conn *irc.Connection, cfg *configure.Config, outChan chan message.OutboundMsg) error {
	cmdMap := make(map[string]*CommandModule)
	parserModules := []*ParserModule{}
	tickerModules := []*TickerModule{}
	for moduleName, _ := range cfg.Modules {
		switch moduleName {
		case "echo_name":
			parserModules = append(parserModules, &ParserModule{nil, EchoName})
		case "help":
			cmdMap["help"] = &CommandModule{nil, nil, Help}
			parserModules = append(parserModules, &ParserModule{nil, ParseHelp})
		case "slam":
			cmdMap["slam"] = &CommandModule{ConfigSlam, HelpSlam, Slam}
		case "compliment":
			cmdMap["compliment"] = &CommandModule{ConfigCompliment, HelpCompliment, GiveCompliment}
		case "quit":
			cmdMap["quit"] = &CommandModule{nil, HelpQuit, Quit}
		case "quote":
			cmdMap["grab"] = &CommandModule{nil, HelpGrabQuote, GrabQuote}
			cmdMap["quote"] = &CommandModule{nil, HelpGetQuote, GetQuote}
			parserModules = append(parserModules, &ParserModule{ConfigQuote, UpdateQuoteBuffer})
			tickerModules = append(
				tickerModules,
				&TickerModule{
					nil,
					GetCleanQuoteBufferDuration,
					CleanQuoteBuffer,
					nil,
				},
			)
		case "say":
			cmdMap["say"] = &CommandModule{nil, HelpSay, Say}
		case "urban":
			cmdMap["urban"] = &CommandModule{nil, HelpUrban, Urban}
		case "urban_wotd":
			cmdMap["urban_wotd"] = &CommandModule{nil, HelpUrbanWotd, UrbanWotd}
		case "urban_trending":
			cmdMap["urban_trending"] = &CommandModule{nil, HelpUrbanTrending, UrbanTrending}
		case "url":
			parserModules = append(parserModules, &ParserModule{nil, Url})
		case "interject":
			cmdMap["interject"] = &CommandModule{nil, HelpInterject, Interject}
		case "xkcd":
			cmdMap["xkcd"] = &CommandModule{nil, Helpxkcd, getXKCD}
		case "doing":
			cmdMap["doing"] = &CommandModule{ConfigDoing, HelpDoing, Doing}
		case "doom":
			cmdMap["doom"] = &CommandModule{nil, HelpDoom, Doom}
		default:
			return fmt.Errorf("invalid name '%s' in module config", moduleName)
		}
	}

	for _, m := range cmdMap {
		if m.GetHelp != nil {
			RegisterHelp(m.GetHelp())
		}
		if m.Configure != nil {
			m.Configure(cfg)
		}
	}

	for _, m := range parserModules {
		if m.Configure != nil {
			m.Configure(cfg)
		}
	}

	actions := Actions{
		Quit: func() {
			conn.Quit()
		},
		SayTo: func(dest string, msg string) {
			outboundMsg := message.OutboundMsg{
				Conn: conn,
				Dest: dest,
				Msg:  msg,
			}
			outChan <- outboundMsg
		},
	}

	for _, m := range tickerModules {
		if m.Configure != nil {
			m.Configure(cfg)
		}
		m.Ticker = time.NewTicker(m.GetDuration(cfg))
		tickerChan := m.Ticker.C
		run := m.Run
		go func() {
			// Note that the sender of this channel will never close it.
			// It must be closed manually after time.Stop in order to exit this goroutine.
			for t := range tickerChan {
				run(cfg, t, &actions)
			}
		}()
	}

	conn.AddCallback("PRIVMSG", func(e *irc.Event) {
		inboundMsg := message.InboundMsg{}
		inboundMsg.Msg = e.Message()
		inboundMsg.MsgArgs = strings.Fields(inboundMsg.Msg)
		inboundMsg.Src = e.Arguments[0]
		if !strings.HasPrefix(inboundMsg.Src, "#") {
			inboundMsg.Src = e.Nick
		}
		inboundMsg.Event = e

		actions.Say = func(msg string) {
			outboundMsg := message.OutboundMsg{
				Conn: conn,
				Dest: inboundMsg.Src,
				Msg:  msg,
			}
			outChan <- outboundMsg
		}

		// run parser modules
		for _, m := range parserModules {
			if m.Run(cfg, &inboundMsg, &actions) {
				return
			}
		}

		// check commands
		cmdPrefix := cfg.Channel.CmdPrefix
		if cmdPrefix == "" {
			cmdPrefix = "."
		}
		if strings.HasPrefix(inboundMsg.Msg, cmdPrefix) {
			if m, ok := cmdMap[strings.TrimPrefix(inboundMsg.MsgArgs[0], cmdPrefix)]; ok {
				m.Run(cfg, &inboundMsg, &actions)
			}
		}

	})

	return nil
}
<commit_msg>update Register to register the Youtube module<commit_after>package module

import (
	"fmt"
	"github.com/davidscholberg/irkbot/lib/configure"
	"github.com/davidscholberg/irkbot/lib/message"
	"github.com/thoj/go-ircevent"
	"strings"
	"time"
)

type CommandModule struct {
	Configure func(*configure.Config)
	GetHelp   func() []string
	Run       func(*configure.Config, *message.InboundMsg, *Actions)
}

type ParserModule struct {
	Configure func(*configure.Config)
	Run       func(*configure.Config, *message.InboundMsg, *Actions) bool
}

type TickerModule struct {
	Configure   func(*configure.Config)
	GetDuration func(*configure.Config) time.Duration
	Run         func(*configure.Config, time.Time, *Actions)
	Ticker      *time.Ticker
}

type Actions struct {
	Quit  func()
	Say   func(string)
	SayTo func(string, string)
}

func RegisterModules(conn *irc.Connection, cfg *configure.Config, outChan chan message.OutboundMsg) error {
	cmdMap := make(map[string]*CommandModule)
	parserModules := []*ParserModule{}
	tickerModules := []*TickerModule{}
	for moduleName, _ := range cfg.Modules {
		switch moduleName {
		case "echo_name":
			parserModules = append(parserModules, &ParserModule{nil, EchoName})
		case "help":
			cmdMap["help"] = &CommandModule{nil, nil, Help}
			parserModules = append(parserModules, &ParserModule{nil, ParseHelp})
		case "slam":
			cmdMap["slam"] = &CommandModule{ConfigSlam, HelpSlam, Slam}
		case "compliment":
			cmdMap["compliment"] = &CommandModule{ConfigCompliment, HelpCompliment, GiveCompliment}
		case "quit":
			cmdMap["quit"] = &CommandModule{nil, HelpQuit, Quit}
		case "quote":
			cmdMap["grab"] = &CommandModule{nil, HelpGrabQuote, GrabQuote}
			cmdMap["quote"] = &CommandModule{nil, HelpGetQuote, GetQuote}
			parserModules = append(parserModules, &ParserModule{ConfigQuote, UpdateQuoteBuffer})
			tickerModules = append(
				tickerModules,
				&TickerModule{
					nil,
					GetCleanQuoteBufferDuration,
					CleanQuoteBuffer,
					nil,
				},
			)
		case "say":
			cmdMap["say"] = &CommandModule{nil, HelpSay, Say}
		case "urban":
			cmdMap["urban"] = &CommandModule{nil, HelpUrban, Urban}
		case "urban_wotd":
			cmdMap["urban_wotd"] = &CommandModule{nil, HelpUrbanWotd, UrbanWotd}
		case "urban_trending":
			cmdMap["urban_trending"] = &CommandModule{nil, HelpUrbanTrending, UrbanTrending}
		case "url":
			parserModules = append(parserModules, &ParserModule{nil, Url})
		case "interject":
			cmdMap["interject"] = &CommandModule{nil, HelpInterject, Interject}
		case "xkcd":
			cmdMap["xkcd"] = &CommandModule{nil, Helpxkcd, getXKCD}
		case "doing":
			cmdMap["doing"] = &CommandModule{ConfigDoing, HelpDoing, Doing}
		case "doom":
			cmdMap["doom"] = &CommandModule{nil, HelpDoom, Doom}
                case "youtube":
                        cmdMap["yt"] = &CommandModule{nil, HelpYoutube, Youtube}
		default:
			return fmt.Errorf("invalid name '%s' in module config", moduleName)
		}
	}

	for _, m := range cmdMap {
		if m.GetHelp != nil {
			RegisterHelp(m.GetHelp())
		}
		if m.Configure != nil {
			m.Configure(cfg)
		}
	}

	for _, m := range parserModules {
		if m.Configure != nil {
			m.Configure(cfg)
		}
	}

	actions := Actions{
		Quit: func() {
			conn.Quit()
		},
		SayTo: func(dest string, msg string) {
			outboundMsg := message.OutboundMsg{
				Conn: conn,
				Dest: dest,
				Msg:  msg,
			}
			outChan <- outboundMsg
		},
	}

	for _, m := range tickerModules {
		if m.Configure != nil {
			m.Configure(cfg)
		}
		m.Ticker = time.NewTicker(m.GetDuration(cfg))
		tickerChan := m.Ticker.C
		run := m.Run
		go func() {
			// Note that the sender of this channel will never close it.
			// It must be closed manually after time.Stop in order to exit this goroutine.
			for t := range tickerChan {
				run(cfg, t, &actions)
			}
		}()
	}

	conn.AddCallback("PRIVMSG", func(e *irc.Event) {
		inboundMsg := message.InboundMsg{}
		inboundMsg.Msg = e.Message()
		inboundMsg.MsgArgs = strings.Fields(inboundMsg.Msg)
		inboundMsg.Src = e.Arguments[0]
		if !strings.HasPrefix(inboundMsg.Src, "#") {
			inboundMsg.Src = e.Nick
		}
		inboundMsg.Event = e

		actions.Say = func(msg string) {
			outboundMsg := message.OutboundMsg{
				Conn: conn,
				Dest: inboundMsg.Src,
				Msg:  msg,
			}
			outChan <- outboundMsg
		}

		// run parser modules
		for _, m := range parserModules {
			if m.Run(cfg, &inboundMsg, &actions) {
				return
			}
		}

		// check commands
		cmdPrefix := cfg.Channel.CmdPrefix
		if cmdPrefix == "" {
			cmdPrefix = "."
		}
		if strings.HasPrefix(inboundMsg.Msg, cmdPrefix) {
			if m, ok := cmdMap[strings.TrimPrefix(inboundMsg.MsgArgs[0], cmdPrefix)]; ok {
				m.Run(cfg, &inboundMsg, &actions)
			}
		}

	})

	return nil
}
<|endoftext|>


<commit_before>package integration_test

import (
	"time"
	"fmt"

	. "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo"
	. "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega"

	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
)

var _ = Describe("RawEphemeralDisk", func() {
	var (
		registrySettings boshsettings.Settings
	)

	BeforeEach(func() {
		err := testEnvironment.StopAgent()
		Expect(err).ToNot(HaveOccurred())

		err = testEnvironment.CleanupDataDir()
		Expect(err).ToNot(HaveOccurred())

		err = testEnvironment.CleanupLogFile()
		Expect(err).ToNot(HaveOccurred())

		err = testEnvironment.SetupConfigDrive()
		Expect(err).ToNot(HaveOccurred())

		err = testEnvironment.UpdateAgentConfig("config-drive-agent.json")
		Expect(err).ToNot(HaveOccurred())

		networks, err := testEnvironment.GetVMNetworks()
		Expect(err).ToNot(HaveOccurred())

		registrySettings = boshsettings.Settings{
			AgentID: "fake-agent-id",
			Mbus:    "https://127.0.0.1:6868",
			Blobstore: boshsettings.Blobstore{
				Type: "local",
				Options: map[string]interface{}{
					"blobstore_path": "/var/vcap/data",
				},
			},
			Networks: networks,
		}
	})

	Context("when raw ephemeral disk is provided in settings", func() {
		BeforeEach(func() {
			err := testEnvironment.AttachDevice("/dev/sdh", 128, 2)
			Expect(err).ToNot(HaveOccurred())

			fmt.Println("======== attaching devices xvdb")
			err = testEnvironment.AttachDevice("/dev/xvdb", 128, 1)
			Expect(err).ToNot(HaveOccurred())

			fmt.Println("======== attaching devices xvdc ")
			err = testEnvironment.AttachDevice("/dev/xvdc", 128, 1)
			Expect(err).ToNot(HaveOccurred())

			registrySettings.Disks = boshsettings.Disks{
				Ephemeral:         "/dev/sdh",
				RawEphemeral: []boshsettings.DiskSettings{{Path: "/dev/xvdb"}, {Path: "/dev/xvdc"}},
			}

			err = testEnvironment.StartRegistry(registrySettings)
			Expect(err).ToNot(HaveOccurred())

			fmt.Println("======== start agent")
			err = testEnvironment.StartAgent()
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			err := testEnvironment.StopAgent()
			Expect(err).ToNot(HaveOccurred())

			err = testEnvironment.DetachDevice("/dev/sdh")
			Expect(err).ToNot(HaveOccurred())

			fmt.Println("======== ======== detach devices xvdb")
			err = testEnvironment.DetachDevice("/dev/xvdb")
			Expect(err).ToNot(HaveOccurred())

			fmt.Println("======== detach devices xvdc")
			err = testEnvironment.DetachDevice("/dev/xvdc")
			Expect(err).ToNot(HaveOccurred())
		})

		It("labels the raw ephemeral paths for unpartitioned disks", func() {
			var output string

			Eventually(func() string {
				stdout, _ := testEnvironment.RunCommand("find /dev/disk/by-partlabel")

				output = stdout

//				Expect(err).ToNot(HaveOccurred())

				return stdout
			}, 2*time.Minute, 1*time.Second).Should(ContainSubstring("/dev/disk/by-partlabel/raw-ephemeral-0"))

			Expect(output).To(ContainSubstring("/dev/disk/by-partlabel/raw-ephemeral-1"))
		})
	})

})
<commit_msg>Revert "Adds acceptance test for raw ephemeral storage"<commit_after><|endoftext|>