<commit_before>// Copyright (C) 2017 ScyllaDB
// Use of this source code is governed by a ALv2-style
// license that can be found in the LICENSE file.

package table

import (
	"context"

	"github.com/scylladb/gocqlx/v2"
	"github.com/scylladb/gocqlx/v2/qb"
)

// Metadata represents table schema.
type Metadata struct {
	Name    string
	Columns []string
	PartKey []string
	SortKey []string
}

type cql struct {
	stmt  string
	names []string
}

// Table allows for simple CRUD operations, it's backed by query builders from
// gocqlx/qb package.
type Table struct {
	metadata      Metadata
	primaryKeyCmp []qb.Cmp
	partKeyCmp    []qb.Cmp

	get    cql
	sel    cql
	insert cql
}

// New creates new Table based on table schema read from Metadata.
func New(m Metadata) *Table { // nolint: gocritic
	t := &Table{
		metadata: m,
	}

	// prepare primary and partition key comparators
	t.primaryKeyCmp = make([]qb.Cmp, 0, len(m.PartKey)+len(m.SortKey))
	for _, k := range m.PartKey {
		t.primaryKeyCmp = append(t.primaryKeyCmp, qb.Eq(k))
	}
	for _, k := range m.SortKey {
		t.primaryKeyCmp = append(t.primaryKeyCmp, qb.Eq(k))
	}
	t.partKeyCmp = make([]qb.Cmp, len(m.PartKey))
	copy(t.partKeyCmp, t.primaryKeyCmp[:len(t.metadata.PartKey)])

	// prepare get stmt
	t.get.stmt, t.get.names = qb.Select(m.Name).Where(t.primaryKeyCmp...).ToCql()
	// prepare select stmt
	t.sel.stmt, t.sel.names = qb.Select(m.Name).Where(t.partKeyCmp...).ToCql()
	// prepare insert stmt
	t.insert.stmt, t.insert.names = qb.Insert(m.Name).Columns(m.Columns...).ToCql()

	return t
}

// Metadata returns copy of table metadata.
func (t *Table) Metadata() Metadata {
	return t.metadata
}

// PrimaryKeyCmp returns copy of table's primaryKeyCmp.
func (t *Table) PrimaryKeyCmp() []qb.Cmp {
	primaryKeyCmp := make([]qb.Cmp, len(t.primaryKeyCmp))
	copy(primaryKeyCmp, t.primaryKeyCmp)
	return primaryKeyCmp
}

// Name returns table name.
func (t *Table) Name() string {
	return t.metadata.Name
}

// Get returns select by primary key statement.
func (t *Table) Get(columns ...string) (stmt string, names []string) {
	if len(columns) == 0 {
		return t.get.stmt, t.get.names
	}

	return qb.Select(t.metadata.Name).
		Columns(columns...).
		Where(t.primaryKeyCmp...).
		ToCql()
}

// GetQuery returns query which gets by partition key.
func (t *Table) GetQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Get(columns...))
}

// GetQueryContext returns query wrapped with context which gets by partition key.
func (t *Table) GetQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.GetQuery(session, columns...).WithContext(ctx)
}

// Select returns select by partition key statement.
func (t *Table) Select(columns ...string) (stmt string, names []string) {
	if len(columns) == 0 {
		return t.sel.stmt, t.sel.names
	}

	return qb.Select(t.metadata.Name).
		Columns(columns...).
		Where(t.primaryKeyCmp[0:len(t.metadata.PartKey)]...).
		ToCql()
}

// SelectQuery returns query which selects by partition key statement.
func (t *Table) SelectQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Select(columns...))
}

// SelectQueryContext returns query wrapped with context which selects by partition key statement.
func (t *Table) SelectQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.SelectQuery(session, columns...).WithContext(ctx)
}

// SelectBuilder returns a builder initialised to select by partition key
// statement.
func (t *Table) SelectBuilder(columns ...string) *qb.SelectBuilder {
	return qb.Select(t.metadata.Name).Columns(columns...).Where(t.partKeyCmp...)
}

// Insert returns insert all columns statement.
func (t *Table) Insert() (stmt string, names []string) {
	return t.insert.stmt, t.insert.names
}

// InsertQuery returns query which inserts all columns.
func (t *Table) InsertQuery(session gocqlx.Session) *gocqlx.Queryx {
	return session.Query(t.Insert())
}

// InsertQueryContext returns query wrapped with context which inserts all columns.
func (t *Table) InsertQueryContext(ctx context.Context, session gocqlx.Session) *gocqlx.Queryx {
	return t.InsertQuery(session).WithContext(ctx)
}

// InsertBuilder returns a builder initialised with all columns.
func (t *Table) InsertBuilder() *qb.InsertBuilder {
	return qb.Insert(t.metadata.Name).Columns(t.metadata.Columns...)
}

// Update returns update by primary key statement.
func (t *Table) Update(columns ...string) (stmt string, names []string) {
	return t.UpdateBuilder(columns...).ToCql()
}

// UpdateQuery returns query which updates by primary key.
func (t *Table) UpdateQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Update(columns...))
}

// UpdateQueryContext returns query wrapped with context which updates by primary key.
func (t *Table) UpdateQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.UpdateQuery(session, columns...).WithContext(ctx)
}

// UpdateBuilder returns a builder initialised to update by primary key statement.
func (t *Table) UpdateBuilder(columns ...string) *qb.UpdateBuilder {
	return qb.Update(t.metadata.Name).Set(columns...).Where(t.primaryKeyCmp...)
}

// Delete returns delete by primary key statement.
func (t *Table) Delete(columns ...string) (stmt string, names []string) {
	return t.DeleteBuilder(columns...).ToCql()
}

// DeleteQuery returns query which delete by primary key.
func (t *Table) DeleteQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Delete(columns...))
}

// DeleteQueryContext returns query wrapped with context which delete by primary key.
func (t *Table) DeleteQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.DeleteQuery(session, columns...).WithContext(ctx)
}

// DeleteBuilder returns a builder initialised to delete by primary key statement.
func (t *Table) DeleteBuilder(columns ...string) *qb.DeleteBuilder {
	return qb.Delete(t.metadata.Name).Columns(columns...).Where(t.primaryKeyCmp...)
}
<commit_msg>table: Add SelectAll<commit_after>// Copyright (C) 2017 ScyllaDB
// Use of this source code is governed by a ALv2-style
// license that can be found in the LICENSE file.

package table

import (
	"context"

	"github.com/scylladb/gocqlx/v2"
	"github.com/scylladb/gocqlx/v2/qb"
)

// Metadata represents table schema.
type Metadata struct {
	Name    string
	Columns []string
	PartKey []string
	SortKey []string
}

type cql struct {
	stmt  string
	names []string
}

// Table allows for simple CRUD operations, it's backed by query builders from
// gocqlx/qb package.
type Table struct {
	metadata      Metadata
	primaryKeyCmp []qb.Cmp
	partKeyCmp    []qb.Cmp

	get    cql
	sel    cql
	insert cql
}

// New creates new Table based on table schema read from Metadata.
func New(m Metadata) *Table { // nolint: gocritic
	t := &Table{
		metadata: m,
	}

	// prepare primary and partition key comparators
	t.primaryKeyCmp = make([]qb.Cmp, 0, len(m.PartKey)+len(m.SortKey))
	for _, k := range m.PartKey {
		t.primaryKeyCmp = append(t.primaryKeyCmp, qb.Eq(k))
	}
	for _, k := range m.SortKey {
		t.primaryKeyCmp = append(t.primaryKeyCmp, qb.Eq(k))
	}
	t.partKeyCmp = make([]qb.Cmp, len(m.PartKey))
	copy(t.partKeyCmp, t.primaryKeyCmp[:len(t.metadata.PartKey)])

	// prepare get stmt
	t.get.stmt, t.get.names = qb.Select(m.Name).Where(t.primaryKeyCmp...).ToCql()
	// prepare select stmt
	t.sel.stmt, t.sel.names = qb.Select(m.Name).Where(t.partKeyCmp...).ToCql()
	// prepare insert stmt
	t.insert.stmt, t.insert.names = qb.Insert(m.Name).Columns(m.Columns...).ToCql()

	return t
}

// Metadata returns copy of table metadata.
func (t *Table) Metadata() Metadata {
	return t.metadata
}

// PrimaryKeyCmp returns copy of table's primaryKeyCmp.
func (t *Table) PrimaryKeyCmp() []qb.Cmp {
	primaryKeyCmp := make([]qb.Cmp, len(t.primaryKeyCmp))
	copy(primaryKeyCmp, t.primaryKeyCmp)
	return primaryKeyCmp
}

// Name returns table name.
func (t *Table) Name() string {
	return t.metadata.Name
}

// Get returns select by primary key statement.
func (t *Table) Get(columns ...string) (stmt string, names []string) {
	if len(columns) == 0 {
		return t.get.stmt, t.get.names
	}

	return qb.Select(t.metadata.Name).
		Columns(columns...).
		Where(t.primaryKeyCmp...).
		ToCql()
}

// GetQuery returns query which gets by partition key.
func (t *Table) GetQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Get(columns...))
}

// GetQueryContext returns query wrapped with context which gets by partition key.
func (t *Table) GetQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.GetQuery(session, columns...).WithContext(ctx)
}

// Select returns select by partition key statement.
func (t *Table) Select(columns ...string) (stmt string, names []string) {
	if len(columns) == 0 {
		return t.sel.stmt, t.sel.names
	}

	return qb.Select(t.metadata.Name).
		Columns(columns...).
		Where(t.primaryKeyCmp[0:len(t.metadata.PartKey)]...).
		ToCql()
}

// SelectQuery returns query which selects by partition key statement.
func (t *Table) SelectQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Select(columns...))
}

// SelectQueryContext returns query wrapped with context which selects by partition key statement.
func (t *Table) SelectQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.SelectQuery(session, columns...).WithContext(ctx)
}

// SelectBuilder returns a builder initialised to select by partition key
// statement.
func (t *Table) SelectBuilder(columns ...string) *qb.SelectBuilder {
	return qb.Select(t.metadata.Name).Columns(columns...).Where(t.partKeyCmp...)
}

// SelectAll returns select * statement.
func (t *Table) SelectAll() (stmt string, names []string) {
	return qb.Select(t.metadata.Name).ToCql()
}

// Insert returns insert all columns statement.
func (t *Table) Insert() (stmt string, names []string) {
	return t.insert.stmt, t.insert.names
}

// InsertQuery returns query which inserts all columns.
func (t *Table) InsertQuery(session gocqlx.Session) *gocqlx.Queryx {
	return session.Query(t.Insert())
}

// InsertQueryContext returns query wrapped with context which inserts all columns.
func (t *Table) InsertQueryContext(ctx context.Context, session gocqlx.Session) *gocqlx.Queryx {
	return t.InsertQuery(session).WithContext(ctx)
}

// InsertBuilder returns a builder initialised with all columns.
func (t *Table) InsertBuilder() *qb.InsertBuilder {
	return qb.Insert(t.metadata.Name).Columns(t.metadata.Columns...)
}

// Update returns update by primary key statement.
func (t *Table) Update(columns ...string) (stmt string, names []string) {
	return t.UpdateBuilder(columns...).ToCql()
}

// UpdateQuery returns query which updates by primary key.
func (t *Table) UpdateQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Update(columns...))
}

// UpdateQueryContext returns query wrapped with context which updates by primary key.
func (t *Table) UpdateQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.UpdateQuery(session, columns...).WithContext(ctx)
}

// UpdateBuilder returns a builder initialised to update by primary key statement.
func (t *Table) UpdateBuilder(columns ...string) *qb.UpdateBuilder {
	return qb.Update(t.metadata.Name).Set(columns...).Where(t.primaryKeyCmp...)
}

// Delete returns delete by primary key statement.
func (t *Table) Delete(columns ...string) (stmt string, names []string) {
	return t.DeleteBuilder(columns...).ToCql()
}

// DeleteQuery returns query which delete by primary key.
func (t *Table) DeleteQuery(session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return session.Query(t.Delete(columns...))
}

// DeleteQueryContext returns query wrapped with context which delete by primary key.
func (t *Table) DeleteQueryContext(ctx context.Context, session gocqlx.Session, columns ...string) *gocqlx.Queryx {
	return t.DeleteQuery(session, columns...).WithContext(ctx)
}

// DeleteBuilder returns a builder initialised to delete by primary key statement.
func (t *Table) DeleteBuilder(columns ...string) *qb.DeleteBuilder {
	return qb.Delete(t.metadata.Name).Columns(columns...).Where(t.primaryKeyCmp...)
}
<|endoftext|>


<commit_before>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/api"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGetTables(t *testing.T) {
	Convey("Get tables without custom where clause", t, func() {
		r, err := http.NewRequest("GET", "/tables", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables1")
	})

	Convey("Get tables with custom where clause", t, func() {
		r, err := http.NewRequest("GET", "/tables?c.relname=test", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables2")
	})

	Convey("Get tables with custom where clause and pagination", t, func() {
		r, err := http.NewRequest("GET", "/tables?c.relname=test&_page=1&_page_size=20", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables3")
	})
}

func TestGetTablesByDatabaseAndSchema(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}", GetTablesByDatabaseAndSchema).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("Get tables by database and schema without custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public", "GetTablesByDatabaseAndSchema")
	})

	Convey("Get tables by database and schema with custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public?t.tablename=test", "GetTablesByDatabaseAndSchema")
	})

	Convey("Get tables by database and schema with custom where clause and pagination", t, func() {
		doValidGetRequest(server.URL+"/prest/public?t.tablename=test&_page=1&_page_size=20", "GetTablesByDatabaseAndSchema")
	})
}

func TestSelectFromTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", SelectFromTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("execute select in a table without custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test", "SelectFromTables")
	})

	Convey("execute select in a table with custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test?name=nuveo", "SelectFromTables")
	})

	Convey("execute select in a table with custom where clause and pagination", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test?name=nuveo&_page=1&_page_size=20", "SelectFromTables")
	})
}

func TestInsertInTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", InsertInTables).Methods("POST")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("execute select in a table without custom where clause", t, func() {
		r := api.Request{
			Data: map[string]string{
				"name": "prest",
			},
		}
		doValidPostRequest(server.URL+"/prest/public/test", r, "InsertInTables")
	})
}

func TestDeleteFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", DeleteFromTable).Methods("DELETE")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("excute delete in a table without where clause", t, func() {
		doValidDeleteRequest(server.URL+"/prest/public/test", "DeleteFromTable")
	})
	Convey("excute delete in a table with where clause", t, func() {
		doValidDeleteRequest(server.URL+"/prest/public/test?name=nuveo", "DeleteFromTable")
	})
}

func TestUpdateFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", UpdateTable).Methods("PUT", "PATCH")
	server := httptest.NewServer(router)
	defer server.Close()
	r := api.Request{
		Data: map[string]string{
			"name": "prest",
		},
	}
	Convey("excute update in a table without where clause using PUT", t, func() {
		doValidPutRequest(server.URL+"/prest/public/test", r, "UpdateTable")
	})
	Convey("excute update in a table with where clause using PUT", t, func() {
		doValidPutRequest(server.URL+"/prest/public/test?name=nuveo", r, "UpdateTable")
	})
	Convey("excute update in a table without where clause using PATCH", t, func() {
		doValidPatchRequest(server.URL+"/prest/public/test", r, "UpdateTable")
	})
	Convey("excute update in a table with where clause using PATCH", t, func() {
		doValidPatchRequest(server.URL+"/prest/public/test?name=nuveo", r, "UpdateTable")
	})
}
<commit_msg>correct "whereValues" vector order<commit_after>package controllers

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/api"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGetTables(t *testing.T) {
	Convey("Get tables without custom where clause", t, func() {
		r, err := http.NewRequest("GET", "/tables", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables1")
	})

	Convey("Get tables with custom where clause", t, func() {
		r, err := http.NewRequest("GET", "/tables?c.relname=test", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables2")
	})

	Convey("Get tables with custom where clause and pagination", t, func() {
		r, err := http.NewRequest("GET", "/tables?c.relname=test&_page=1&_page_size=20", nil)
		w := httptest.NewRecorder()
		So(err, ShouldBeNil)
		validate(w, r, GetTables, "TestGetTables3")
	})
}

func TestGetTablesByDatabaseAndSchema(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}", GetTablesByDatabaseAndSchema).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("Get tables by database and schema without custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public", "GetTablesByDatabaseAndSchema")
	})

	Convey("Get tables by database and schema with custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public?t.tablename=test", "GetTablesByDatabaseAndSchema")
	})

	Convey("Get tables by database and schema with custom where clause and pagination", t, func() {
		doValidGetRequest(server.URL+"/prest/public?t.tablename=test&_page=1&_page_size=20", "GetTablesByDatabaseAndSchema")
	})
}

func TestSelectFromTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", SelectFromTables).Methods("GET")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("execute select in a table without custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test", "SelectFromTables")
	})

	Convey("execute select in a table with custom where clause", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test?name=nuveo", "SelectFromTables")
	})

	Convey("execute select in a table with custom where clause and pagination", t, func() {
		doValidGetRequest(server.URL+"/prest/public/test?name=nuveo&_page=1&_page_size=20", "SelectFromTables")
	})
}

func TestInsertInTables(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", InsertInTables).Methods("POST")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("execute select in a table without custom where clause", t, func() {

		m := make(map[string]interface{}, 0)
		m["name"] = "prest"

		r := api.Request{
			Data: m,
		}

		doValidPostRequest(server.URL+"/prest/public/test", r, "InsertInTables")
	})
}

func TestDeleteFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", DeleteFromTable).Methods("DELETE")
	server := httptest.NewServer(router)
	defer server.Close()
	Convey("excute delete in a table without where clause", t, func() {
		doValidDeleteRequest(server.URL+"/prest/public/test", "DeleteFromTable")
	})
	Convey("excute delete in a table with where clause", t, func() {
		doValidDeleteRequest(server.URL+"/prest/public/test?name=nuveo", "DeleteFromTable")
	})
}

func TestUpdateFromTable(t *testing.T) {
	router := mux.NewRouter()
	router.HandleFunc("/{database}/{schema}/{table}", UpdateTable).Methods("PUT", "PATCH")
	server := httptest.NewServer(router)
	defer server.Close()

	m := make(map[string]interface{}, 0)
	m["name"] = "prest"

	r := api.Request{
		Data: m,
	}

	Convey("excute update in a table without where clause using PUT", t, func() {
		doValidPutRequest(server.URL+"/prest/public/test", r, "UpdateTable")
	})
	Convey("excute update in a table with where clause using PUT", t, func() {
		doValidPutRequest(server.URL+"/prest/public/test?name=nuveo", r, "UpdateTable")
	})
	Convey("excute update in a table without where clause using PATCH", t, func() {
		doValidPatchRequest(server.URL+"/prest/public/test", r, "UpdateTable")
	})
	Convey("excute update in a table with where clause using PATCH", t, func() {
		doValidPatchRequest(server.URL+"/prest/public/test?name=nuveo", r, "UpdateTable")
	})
}
<|endoftext|>


<commit_before>package command

import (
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/logutils"
	"github.com/hashicorp/vault/audit"
	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/helper/flag-slice"
	"github.com/hashicorp/vault/helper/gated-writer"
	vaulthttp "github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// ServerCommand is a Command that starts the Vault server.
type ServerCommand struct {
	AuditBackends      map[string]audit.Factory
	CredentialBackends map[string]logical.Factory
	LogicalBackends    map[string]logical.Factory

	Meta
}

func (c *ServerCommand) Run(args []string) int {
	var dev bool
	var configPath []string
	var logLevel string
	flags := c.Meta.FlagSet("server", FlagSetDefault)
	flags.BoolVar(&dev, "dev", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config")
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Validation
	if !dev && len(configPath) == 0 {
		c.Ui.Error("At least one config path must be specified with -config")
		flags.Usage()
		return 1
	}

	// Load the configuration
	var config *server.Config
	if dev {
		config = server.DevConfig()
	}
	for _, path := range configPath {
		current, err := server.LoadConfig(path)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error loading configuration from %s: %s", path, err))
			return 1
		}

		if config == nil {
			config = current
		} else {
			config = config.Merge(current)
		}
	}

	// Create a logger. We wrap it in a gated writer so that it doesn't
	// start logging too early.
	logGate := &gatedwriter.Writer{Writer: os.Stderr}
	logger := log.New(&logutils.LevelFilter{
		Levels: []logutils.LogLevel{
			"TRACE", "DEBUG", "INFO", "WARN", "ERR"},
		MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)),
		Writer:   logGate,
	}, "", log.LstdFlags)

	// Initialize the backend
	backend, err := physical.NewBackend(
		config.Backend.Type, config.Backend.Config)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing backend of type %s: %s",
			config.Backend.Type, err))
		return 1
	}

	// Initialize the core
	core, err := vault.NewCore(&vault.CoreConfig{
		Physical:           backend,
		AuditBackends:      c.AuditBackends,
		CredentialBackends: c.CredentialBackends,
		LogicalBackends:    c.LogicalBackends,
		Logger:             logger,
	})

	// If we're in dev mode, then initialize the core
	if dev {
		init, err := c.enableDev(core)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing dev mode: %s", err))
			return 1
		}

		c.Ui.Output(fmt.Sprintf(
			"WARNING: Dev mode is enabled!\n\n"+
				"In this mode, Vault is completely in-memory and unsealed.\n"+
				"Vault is configured to only have a single unseal key. The root\n"+
				"token has already been authenticated with the CLI, so you can\n"+
				"immediately begin using the Vault CLI.\n\n"+
				"The unseal key and root token are reproduced below in case you\n"+
				"want to seal/unseal the Vault or play with authentication.\n\n"+
				"Unseal Key: %s\nRoot Token: %s\n",
			hex.EncodeToString(init.SecretShares[0]),
			init.RootToken,
		))
	}

	// Compile server information for output later
	infoKeys := make([]string, 0, 10)
	info := make(map[string]string)
	info["backend"] = config.Backend.Type
	info["log level"] = logLevel
	infoKeys = append(infoKeys, "log level", "backend")

	// Initialize the listeners
	lns := make([]net.Listener, 0, len(config.Listeners))
	for i, lnConfig := range config.Listeners {
		ln, props, err := server.NewListener(lnConfig.Type, lnConfig.Config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing listener of type %s: %s",
				lnConfig.Type, err))
			return 1
		}

		// Store the listener props for output later
		key := fmt.Sprintf("listener %d", i+1)
		propsList := make([]string, 0, len(props))
		for k, v := range props {
			propsList = append(propsList, fmt.Sprintf(
				"%s: %q", k, v))
		}
		sort.Strings(propsList)
		infoKeys = append(infoKeys, key)
		info[key] = fmt.Sprintf(
			"%s (%s)", lnConfig.Type, strings.Join(propsList, ", "))

		lns = append(lns, ln)
	}

	// Initialize the HTTP server
	server := &http.Server{}
	server.Handler = vaulthttp.Handler(core)
	for _, ln := range lns {
		go server.Serve(ln)
	}

	// Server configuration output
	padding := 18
	c.Ui.Output("==> Vault server configuration:\n")
	for _, k := range infoKeys {
		c.Ui.Output(fmt.Sprintf(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k]))
	}
	c.Ui.Output("")

	// Output the header that the server has started
	c.Ui.Output("==> Vault server started! Log data will stream in below:\n")

	// Release the log gate.
	logGate.Flush()

	<-make(chan struct{})
	return 0
}

func (c *ServerCommand) enableDev(core *vault.Core) (*vault.InitResult, error) {
	// Initialize it with a basic single key
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		return nil, err
	}

	// Copy the key so that it can be zeroed
	key := make([]byte, len(init.SecretShares[0]))
	copy(key, init.SecretShares[0])

	// Unseal the core
	unsealed, err := core.Unseal(key)
	if err != nil {
		return nil, err
	}
	if !unsealed {
		return nil, fmt.Errorf("failed to unseal Vault for dev mode")
	}

	// Set the token
	tokenHelper, err := c.TokenHelper()
	if err != nil {
		return nil, err
	}
	if err := tokenHelper.Store(init.RootToken); err != nil {
		return nil, err
	}

	return init, nil
}

func (c *ServerCommand) Synopsis() string {
	return "Start a Vault server"
}

func (c *ServerCommand) Help() string {
	helpText := `
Usage: vault server [options]

  Start a Vault server.

  This command starts a Vault server that responds to API requests.
  Vault will start in a "sealed" state. The Vault must be unsealed
  with "vault unseal" or the API before this server can respond to requests.
  This must be done for every server.

  If the server is being started against a storage backend that has
  brand new (no existing Vault data in it), it must be initialized with
  "vault init" or the API first.

General Options:

  -config=<path>      Path to the configuration file or directory. This can be
                      specified multiple times. If it is a directory, all
                      files with a ".hcl" or ".json" suffix will be loaded.

  -log-level=info     Log verbosity. Defaults to "info", will be outputted
                      to stderr.

`
	return strings.TrimSpace(helpText)
}
<commit_msg>command/server: env var for dev mode<commit_after>package command

import (
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/logutils"
	"github.com/hashicorp/vault/audit"
	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/helper/flag-slice"
	"github.com/hashicorp/vault/helper/gated-writer"
	vaulthttp "github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// ServerCommand is a Command that starts the Vault server.
type ServerCommand struct {
	AuditBackends      map[string]audit.Factory
	CredentialBackends map[string]logical.Factory
	LogicalBackends    map[string]logical.Factory

	Meta
}

func (c *ServerCommand) Run(args []string) int {
	var dev bool
	var configPath []string
	var logLevel string
	flags := c.Meta.FlagSet("server", FlagSetDefault)
	flags.BoolVar(&dev, "dev", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config")
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Validation
	if !dev && len(configPath) == 0 {
		c.Ui.Error("At least one config path must be specified with -config")
		flags.Usage()
		return 1
	}

	// Load the configuration
	var config *server.Config
	if dev {
		config = server.DevConfig()
	}
	for _, path := range configPath {
		current, err := server.LoadConfig(path)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error loading configuration from %s: %s", path, err))
			return 1
		}

		if config == nil {
			config = current
		} else {
			config = config.Merge(current)
		}
	}

	// Create a logger. We wrap it in a gated writer so that it doesn't
	// start logging too early.
	logGate := &gatedwriter.Writer{Writer: os.Stderr}
	logger := log.New(&logutils.LevelFilter{
		Levels: []logutils.LogLevel{
			"TRACE", "DEBUG", "INFO", "WARN", "ERR"},
		MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)),
		Writer:   logGate,
	}, "", log.LstdFlags)

	// Initialize the backend
	backend, err := physical.NewBackend(
		config.Backend.Type, config.Backend.Config)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing backend of type %s: %s",
			config.Backend.Type, err))
		return 1
	}

	// Initialize the core
	core, err := vault.NewCore(&vault.CoreConfig{
		Physical:           backend,
		AuditBackends:      c.AuditBackends,
		CredentialBackends: c.CredentialBackends,
		LogicalBackends:    c.LogicalBackends,
		Logger:             logger,
	})

	// If we're in dev mode, then initialize the core
	if dev {
		init, err := c.enableDev(core)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing dev mode: %s", err))
			return 1
		}

		c.Ui.Output(fmt.Sprintf(
			"WARNING: Dev mode is enabled!\n\n"+
				"In this mode, Vault is completely in-memory and unsealed.\n"+
				"Vault is configured to only have a single unseal key. The root\n"+
				"token has already been authenticated with the CLI, so you can\n"+
				"immediately begin using the Vault CLI.\n\n"+
				"The only step you need to take is to set the following\n"+
				"environment variable since Vault will be taking without TLS:\n\n"+
				"    export VAULT_ADDR='http://127.0.0.1:8200'\n\n"+
				"The unseal key and root token are reproduced below in case you\n"+
				"want to seal/unseal the Vault or play with authentication.\n\n"+
				"Unseal Key: %s\nRoot Token: %s\n",
			hex.EncodeToString(init.SecretShares[0]),
			init.RootToken,
		))
	}

	// Compile server information for output later
	infoKeys := make([]string, 0, 10)
	info := make(map[string]string)
	info["backend"] = config.Backend.Type
	info["log level"] = logLevel
	infoKeys = append(infoKeys, "log level", "backend")

	// Initialize the listeners
	lns := make([]net.Listener, 0, len(config.Listeners))
	for i, lnConfig := range config.Listeners {
		ln, props, err := server.NewListener(lnConfig.Type, lnConfig.Config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing listener of type %s: %s",
				lnConfig.Type, err))
			return 1
		}

		// Store the listener props for output later
		key := fmt.Sprintf("listener %d", i+1)
		propsList := make([]string, 0, len(props))
		for k, v := range props {
			propsList = append(propsList, fmt.Sprintf(
				"%s: %q", k, v))
		}
		sort.Strings(propsList)
		infoKeys = append(infoKeys, key)
		info[key] = fmt.Sprintf(
			"%s (%s)", lnConfig.Type, strings.Join(propsList, ", "))

		lns = append(lns, ln)
	}

	// Initialize the HTTP server
	server := &http.Server{}
	server.Handler = vaulthttp.Handler(core)
	for _, ln := range lns {
		go server.Serve(ln)
	}

	// Server configuration output
	padding := 18
	c.Ui.Output("==> Vault server configuration:\n")
	for _, k := range infoKeys {
		c.Ui.Output(fmt.Sprintf(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k]))
	}
	c.Ui.Output("")

	// Output the header that the server has started
	c.Ui.Output("==> Vault server started! Log data will stream in below:\n")

	// Release the log gate.
	logGate.Flush()

	<-make(chan struct{})
	return 0
}

func (c *ServerCommand) enableDev(core *vault.Core) (*vault.InitResult, error) {
	// Initialize it with a basic single key
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		return nil, err
	}

	// Copy the key so that it can be zeroed
	key := make([]byte, len(init.SecretShares[0]))
	copy(key, init.SecretShares[0])

	// Unseal the core
	unsealed, err := core.Unseal(key)
	if err != nil {
		return nil, err
	}
	if !unsealed {
		return nil, fmt.Errorf("failed to unseal Vault for dev mode")
	}

	// Set the token
	tokenHelper, err := c.TokenHelper()
	if err != nil {
		return nil, err
	}
	if err := tokenHelper.Store(init.RootToken); err != nil {
		return nil, err
	}

	return init, nil
}

func (c *ServerCommand) Synopsis() string {
	return "Start a Vault server"
}

func (c *ServerCommand) Help() string {
	helpText := `
Usage: vault server [options]

  Start a Vault server.

  This command starts a Vault server that responds to API requests.
  Vault will start in a "sealed" state. The Vault must be unsealed
  with "vault unseal" or the API before this server can respond to requests.
  This must be done for every server.

  If the server is being started against a storage backend that has
  brand new (no existing Vault data in it), it must be initialized with
  "vault init" or the API first.

General Options:

  -config=<path>      Path to the configuration file or directory. This can be
                      specified multiple times. If it is a directory, all
                      files with a ".hcl" or ".json" suffix will be loaded.

  -log-level=info     Log verbosity. Defaults to "info", will be outputted
                      to stderr.

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>package tasklog

import (
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"sync"
	"time"

	"github.com/olekukonko/ts"
)

const (
	DefaultLoggingThrottle = 200 * time.Millisecond
)

// Logger logs a series of tasks to an io.Writer, processing each task in order
// until completion .
type Logger struct {
	// sink is the writer to write to.
	sink io.Writer

	// widthFn is a function that returns the width of the terminal that
	// this logger is running within.
	widthFn func() int

	// throttle is the minimum amount of time that must pass between each
	// instant data is logged.
	throttle time.Duration

	// queue is the incoming, unbuffered queue of tasks to enqueue.
	queue chan Task
	// tasks is the set of tasks to process.
	tasks chan Task
	// wg is a WaitGroup that is incremented when new tasks are enqueued,
	// and decremented when tasks finish.
	wg *sync.WaitGroup
}

// NewLogger retuns a new *Logger instance that logs to "sink" and uses the
// current terminal width as the width of the line.
func NewLogger(sink io.Writer) *Logger {
	if sink == nil {
		sink = ioutil.Discard
	}

	l := &Logger{
		sink:     sink,
		throttle: DefaultLoggingThrottle,
		widthFn: func() int {
			size, err := ts.GetSize()
			if err != nil {
				return 80
			}
			return size.Col()
		},
		queue: make(chan Task),
		tasks: make(chan Task),
		wg:    new(sync.WaitGroup),
	}

	go l.consume()

	return l
}

// Close closes the queue and does not allow new Tasks to be `enqueue()`'d. It
// waits until the currently running Task has completed.
func (l *Logger) Close() {
	if l == nil {
		return
	}

	close(l.queue)

	l.wg.Wait()
}

// Waitier creates and enqueues a new *WaitingTask.
func (l *Logger) Waiter(msg string) *WaitingTask {
	t := NewWaitingTask(msg)
	l.Enqueue(t)

	return t
}

// Percentage creates and enqueues a new *PercentageTask.
func (l *Logger) Percentage(msg string, total uint64) *PercentageTask {
	t := NewPercentageTask(msg, total)
	l.Enqueue(t)

	return t
}

// List creates and enqueues a new *ListTask.
func (l *Logger) List(msg string) *ListTask {
	t := NewListTask(msg)
	l.Enqueue(t)

	return t
}

// Enqueue enqueues the given Tasks "ts".
func (l *Logger) Enqueue(ts ...Task) {
	if l == nil {
		for _, t := range ts {
			go func(t Task) {
				for range t.Updates() {
					// Discard all updates.
				}
			}(t)
		}
		return
	}

	l.wg.Add(len(ts))
	for _, t := range ts {
		l.queue <- t
	}
}

// consume creates a pseudo-infinte buffer between the incoming set of tasks and
// the queue of tasks to work on.
func (l *Logger) consume() {
	go func() {
		// Process the single next task in sequence until completion,
		// then consume the next task.
		for task := range l.tasks {
			l.logTask(task)
		}
	}()

	defer close(l.tasks)

	pending := make([]Task, 0)

	for {
		// If there is a pending task, "peek" it off of the set of
		// pending tasks.
		var next Task
		if len(pending) > 0 {
			next = pending[0]
		}

		if next == nil {
			// If there was no pending task, wait for either a)
			// l.queue to close, or b) a new task to be submitted.
			task, ok := <-l.queue
			if !ok {
				// If the queue is closed, no more new tasks may
				// be added.
				return
			}

			// Otherwise, add a new task to the set of tasks to
			// process immediately, since there is no current
			// buffer.
			l.tasks <- task
		} else {
			// If there is a pending task, wait for either a) a
			// write to process the task to become non-blocking, or
			// b) a new task to enter the queue.
			select {
			case task, ok := <-l.queue:
				if !ok {
					// If the queue is closed, no more tasks
					// may be added.
					return
				}
				// Otherwise, add the next task to the set of
				// pending, active tasks.
				pending = append(pending, task)
			case l.tasks <- next:
				// Or "pop" the peeked task off of the pending
				// set.
				pending = pending[1:]
			}
		}
	}
}

// logTask logs the set of updates from a given task to the sink, then logs a
// "done" message, and then marks the task as done.
//
// By default, the *Logger throttles log entry updates to once per the duration
// of time specified by `l.throttle time.Duration`.
//
// If the duration if 0, or the task is "durable" (by implementing
// github.com/git-lfs/git-lfs/tasklog#DurableTask), then all entries will be
// logged.
func (l *Logger) logTask(task Task) {
	defer l.wg.Done()

	logAll := !task.Throttled()
	var last time.Time

	var update *Update
	for update = range task.Updates() {
		if logAll || l.throttle == 0 || !update.Throttled(last.Add(l.throttle)) {
			l.logLine(update.S)
			last = update.At
		}
	}

	if update != nil {
		// If a task sent no updates, the last recorded update will be
		// nil. Given this, only log a message when there was at least
		// (1) update.
		l.log(fmt.Sprintf("%s, done\n", update.S))
	}
}

// logLine writes a complete line and moves the cursor to the beginning of the
// line.
//
// It returns the number of bytes "n" written to the sink and the error "err",
// if one was encountered.
func (l *Logger) logLine(str string) (n int, err error) {
	padding := strings.Repeat(" ", maxInt(0, l.widthFn()-len(str)))

	return l.log(str + padding + "\r")
}

// log writes a string verbatim to the sink.
//
// It returns the number of bytes "n" written to the sink and the error "err",
// if one was encountered.
func (l *Logger) log(str string) (n int, err error) {
	return fmt.Fprint(l.sink, str)
}

func maxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<commit_msg>tasklog: don't enqueue nil tasks<commit_after>package tasklog

import (
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"sync"
	"time"

	"github.com/olekukonko/ts"
)

const (
	DefaultLoggingThrottle = 200 * time.Millisecond
)

// Logger logs a series of tasks to an io.Writer, processing each task in order
// until completion .
type Logger struct {
	// sink is the writer to write to.
	sink io.Writer

	// widthFn is a function that returns the width of the terminal that
	// this logger is running within.
	widthFn func() int

	// throttle is the minimum amount of time that must pass between each
	// instant data is logged.
	throttle time.Duration

	// queue is the incoming, unbuffered queue of tasks to enqueue.
	queue chan Task
	// tasks is the set of tasks to process.
	tasks chan Task
	// wg is a WaitGroup that is incremented when new tasks are enqueued,
	// and decremented when tasks finish.
	wg *sync.WaitGroup
}

// NewLogger retuns a new *Logger instance that logs to "sink" and uses the
// current terminal width as the width of the line.
func NewLogger(sink io.Writer) *Logger {
	if sink == nil {
		sink = ioutil.Discard
	}

	l := &Logger{
		sink:     sink,
		throttle: DefaultLoggingThrottle,
		widthFn: func() int {
			size, err := ts.GetSize()
			if err != nil {
				return 80
			}
			return size.Col()
		},
		queue: make(chan Task),
		tasks: make(chan Task),
		wg:    new(sync.WaitGroup),
	}

	go l.consume()

	return l
}

// Close closes the queue and does not allow new Tasks to be `enqueue()`'d. It
// waits until the currently running Task has completed.
func (l *Logger) Close() {
	if l == nil {
		return
	}

	close(l.queue)

	l.wg.Wait()
}

// Waitier creates and enqueues a new *WaitingTask.
func (l *Logger) Waiter(msg string) *WaitingTask {
	t := NewWaitingTask(msg)
	l.Enqueue(t)

	return t
}

// Percentage creates and enqueues a new *PercentageTask.
func (l *Logger) Percentage(msg string, total uint64) *PercentageTask {
	t := NewPercentageTask(msg, total)
	l.Enqueue(t)

	return t
}

// List creates and enqueues a new *ListTask.
func (l *Logger) List(msg string) *ListTask {
	t := NewListTask(msg)
	l.Enqueue(t)

	return t
}

// Enqueue enqueues the given Tasks "ts".
func (l *Logger) Enqueue(ts ...Task) {
	if l == nil {
		for _, t := range ts {
			if t == nil {
				// NOTE: Do not allow nil tasks which are unable
				// to be completed.
				continue
			}
			go func(t Task) {
				for range t.Updates() {
					// Discard all updates.
				}
			}(t)
		}
		return
	}

	l.wg.Add(len(ts))
	for _, t := range ts {
		if t == nil {
			// NOTE: See above.
			continue
		}
		l.queue <- t
	}
}

// consume creates a pseudo-infinte buffer between the incoming set of tasks and
// the queue of tasks to work on.
func (l *Logger) consume() {
	go func() {
		// Process the single next task in sequence until completion,
		// then consume the next task.
		for task := range l.tasks {
			l.logTask(task)
		}
	}()

	defer close(l.tasks)

	pending := make([]Task, 0)

	for {
		// If there is a pending task, "peek" it off of the set of
		// pending tasks.
		var next Task
		if len(pending) > 0 {
			next = pending[0]
		}

		if next == nil {
			// If there was no pending task, wait for either a)
			// l.queue to close, or b) a new task to be submitted.
			task, ok := <-l.queue
			if !ok {
				// If the queue is closed, no more new tasks may
				// be added.
				return
			}

			// Otherwise, add a new task to the set of tasks to
			// process immediately, since there is no current
			// buffer.
			l.tasks <- task
		} else {
			// If there is a pending task, wait for either a) a
			// write to process the task to become non-blocking, or
			// b) a new task to enter the queue.
			select {
			case task, ok := <-l.queue:
				if !ok {
					// If the queue is closed, no more tasks
					// may be added.
					return
				}
				// Otherwise, add the next task to the set of
				// pending, active tasks.
				pending = append(pending, task)
			case l.tasks <- next:
				// Or "pop" the peeked task off of the pending
				// set.
				pending = pending[1:]
			}
		}
	}
}

// logTask logs the set of updates from a given task to the sink, then logs a
// "done" message, and then marks the task as done.
//
// By default, the *Logger throttles log entry updates to once per the duration
// of time specified by `l.throttle time.Duration`.
//
// If the duration if 0, or the task is "durable" (by implementing
// github.com/git-lfs/git-lfs/tasklog#DurableTask), then all entries will be
// logged.
func (l *Logger) logTask(task Task) {
	defer l.wg.Done()

	logAll := !task.Throttled()
	var last time.Time

	var update *Update
	for update = range task.Updates() {
		if logAll || l.throttle == 0 || !update.Throttled(last.Add(l.throttle)) {
			l.logLine(update.S)
			last = update.At
		}
	}

	if update != nil {
		// If a task sent no updates, the last recorded update will be
		// nil. Given this, only log a message when there was at least
		// (1) update.
		l.log(fmt.Sprintf("%s, done\n", update.S))
	}
}

// logLine writes a complete line and moves the cursor to the beginning of the
// line.
//
// It returns the number of bytes "n" written to the sink and the error "err",
// if one was encountered.
func (l *Logger) logLine(str string) (n int, err error) {
	padding := strings.Repeat(" ", maxInt(0, l.widthFn()-len(str)))

	return l.log(str + padding + "\r")
}

// log writes a string verbatim to the sink.
//
// It returns the number of bytes "n" written to the sink and the error "err",
// if one was encountered.
func (l *Logger) log(str string) (n int, err error) {
	return fmt.Fprint(l.sink, str)
}

func maxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package common

import "net"

type Payload struct {
	Raw       []byte
	Packet    []byte
	IpAddress []byte
	Nonce     []byte
	Length    int
	Address   *net.UDPAddr
}

func NewTunPayload(raw []byte, packetLength int) *Payload {
	ip := raw[IpStart:IpEnd]
	nonce := raw[NonceStart:NonceEnd]
	pkt := raw[PacketStart : PacketStart+packetLength]

	return &Payload{
		Raw:       raw,
		IpAddress: ip,
		Nonce:     nonce,
		Packet:    pkt,
		Length:    PacketStart + packetLength + BlockSize,
	}
}

func NewSockPayload(raw []byte, packetLength int) *Payload {
	ip := raw[IpStart:IpEnd]
	nonce := raw[NonceStart:NonceEnd]
	pkt := raw[PacketStart:packetLength]

	return &Payload{
		Raw:       raw,
		IpAddress: ip,
		Nonce:     nonce,
		Packet:    pkt,
	}
}
<commit_msg>Backing out test code<commit_after>package common

type Payload struct {
	Raw       []byte
	Packet    []byte
	IpAddress []byte
	Nonce     []byte
	Length    int
}

func NewTunPayload(raw []byte, packetLength int) *Payload {
	ip := raw[IpStart:IpEnd]
	nonce := raw[NonceStart:NonceEnd]
	pkt := raw[PacketStart : PacketStart+packetLength]

	return &Payload{
		Raw:       raw,
		IpAddress: ip,
		Nonce:     nonce,
		Packet:    pkt,
		Length:    PacketStart + packetLength + BlockSize,
	}
}

func NewSockPayload(raw []byte, packetLength int) *Payload {
	ip := raw[IpStart:IpEnd]
	nonce := raw[NonceStart:NonceEnd]
	pkt := raw[PacketStart:packetLength]

	return &Payload{
		Raw:       raw,
		IpAddress: ip,
		Nonce:     nonce,
		Packet:    pkt,
	}
}
<|endoftext|>


<commit_before>package certificate

import (
	"crypto/x509"
	"testing"

	"github.com/chrjoh/certificateBar/key"
)

func TestCreateCertificateCahin(t *testing.T) {

	ca, caPriv := createCA()
	caPub := key.PublicKey(caPriv)
	caBytes := Sign(ca, ca, caPub, caPriv)
	interCa, interCaPriv := createInterCA()
	interCaPub := key.PublicKey(interCaPriv)
	interCaBytes := Sign(interCa, ca, interCaPub, caPriv)

	client, clientPriv := createClient()
	clientPub := key.PublicKey(clientPriv)
	clientBytes := Sign(client, interCa, clientPub, interCaPriv)
	chainOk := CheckCertificate(caBytes, interCaBytes, clientBytes)
	if !chainOk {
		t.Fatal("Failed to create certificate chain")
	}
}

func createCA() (*x509.Certificate, interface{}) {
	caData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "WebCA",
		CA:                 true,
		SubjectKey:         []byte{1, 2, 3, 4, 5, 6},
	}

	caPriv := key.GenerateKey("P224", 0)
	return CreateCertificateTemplate(caData), caPriv
}

func createInterCA() (*x509.Certificate, interface{}) {
	interCaData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "WebInterCA",
		CA:                 true,
		SubjectKey:         []byte{1, 2, 3},
	}
	interCaPriv := key.GenerateKey("RSA", 1024) // use small key for fast generation
	return CreateCertificateTemplate(interCaData), interCaPriv
}

func createClient() (*x509.Certificate, interface{}) {
	clientData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "Web",
		CA:                 false,
		SubjectKey:         []byte{1, 6},
		CommonName:         "www.baz.se",
		AlternativeNames:   []string{"www.baz.se", "www.foo.se", "www.bar.se"},
	}
	clientPriv := key.GenerateKey("RSA", 1024)
	return CreateCertificateTemplate(clientData), clientPriv
}
<commit_msg>split some test checks<commit_after>package certificate

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"testing"

	"github.com/chrjoh/certificateBar/key"
)

var (
	OU = asn1.ObjectIdentifier{2, 5, 4, 11}
)

func TestCreateCertificateCahin(t *testing.T) {
	ca, caPriv := createCA()
	caPub := key.PublicKey(caPriv)
	caBytes := Sign(ca, ca, caPub, caPriv)
	interCa, interCaPriv := createInterCA()
	interCaPub := key.PublicKey(interCaPriv)
	interCaBytes := Sign(interCa, ca, interCaPub, caPriv)
	client, clientPriv := createClient()
	clientPub := key.PublicKey(clientPriv)
	clientBytes := Sign(client, interCa, clientPub, interCaPriv)

	clientCert, _ := x509.ParseCertificate(clientBytes)
	ouIssuer := getPkixValue(clientCert.Issuer.Names, OU)
	if ouIssuer != "WebInterCA" {
		t.Fatalf("Wrong issuer ou wanted: WebInterCA, got: %v\n", ouIssuer)
	}
	interCert, _ := x509.ParseCertificate(interCaBytes)
	ouIssuer = getPkixValue(interCert.Issuer.Names, OU)
	if ouIssuer != "WebCA" {
		t.Fatalf("Wrong issuer ou wanted: WebCA, got: %v\n", ouIssuer)
	}
	caCert, _ := x509.ParseCertificate(caBytes)
	ouIssuer = getPkixValue(caCert.Issuer.Names, OU)
	if ouIssuer != "WebCA" {
		t.Fatalf("Wrong issuer ou wanted: WebCA, got: %v\n", ouIssuer)
	}
}

func TestValidSignedCertificateCahin(t *testing.T) {

	ca, caPriv := createCA()
	caPub := key.PublicKey(caPriv)
	caBytes := Sign(ca, ca, caPub, caPriv)
	interCa, interCaPriv := createInterCA()
	interCaPub := key.PublicKey(interCaPriv)
	interCaBytes := Sign(interCa, ca, interCaPub, caPriv)
	client, clientPriv := createClient()
	clientPub := key.PublicKey(clientPriv)
	clientBytes := Sign(client, interCa, clientPub, interCaPriv)
	chainOk := CheckCertificate(caBytes, interCaBytes, clientBytes)
	if !chainOk {
		t.Fatal("Failed to create certificate chain")
	}
}
func createCA() (*x509.Certificate, interface{}) {
	caData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "WebCA",
		CA:                 true,
		SubjectKey:         []byte{1, 2, 3, 4, 5, 6},
	}

	caPriv := key.GenerateKey("P224", 0)
	return CreateCertificateTemplate(caData), caPriv
}

func createInterCA() (*x509.Certificate, interface{}) {
	interCaData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "WebInterCA",
		CA:                 true,
		SubjectKey:         []byte{1, 2, 3},
	}
	interCaPriv := key.GenerateKey("RSA", 1024) // use small key for fast generation
	return CreateCertificateTemplate(interCaData), interCaPriv
}

func createClient() (*x509.Certificate, interface{}) {
	clientData := Certificate{
		Country:            "SE",
		Organization:       "test",
		OrganizationalUnit: "Web",
		CA:                 false,
		SubjectKey:         []byte{1, 6},
		CommonName:         "www.baz.se",
		AlternativeNames:   []string{"www.baz.se", "www.foo.se", "www.bar.se"},
	}
	clientPriv := key.GenerateKey("RSA", 1024)
	return CreateCertificateTemplate(clientData), clientPriv
}

func getPkixValue(values []pkix.AttributeTypeAndValue, key asn1.ObjectIdentifier) string {
	for _, v := range values {
		if v.Type.Equal(key) {
			return v.Value.(string)
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package chainntnfs

import (
	"bytes"
	"errors"

	bolt "github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/channeldb"
)

var (
	// spendHintBucket is the name of the bucket which houses the height
	// hint for outpoints. Each height hint represents the earliest height
	// at which its corresponding outpoint could have been spent within.
	spendHintBucket = []byte("spend-hints")

	// confirmHintBucket is the name of the bucket which houses the height
	// hints for transactions. Each height hint represents the earliest
	// height at which its corresponding transaction could have been
	// confirmed within.
	confirmHintBucket = []byte("confirm-hints")

	// ErrCorruptedHeightHintCache indicates that the on-disk bucketing
	// structure has altered since the height hint cache instance was
	// initialized.
	ErrCorruptedHeightHintCache = errors.New("height hint cache has been " +
		"corrupted")

	// ErrSpendHintNotFound is an error returned when a spend hint for an
	// outpoint was not found.
	ErrSpendHintNotFound = errors.New("spend hint not found")

	// ErrConfirmHintNotFound is an error returned when a confirm hint for a
	// transaction was not found.
	ErrConfirmHintNotFound = errors.New("confirm hint not found")
)

// SpendHintCache is an interface whose duty is to cache spend hints for
// outpoints. A spend hint is defined as the earliest height in the chain at
// which an outpoint could have been spent within.
type SpendHintCache interface {
	// CommitSpendHint commits a spend hint for the outpoints to the cache.
	CommitSpendHint(height uint32, spendRequests ...SpendRequest) error

	// QuerySpendHint returns the latest spend hint for an outpoint.
	// ErrSpendHintNotFound is returned if a spend hint does not exist
	// within the cache for the outpoint.
	QuerySpendHint(spendRequest SpendRequest) (uint32, error)

	// PurgeSpendHint removes the spend hint for the outpoints from the
	// cache.
	PurgeSpendHint(spendRequests ...SpendRequest) error
}

// ConfirmHintCache is an interface whose duty is to cache confirm hints for
// transactions. A confirm hint is defined as the earliest height in the chain
// at which a transaction could have been included in a block.
type ConfirmHintCache interface {
	// CommitConfirmHint commits a confirm hint for the transactions to the
	// cache.
	CommitConfirmHint(height uint32, confRequests ...ConfRequest) error

	// QueryConfirmHint returns the latest confirm hint for a transaction
	// hash. ErrConfirmHintNotFound is returned if a confirm hint does not
	// exist within the cache for the transaction hash.
	QueryConfirmHint(confRequest ConfRequest) (uint32, error)

	// PurgeConfirmHint removes the confirm hint for the transactions from
	// the cache.
	PurgeConfirmHint(confRequests ...ConfRequest) error
}

// HeightHintCache is an implementation of the SpendHintCache and
// ConfirmHintCache interfaces backed by a channeldb DB instance where the hints
// will be stored.
type HeightHintCache struct {
	db *channeldb.DB
}

// Compile-time checks to ensure HeightHintCache satisfies the SpendHintCache
// and ConfirmHintCache interfaces.
var _ SpendHintCache = (*HeightHintCache)(nil)
var _ ConfirmHintCache = (*HeightHintCache)(nil)

// NewHeightHintCache returns a new height hint cache backed by a database.
func NewHeightHintCache(db *channeldb.DB) (*HeightHintCache, error) {
	cache := &HeightHintCache{db}
	if err := cache.initBuckets(); err != nil {
		return nil, err
	}

	return cache, nil
}

// initBuckets ensures that the primary buckets used by the circuit are
// initialized so that we can assume their existence after startup.
func (c *HeightHintCache) initBuckets() error {
	return c.db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(spendHintBucket)
		if err != nil {
			return err
		}

		_, err = tx.CreateBucketIfNotExists(confirmHintBucket)
		return err
	})
}

// CommitSpendHint commits a spend hint for the outpoints to the cache.
func (c *HeightHintCache) CommitSpendHint(height uint32,
	spendRequests ...SpendRequest) error {

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

	Log.Tracef("Updating spend hint to height %d for %v", height,
		spendRequests)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, spendRequest := range spendRequests {
			spendHintKey, err := spendRequest.SpendHintKey()
			if err != nil {
				return err
			}
			err = spendHints.Put(spendHintKey, hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QuerySpendHint returns the latest spend hint for an outpoint.
// ErrSpendHintNotFound is returned if a spend hint does not exist within the
// cache for the outpoint.
func (c *HeightHintCache) QuerySpendHint(spendRequest SpendRequest) (uint32, error) {
	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		spendHintKey, err := spendRequest.SpendHintKey()
		if err != nil {
			return err
		}
		spendHint := spendHints.Get(spendHintKey)
		if spendHint == nil {
			return ErrSpendHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(spendHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeSpendHint removes the spend hint for the outpoints from the cache.
func (c *HeightHintCache) PurgeSpendHint(spendRequests ...SpendRequest) error {
	if len(spendRequests) == 0 {
		return nil
	}

	Log.Tracef("Removing spend hints for %v", spendRequests)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, spendRequest := range spendRequests {
			spendHintKey, err := spendRequest.SpendHintKey()
			if err != nil {
				return err
			}
			if err := spendHints.Delete(spendHintKey); err != nil {
				return err
			}
		}

		return nil
	})
}

// CommitConfirmHint commits a confirm hint for the transactions to the cache.
func (c *HeightHintCache) CommitConfirmHint(height uint32,
	confRequests ...ConfRequest) error {

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

	Log.Tracef("Updating confirm hints to height %d for %v", height,
		confRequests)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, confRequest := range confRequests {
			confHintKey, err := confRequest.ConfHintKey()
			if err != nil {
				return err
			}
			err = confirmHints.Put(confHintKey, hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QueryConfirmHint returns the latest confirm hint for a transaction hash.
// ErrConfirmHintNotFound is returned if a confirm hint does not exist within
// the cache for the transaction hash.
func (c *HeightHintCache) QueryConfirmHint(confRequest ConfRequest) (uint32, error) {
	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		confHintKey, err := confRequest.ConfHintKey()
		if err != nil {
			return err
		}
		confirmHint := confirmHints.Get(confHintKey)
		if confirmHint == nil {
			return ErrConfirmHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(confirmHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeConfirmHint removes the confirm hint for the transactions from the
// cache.
func (c *HeightHintCache) PurgeConfirmHint(confRequests ...ConfRequest) error {
	if len(confRequests) == 0 {
		return nil
	}

	Log.Tracef("Removing confirm hints for %v", confRequests)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, confRequest := range confRequests {
			confHintKey, err := confRequest.ConfHintKey()
			if err != nil {
				return err
			}
			if err := confirmHints.Delete(confHintKey); err != nil {
				return err
			}
		}

		return nil
	})
}
<commit_msg>chainntnfs: convert to use new kvdb abstraction<commit_after>package chainntnfs

import (
	"bytes"
	"errors"

	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/channeldb/kvdb"
)

var (
	// spendHintBucket is the name of the bucket which houses the height
	// hint for outpoints. Each height hint represents the earliest height
	// at which its corresponding outpoint could have been spent within.
	spendHintBucket = []byte("spend-hints")

	// confirmHintBucket is the name of the bucket which houses the height
	// hints for transactions. Each height hint represents the earliest
	// height at which its corresponding transaction could have been
	// confirmed within.
	confirmHintBucket = []byte("confirm-hints")

	// ErrCorruptedHeightHintCache indicates that the on-disk bucketing
	// structure has altered since the height hint cache instance was
	// initialized.
	ErrCorruptedHeightHintCache = errors.New("height hint cache has been " +
		"corrupted")

	// ErrSpendHintNotFound is an error returned when a spend hint for an
	// outpoint was not found.
	ErrSpendHintNotFound = errors.New("spend hint not found")

	// ErrConfirmHintNotFound is an error returned when a confirm hint for a
	// transaction was not found.
	ErrConfirmHintNotFound = errors.New("confirm hint not found")
)

// SpendHintCache is an interface whose duty is to cache spend hints for
// outpoints. A spend hint is defined as the earliest height in the chain at
// which an outpoint could have been spent within.
type SpendHintCache interface {
	// CommitSpendHint commits a spend hint for the outpoints to the cache.
	CommitSpendHint(height uint32, spendRequests ...SpendRequest) error

	// QuerySpendHint returns the latest spend hint for an outpoint.
	// ErrSpendHintNotFound is returned if a spend hint does not exist
	// within the cache for the outpoint.
	QuerySpendHint(spendRequest SpendRequest) (uint32, error)

	// PurgeSpendHint removes the spend hint for the outpoints from the
	// cache.
	PurgeSpendHint(spendRequests ...SpendRequest) error
}

// ConfirmHintCache is an interface whose duty is to cache confirm hints for
// transactions. A confirm hint is defined as the earliest height in the chain
// at which a transaction could have been included in a block.
type ConfirmHintCache interface {
	// CommitConfirmHint commits a confirm hint for the transactions to the
	// cache.
	CommitConfirmHint(height uint32, confRequests ...ConfRequest) error

	// QueryConfirmHint returns the latest confirm hint for a transaction
	// hash. ErrConfirmHintNotFound is returned if a confirm hint does not
	// exist within the cache for the transaction hash.
	QueryConfirmHint(confRequest ConfRequest) (uint32, error)

	// PurgeConfirmHint removes the confirm hint for the transactions from
	// the cache.
	PurgeConfirmHint(confRequests ...ConfRequest) error
}

// HeightHintCache is an implementation of the SpendHintCache and
// ConfirmHintCache interfaces backed by a channeldb DB instance where the hints
// will be stored.
type HeightHintCache struct {
	db *channeldb.DB
}

// Compile-time checks to ensure HeightHintCache satisfies the SpendHintCache
// and ConfirmHintCache interfaces.
var _ SpendHintCache = (*HeightHintCache)(nil)
var _ ConfirmHintCache = (*HeightHintCache)(nil)

// NewHeightHintCache returns a new height hint cache backed by a database.
func NewHeightHintCache(db *channeldb.DB) (*HeightHintCache, error) {
	cache := &HeightHintCache{db}
	if err := cache.initBuckets(); err != nil {
		return nil, err
	}

	return cache, nil
}

// initBuckets ensures that the primary buckets used by the circuit are
// initialized so that we can assume their existence after startup.
func (c *HeightHintCache) initBuckets() error {
	return kvdb.Batch(c.db.Backend, func(tx kvdb.RwTx) error {
		_, err := tx.CreateTopLevelBucket(spendHintBucket)
		if err != nil {
			return err
		}

		_, err = tx.CreateTopLevelBucket(confirmHintBucket)
		return err
	})
}

// CommitSpendHint commits a spend hint for the outpoints to the cache.
func (c *HeightHintCache) CommitSpendHint(height uint32,
	spendRequests ...SpendRequest) error {

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

	Log.Tracef("Updating spend hint to height %d for %v", height,
		spendRequests)

	return kvdb.Batch(c.db.Backend, func(tx kvdb.RwTx) error {
		spendHints := tx.ReadWriteBucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, spendRequest := range spendRequests {
			spendHintKey, err := spendRequest.SpendHintKey()
			if err != nil {
				return err
			}
			err = spendHints.Put(spendHintKey, hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QuerySpendHint returns the latest spend hint for an outpoint.
// ErrSpendHintNotFound is returned if a spend hint does not exist within the
// cache for the outpoint.
func (c *HeightHintCache) QuerySpendHint(spendRequest SpendRequest) (uint32, error) {
	var hint uint32
	err := kvdb.View(c.db, func(tx kvdb.ReadTx) error {
		spendHints := tx.ReadBucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		spendHintKey, err := spendRequest.SpendHintKey()
		if err != nil {
			return err
		}
		spendHint := spendHints.Get(spendHintKey)
		if spendHint == nil {
			return ErrSpendHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(spendHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeSpendHint removes the spend hint for the outpoints from the cache.
func (c *HeightHintCache) PurgeSpendHint(spendRequests ...SpendRequest) error {
	if len(spendRequests) == 0 {
		return nil
	}

	Log.Tracef("Removing spend hints for %v", spendRequests)

	return kvdb.Batch(c.db.Backend, func(tx kvdb.RwTx) error {
		spendHints := tx.ReadWriteBucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, spendRequest := range spendRequests {
			spendHintKey, err := spendRequest.SpendHintKey()
			if err != nil {
				return err
			}
			if err := spendHints.Delete(spendHintKey); err != nil {
				return err
			}
		}

		return nil
	})
}

// CommitConfirmHint commits a confirm hint for the transactions to the cache.
func (c *HeightHintCache) CommitConfirmHint(height uint32,
	confRequests ...ConfRequest) error {

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

	Log.Tracef("Updating confirm hints to height %d for %v", height,
		confRequests)

	return kvdb.Batch(c.db.Backend, func(tx kvdb.RwTx) error {
		confirmHints := tx.ReadWriteBucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, confRequest := range confRequests {
			confHintKey, err := confRequest.ConfHintKey()
			if err != nil {
				return err
			}
			err = confirmHints.Put(confHintKey, hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QueryConfirmHint returns the latest confirm hint for a transaction hash.
// ErrConfirmHintNotFound is returned if a confirm hint does not exist within
// the cache for the transaction hash.
func (c *HeightHintCache) QueryConfirmHint(confRequest ConfRequest) (uint32, error) {
	var hint uint32
	err := kvdb.View(c.db, func(tx kvdb.ReadTx) error {
		confirmHints := tx.ReadBucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		confHintKey, err := confRequest.ConfHintKey()
		if err != nil {
			return err
		}
		confirmHint := confirmHints.Get(confHintKey)
		if confirmHint == nil {
			return ErrConfirmHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(confirmHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeConfirmHint removes the confirm hint for the transactions from the
// cache.
func (c *HeightHintCache) PurgeConfirmHint(confRequests ...ConfRequest) error {
	if len(confRequests) == 0 {
		return nil
	}

	Log.Tracef("Removing confirm hints for %v", confRequests)

	return kvdb.Batch(c.db.Backend, func(tx kvdb.RwTx) error {
		confirmHints := tx.ReadWriteBucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, confRequest := range confRequests {
			confHintKey, err := confRequest.ConfHintKey()
			if err != nil {
				return err
			}
			if err := confirmHints.Delete(confHintKey); err != nil {
				return err
			}
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/ying32/govcl/vcl"

	"github.com/ying32/govcl/vcl/types"
)

func main() {
	vcl.Application.SetIconResId(3)
	vcl.Application.Initialize()
	vcl.Application.SetMainFormOnTaskBar(true)

	mainForm := vcl.Application.CreateForm()
	mainForm.SetCaption("Hello")
	mainForm.SetPosition(types.PoScreenCenter)
	mainForm.SetWidth(500)
	mainForm.SetHeight(700)

	var top int32 = 40
	// TButton
	btn := vcl.NewButton(mainForm)
	btn.SetParent(mainForm)
	btn.SetLeft(10)
	btn.SetTop(top)
	btn.SetCaption("按钮1")
	btn.SetOnClick(func(vcl.IObject) {
		fmt.Println("按钮1单击")
	})

	top += btn.Height() + 5

	// TEdit
	edit := vcl.NewEdit(mainForm)
	edit.SetParent(mainForm)
	edit.SetLeft(10)
	edit.SetTop(top)
	edit.SetTextHint("提示")
	//edit.SetText("文字")
	//	edit.SetReadOnly(true)
	edit.SetOnChange(func(vcl.IObject) {
		fmt.Println("文字改变了")
	})

	top += edit.Height() + 5
	// TEdit Password
	edit = vcl.NewEdit(mainForm)
	edit.SetParent(mainForm)
	edit.SetLeft(10)
	edit.SetTop(top)
	edit.SetText("文字")
	edit.SetPasswordChar('*')

	top += edit.Height() + 5

	// TLabel
	lbl := vcl.NewLabel(mainForm)
	lbl.SetParent(mainForm)
	lbl.SetLeft(10)
	lbl.SetTop(top)
	lbl.SetCaption("标签1")
	lbl.Font().SetColor(255)

	top += lbl.Height() + 5

	// TCheckBox
	chk := vcl.NewCheckBox(mainForm)
	chk.SetParent(mainForm)
	chk.SetLeft(10)
	chk.SetTop(top)
	chk.SetCaption("选择框1")
	chk.SetOnClick(func(vcl.IObject) {
		fmt.Println("checked: ", chk.Checked())
	})

	// TStatusBar
	stat := vcl.NewStatusBar(mainForm)
	stat.SetParent(mainForm)
	//stat.SetSizeGrip(false) // 右解是否有可调的
	spnl := stat.Panels().Add()
	spnl.SetText("第一个")
	spnl.SetWidth(80)

	spnl = stat.Panels().Add()
	spnl.SetText("第二个")
	spnl.SetWidth(80)

	// TToolBar
	tlbar := vcl.NewToolBar(mainForm)
	tlbar.SetParent(mainForm)
	tlbar.SetShowCaptions(true)

	// 倒过来创建
	tlbtn := vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetCaption("2")
	tlbtn.SetStyle(types.TbsDropDown)

	tlbtn = vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetStyle(types.TbsSeparator)

	tlbtn = vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetCaption("1")

	top += chk.Height() + 5
	// TRadioButton
	rd := vcl.NewRadioButton(mainForm)
	rd.SetParent(mainForm)
	rd.SetLeft(10)
	rd.SetTop(top)
	rd.SetCaption("选项1")

	var left int32 = rd.Left() + rd.Width() + 5

	rd = vcl.NewRadioButton(mainForm)
	rd.SetParent(mainForm)
	rd.SetLeft(left)
	rd.SetTop(top)
	rd.SetCaption("选项2")

	top += rd.Height() + 5
	// TMemo
	mmo := vcl.NewMemo(mainForm)
	mmo.SetParent(mainForm)
	mmo.SetBounds(10, top, 167, 50)
	//    mmo.Text()
	mmo.Lines().Add("1")
	mmo.Lines().Add("2")

	top += mmo.Height() + 5
	// TComboBox
	cb := vcl.NewComboBox(mainForm)
	cb.SetParent(mainForm)
	cb.SetLeft(10)
	cb.SetTop(top)
	cb.SetStyle(types.CsDropDownList)
	cb.Items().Add("1")
	cb.Items().Add("2")
	cb.Items().Add("3")
	cb.SetItemIndex(0)
	cb.SetOnChange(func(vcl.IObject) {
		if cb.ItemIndex() != -1 {
			fmt.Println(cb.Items().Strings(cb.ItemIndex()))
		}
	})

	// TListBox
	top += cb.Height() + 5
	lst := vcl.NewListBox(mainForm)
	lst.SetParent(mainForm)
	lst.SetBounds(10, top, 167, 50)
	lst.Items().Add("1")
	lst.Items().Add("2")
	lst.Items().Add("3")

	// TPanel
	top += lst.Height() + 5
	pnl := vcl.NewPanel(mainForm)
	pnl.SetParent(mainForm)
	pnl.SetCaption("fff")
	//    pnl.SetShowCaption(false)
	pnl.SetBounds(10, top, 167, 50)

	// color
	top += pnl.Height() + 5
	clr := vcl.NewColorBox(mainForm)
	clr.SetParent(mainForm)
	clr.SetLeft(10)
	clr.SetTop(top)
	clr.SetOnChange(func(vcl.IObject) {
		if clr.ItemIndex() != -1 {
			lbl.Font().SetColor(clr.Selected())
		}
	})

	// TPageControl
	top += clr.Height() + 5
	pgc := vcl.NewPageControl(mainForm)
	pgc.SetParent(mainForm)
	pgc.SetBounds(10, top, 167, 100)
	pgc.SetOnChange(func(vcl.IObject) {
		fmt.Println("当前索引:", pgc.ActivePageIndex())
	})

	sheet := vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("一")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮1")

	sheet = vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("二")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮2")

	sheet = vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("三")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮3")

	// TImage
	top += pgc.Height() + 5
	img := vcl.NewImage(mainForm)
	img.SetBounds(10, top, 167, 97)
	img.SetParent(mainForm)
	img.Picture().LoadFromFile("1.jpg")
	//img.SetStretch(true)
	img.SetProportional(true)

	left = 210
	top = 10
	// TTrackBar
	trkbar := vcl.NewTrackBar(mainForm)
	trkbar.SetParent(mainForm)
	trkbar.SetBounds(left, top, 167, 20)
	trkbar.SetMax(100)
	trkbar.SetMin(0)
	trkbar.SetPosition(50)

	// TProgressBar
	top += trkbar.Height() + 10
	prgbar := vcl.NewProgressBar(mainForm)
	prgbar.SetParent(mainForm)
	prgbar.SetBounds(left, top, 10, 167)
	prgbar.SetMax(100)
	prgbar.SetMin(0)
	prgbar.SetPosition(1)
	prgbar.SetOrientation(types.PbVertical)

	trkbar.SetOnChange(func(vcl.IObject) {
		prgbar.SetPosition(trkbar.Position())
	})

	top += prgbar.Height() + 10

	dtp := vcl.NewDateTimePicker(mainForm)
	dtp.SetParent(mainForm)
	dtp.SetBounds(left, top, 167, 25)
	dtp.SetFormat("yyyy-MM-dd HH:mm:ss")

	top += dtp.Height() + 10

	mdtp := vcl.NewMonthCalendar(mainForm)
	mdtp.SetParent(mainForm)
	mdtp.SetBounds(left, top, 250, 250)
	mdtp.SetOnClick(func(vcl.IObject) {
		fmt.Println(mdtp.Date())
	})

	top += mdtp.Height() + 10
	dtp.SetDateTime(time.Now().Add(time.Hour * 48))
	dtp.SetDate(time.Now().AddDate(1, 0, 0))
	fmt.Println("time: ", mdtp.Date())

	btn = vcl.NewButton(mainForm)
	btn.SetParent(mainForm)
	btn.SetLeft(left)
	btn.SetTop(top)
	btn.SetCaption("改变日期")
	btn.SetOnClick(func(vcl.IObject) {
		mdtp.SetDate(time.Now().AddDate(-20, 0, 0))
	})

	top += btn.Height() + 10
	spinedit := vcl.NewSpinEdit(mainForm)
	spinedit.SetParent(mainForm)
	spinedit.SetLeft(left)
	spinedit.SetTop(top)
	spinedit.SetWidth(100)
	spinedit.SetMaxValue(10000)
	spinedit.SetMinValue(50)
	spinedit.SetValue(100)
	spinedit.SetOnChange(func(sender vcl.IObject) {
		fmt.Println(spinedit.Value())
	})

	// run
	vcl.Application.Run()
}
<commit_msg>Update<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/ying32/govcl/vcl"

	"github.com/ying32/govcl/vcl/types"
)

func main() {
	vcl.Application.SetIconResId(3)
	vcl.Application.Initialize()
	vcl.Application.SetMainFormOnTaskBar(true)

	mainForm := vcl.Application.CreateForm()
	mainForm.SetCaption("Hello")
	mainForm.SetPosition(types.PoScreenCenter)
	mainForm.SetWidth(500)
	mainForm.SetHeight(700)

	var top int32 = 40
	// TButton
	btn := vcl.NewButton(mainForm)
	btn.SetParent(mainForm)
	btn.SetLeft(10)
	btn.SetTop(top)
	btn.SetCaption("按钮1")
	btn.SetOnClick(func(vcl.IObject) {
		fmt.Println("按钮1单击")
	})

	top += btn.Height() + 5

	// TEdit
	edit := vcl.NewEdit(mainForm)
	edit.SetParent(mainForm)
	edit.SetLeft(10)
	edit.SetTop(top)
	edit.SetTextHint("提示")
	//edit.SetText("文字")
	//	edit.SetReadOnly(true)
	edit.SetOnChange(func(vcl.IObject) {
		fmt.Println("文字改变了")
	})

	top += edit.Height() + 5
	// TEdit Password
	edit = vcl.NewEdit(mainForm)
	edit.SetParent(mainForm)
	edit.SetLeft(10)
	edit.SetTop(top)
	edit.SetText("文字")
	edit.SetPasswordChar('*')

	top += edit.Height() + 5

	// TLabel
	lbl := vcl.NewLabel(mainForm)
	lbl.SetParent(mainForm)
	lbl.SetLeft(10)
	lbl.SetTop(top)
	lbl.SetCaption("标签1")
	lbl.Font().SetColor(255)

	top += lbl.Height() + 5

	// TCheckBox
	chk := vcl.NewCheckBox(mainForm)
	chk.SetParent(mainForm)
	chk.SetLeft(10)
	chk.SetTop(top)
	chk.SetCaption("选择框1")
	chk.SetOnClick(func(vcl.IObject) {
		fmt.Println("checked: ", chk.Checked())
	})

	// TStatusBar
	stat := vcl.NewStatusBar(mainForm)
	stat.SetParent(mainForm)
	//stat.SetSizeGrip(false) // 右解是否有可调的
	spnl := stat.Panels().Add()
	spnl.SetText("第一个")
	spnl.SetWidth(80)

	spnl = stat.Panels().Add()
	spnl.SetText("第二个")
	spnl.SetWidth(80)

	// TToolBar
	tlbar := vcl.NewToolBar(mainForm)
	tlbar.SetParent(mainForm)
	tlbar.SetShowCaptions(true)

	// 倒过来创建
	tlbtn := vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetCaption("2")
	tlbtn.SetStyle(types.TbsDropDown)

	tlbtn = vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetStyle(types.TbsSeparator)

	tlbtn = vcl.NewToolButton(mainForm)
	tlbtn.SetParent(tlbar)
	tlbtn.SetCaption("1")

	top += chk.Height() + 5
	// TRadioButton
	rd := vcl.NewRadioButton(mainForm)
	rd.SetParent(mainForm)
	rd.SetLeft(10)
	rd.SetTop(top)
	rd.SetCaption("选项1")

	var left int32 = rd.Left() + rd.Width() + 5

	rd = vcl.NewRadioButton(mainForm)
	rd.SetParent(mainForm)
	rd.SetLeft(left)
	rd.SetTop(top)
	rd.SetCaption("选项2")

	top += rd.Height() + 5
	// TMemo
	mmo := vcl.NewMemo(mainForm)
	mmo.SetParent(mainForm)
	mmo.SetBounds(10, top, 167, 50)
	//    mmo.Text()
	mmo.Lines().Add("1")
	mmo.Lines().Add("2")

	top += mmo.Height() + 5
	// TComboBox
	cb := vcl.NewComboBox(mainForm)
	cb.SetParent(mainForm)
	cb.SetLeft(10)
	cb.SetTop(top)
	cb.SetStyle(types.CsDropDownList)
	cb.Items().Add("1")
	cb.Items().Add("2")
	cb.Items().Add("3")
	cb.SetItemIndex(0)
	cb.SetOnChange(func(vcl.IObject) {
		if cb.ItemIndex() != -1 {
			fmt.Println(cb.Items().Strings(cb.ItemIndex()))
		}
	})

	// TListBox
	top += cb.Height() + 5
	lst := vcl.NewListBox(mainForm)
	lst.SetParent(mainForm)
	lst.SetBounds(10, top, 167, 50)
	lst.Items().Add("1")
	lst.Items().Add("2")
	lst.Items().Add("3")

	// TPanel
	top += lst.Height() + 5
	pnl := vcl.NewPanel(mainForm)
	pnl.SetParent(mainForm)
	pnl.SetCaption("fff")
	//    pnl.SetShowCaption(false)
	pnl.SetBounds(10, top, 167, 50)

	// color
	top += pnl.Height() + 5
	clr := vcl.NewColorBox(mainForm)
	clr.SetParent(mainForm)
	clr.SetLeft(10)
	clr.SetTop(top)
	clr.SetOnChange(func(vcl.IObject) {
		if clr.ItemIndex() != -1 {
			lbl.Font().SetColor(clr.Selected())
		}
	})

	// TPageControl
	top += clr.Height() + 5
	pgc := vcl.NewPageControl(mainForm)
	pgc.SetParent(mainForm)
	pgc.SetBounds(10, top, 167, 100)
	pgc.SetOnChange(func(vcl.IObject) {
		fmt.Println("当前索引:", pgc.ActivePageIndex())
	})

	sheet := vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("一")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮1")

	sheet = vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("二")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮2")

	sheet = vcl.NewTabSheet(mainForm)
	sheet.SetPageControl(pgc)
	sheet.SetCaption("三")
	btn = vcl.NewButton(mainForm)
	btn.SetParent(sheet)
	btn.SetLeft(10)
	btn.SetTop(10)
	btn.SetCaption("按钮3")

	// TImage
	top += pgc.Height() + 5
	img := vcl.NewImage(mainForm)
	img.SetBounds(10, top, 167, 97)
	img.SetParent(mainForm)
	img.Picture().LoadFromFile("1.jpg")
	//img.SetStretch(true)
	img.SetProportional(true)

	left = 210
	top = 10
	// TTrackBar
	trkbar := vcl.NewTrackBar(mainForm)
	trkbar.SetParent(mainForm)
	trkbar.SetBounds(left, top, 167, 20)
	trkbar.SetMax(100)
	trkbar.SetMin(0)
	trkbar.SetPosition(50)

	// TProgressBar
	top += trkbar.Height() + 10
	prgbar := vcl.NewProgressBar(mainForm)
	prgbar.SetParent(mainForm)
	prgbar.SetBounds(left, top, 10, 167)
	prgbar.SetMax(100)
	prgbar.SetMin(0)
	prgbar.SetPosition(1)
	prgbar.SetOrientation(types.PbVertical)

	trkbar.SetOnChange(func(vcl.IObject) {
		prgbar.SetPosition(trkbar.Position())
	})

	top += prgbar.Height() + 10

	dtp := vcl.NewDateTimePicker(mainForm)
	dtp.SetParent(mainForm)
	dtp.SetBounds(left, top, 167, 25)
	dtp.SetFormat("yyyy-MM-dd HH:mm:ss")

	top += dtp.Height() + 10

	mdtp := vcl.NewMonthCalendar(mainForm)
	mdtp.SetParent(mainForm)
	mdtp.SetBounds(left, top, 250, 250)
	mdtp.SetOnClick(func(vcl.IObject) {
		fmt.Println(mdtp.Date())
	})

	top += mdtp.Height() + 10
	dtp.SetDateTime(time.Now().Add(time.Hour * 48))
	dtp.SetDate(time.Now().AddDate(1, 0, 0))

	fmt.Println("time: ", mdtp.Date(), dtp.DateTime())

	btn = vcl.NewButton(mainForm)
	btn.SetParent(mainForm)
	btn.SetLeft(left)
	btn.SetTop(top)
	btn.SetCaption("改变日期")
	btn.SetOnClick(func(vcl.IObject) {
		mdtp.SetDate(time.Now().AddDate(-20, 0, 0))
	})

	top += btn.Height() + 10
	spinedit := vcl.NewSpinEdit(mainForm)
	spinedit.SetParent(mainForm)
	spinedit.SetLeft(left)
	spinedit.SetTop(top)
	spinedit.SetWidth(100)
	spinedit.SetMaxValue(10000)
	spinedit.SetMinValue(50)
	spinedit.SetValue(100)
	spinedit.SetOnChange(func(sender vcl.IObject) {
		fmt.Println(spinedit.Value())
	})

	// run
	vcl.Application.Run()
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/BurntSushi/toml"
	"github.com/osrg/gobgp/packet"
	"strings"
)

const (
	DEFAULT_HOLDTIME                  = 90
	DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30
	DEFAULT_CONNECT_RETRY             = 120
)

type neighbor struct {
	attributes map[string]bool
}

func SetDefaultConfigValues(md toml.MetaData, bt *Bgp) error {
	neighbors := []neighbor{}
	global := make(map[string]bool)

	for _, key := range md.Keys() {
		if !strings.HasPrefix(key.String(), "Global") {
			continue
		}
		if key.String() != "Global" {
			global[key.String()] = true
		}
	}

	if _, ok := global["Global.AfiSafis.AfiSafiList"]; !ok {
		bt.Global.AfiSafis.AfiSafiList = []AfiSafi{
			AfiSafi{AfiSafiName: "ipv4-unicast"},
			AfiSafi{AfiSafiName: "ipv6-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"},
			AfiSafi{AfiSafiName: "l2vpn-evpn"},
			AfiSafi{AfiSafiName: "encap"},
			AfiSafi{AfiSafiName: "rtc"},
			AfiSafi{AfiSafiName: "ipv4-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipnv4-flowspec"},
		}
	}

	nidx := 0
	for _, key := range md.Keys() {
		if !strings.HasPrefix(key.String(), "Neighbors.NeighborList") {
			continue
		}
		if key.String() == "Neighbors.NeighborList" {
			neighbors = append(neighbors, neighbor{attributes: make(map[string]bool)})
			nidx++
		} else {
			neighbors[nidx-1].attributes[key.String()] = true
		}
	}
	for i, n := range neighbors {
		neighbor := &bt.Neighbors.NeighborList[i]
		timerConfig := &neighbor.Timers.TimersConfig

		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.ConnectRetry"]; !ok {
			timerConfig.HoldTime = float64(DEFAULT_CONNECT_RETRY)
		}
		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.HoldTime"]; !ok {
			timerConfig.HoldTime = float64(DEFAULT_HOLDTIME)
		}
		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.KeepaliveInterval"]; !ok {
			timerConfig.KeepaliveInterval = timerConfig.HoldTime / 3
		}

		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.IdleHoldTimeAfterReset"]; !ok {
			timerConfig.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
		}

		if _, ok := n.attributes["Neighbors.NeighborList.AfiSafis.AfiSafiList"]; !ok {
			if neighbor.NeighborConfig.NeighborAddress.To4() != nil {
				neighbor.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv4-unicast"}}
			} else {
				neighbor.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv6-unicast"}}
			}
		} else {
			for _, rf := range neighbor.AfiSafis.AfiSafiList {
				_, err := bgp.GetRouteFamily(rf.AfiSafiName)
				if err != nil {
					return err
				}
			}
		}

		if _, ok := n.attributes["Neighbors.NeighborList.NeighborConfig"]; !ok {
			if neighbor.NeighborConfig.PeerAs != bt.Global.GlobalConfig.As {
				neighbor.NeighborConfig.PeerType = PEER_TYPE_EXTERNAL
			} else {
				neighbor.NeighborConfig.PeerType = PEER_TYPE_INTERNAL
			}
		}
	}
	return nil
}
<commit_msg>config: fix peer type detection<commit_after>package config

import (
	"github.com/BurntSushi/toml"
	"github.com/osrg/gobgp/packet"
	"strings"
)

const (
	DEFAULT_HOLDTIME                  = 90
	DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30
	DEFAULT_CONNECT_RETRY             = 120
)

type neighbor struct {
	attributes map[string]bool
}

func SetDefaultConfigValues(md toml.MetaData, bt *Bgp) error {
	neighbors := []neighbor{}
	global := make(map[string]bool)

	for _, key := range md.Keys() {
		if !strings.HasPrefix(key.String(), "Global") {
			continue
		}
		if key.String() != "Global" {
			global[key.String()] = true
		}
	}

	if _, ok := global["Global.AfiSafis.AfiSafiList"]; !ok {
		bt.Global.AfiSafis.AfiSafiList = []AfiSafi{
			AfiSafi{AfiSafiName: "ipv4-unicast"},
			AfiSafi{AfiSafiName: "ipv6-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"},
			AfiSafi{AfiSafiName: "l2vpn-evpn"},
			AfiSafi{AfiSafiName: "encap"},
			AfiSafi{AfiSafiName: "rtc"},
			AfiSafi{AfiSafiName: "ipv4-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipnv4-flowspec"},
		}
	}

	nidx := 0
	for _, key := range md.Keys() {
		if !strings.HasPrefix(key.String(), "Neighbors.NeighborList") {
			continue
		}
		if key.String() == "Neighbors.NeighborList" {
			neighbors = append(neighbors, neighbor{attributes: make(map[string]bool)})
			nidx++
		} else {
			neighbors[nidx-1].attributes[key.String()] = true
		}
	}
	for i, n := range neighbors {
		neighbor := &bt.Neighbors.NeighborList[i]
		timerConfig := &neighbor.Timers.TimersConfig

		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.ConnectRetry"]; !ok {
			timerConfig.HoldTime = float64(DEFAULT_CONNECT_RETRY)
		}
		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.HoldTime"]; !ok {
			timerConfig.HoldTime = float64(DEFAULT_HOLDTIME)
		}
		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.KeepaliveInterval"]; !ok {
			timerConfig.KeepaliveInterval = timerConfig.HoldTime / 3
		}

		if _, ok := n.attributes["Neighbors.NeighborList.Timers.TimersConfig.IdleHoldTimeAfterReset"]; !ok {
			timerConfig.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
		}

		if _, ok := n.attributes["Neighbors.NeighborList.AfiSafis.AfiSafiList"]; !ok {
			if neighbor.NeighborConfig.NeighborAddress.To4() != nil {
				neighbor.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv4-unicast"}}
			} else {
				neighbor.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv6-unicast"}}
			}
		} else {
			for _, rf := range neighbor.AfiSafis.AfiSafiList {
				_, err := bgp.GetRouteFamily(rf.AfiSafiName)
				if err != nil {
					return err
				}
			}
		}

		if _, ok := n.attributes["Neighbors.NeighborList.NeighborConfig.PeerType"]; !ok {
			if neighbor.NeighborConfig.PeerAs != bt.Global.GlobalConfig.As {
				neighbor.NeighborConfig.PeerType = PEER_TYPE_EXTERNAL
			} else {
				neighbor.NeighborConfig.PeerType = PEER_TYPE_INTERNAL
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"github.com/osrg/gobgp/packet"
	"github.com/spf13/viper"
	"net"
	"strings"
)

const (
	DEFAULT_HOLDTIME                  = 90
	DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30
	DEFAULT_CONNECT_RETRY             = 120
	DEFAULT_MPLS_LABEL_MIN            = 16000
	DEFAULT_MPLS_LABEL_MAX            = 1048575
)

func SetDefaultConfigValues(v *viper.Viper, b *Bgp) error {
	if v == nil {
		v = viper.New()
	}
	if !v.IsSet("global.afisafis.afisafilist") {
		b.Global.AfiSafis.AfiSafiList = []AfiSafi{
			AfiSafi{AfiSafiName: "ipv4-unicast"},
			AfiSafi{AfiSafiName: "ipv6-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"},
			AfiSafi{AfiSafiName: "l2vpn-evpn"},
			AfiSafi{AfiSafiName: "encap"},
			AfiSafi{AfiSafiName: "rtc"},
			AfiSafi{AfiSafiName: "ipv4-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-flowspec"},
			AfiSafi{AfiSafiName: "ipv6-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-flowspec"},
		}
	}

	if b.Global.ListenConfig.Port == 0 {
		b.Global.ListenConfig.Port = bgp.BGP_PORT
	}

	if !v.IsSet("global.mplslabelrange.minlabel") {
		b.Global.MplsLabelRange.MinLabel = DEFAULT_MPLS_LABEL_MIN
	}

	if !v.IsSet("global.mplslabelrange.maxlabel") {
		b.Global.MplsLabelRange.MaxLabel = DEFAULT_MPLS_LABEL_MAX
	}
	var list []interface{}
	for k, val := range v.GetStringMap("neighbors") {
		if strings.ToLower(k) == "neighborlist" {
			var ok bool
			// yaml is decoded as []interface{}
			// but toml is decoded as []map[string]interface{}.
			// currently, viper can't hide this difference.
			// handle the difference here.
			list, ok = val.([]interface{})
			if !ok {
				l, ok := val.([]map[string]interface{})
				if !ok {
					return fmt.Errorf("invalid configuration: neighborlist must be a list")
				}
				for _, m := range l {
					list = append(list, m)
				}
			}
		}
	}
	for idx, n := range b.Neighbors.NeighborList {
		vv := viper.New()
		if len(list) > idx {
			vv.Set("neighbor", list[idx])
		}
		if !vv.IsSet("neighbor.timers.config.connectretry") {
			n.Timers.Config.ConnectRetry = float64(DEFAULT_CONNECT_RETRY)
		}
		if !vv.IsSet("neighbor.timers.config.holdtime") {
			n.Timers.Config.HoldTime = float64(DEFAULT_HOLDTIME)
		}
		if !vv.IsSet("neighbor.timers.config.keepaliveinterval") {
			n.Timers.Config.KeepaliveInterval = n.Timers.Config.HoldTime / 3
		}
		if !vv.IsSet("neighbor.timers.config.idleholdtimeafterreset") {
			n.Timers.Config.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
		}

		if !vv.IsSet("neighbor.afisafis.afisafilist") {
			if ip := net.ParseIP(n.Config.NeighborAddress); ip.To4() != nil {
				n.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv4-unicast"},
				}
			} else if ip.To16() != nil {
				n.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv6-unicast"},
				}
			} else {
				return fmt.Errorf("invalid neighbor address: %s", n.Config.NeighborAddress)
			}
		}

		if !vv.IsSet("neighbor.config.peertype") {
			if n.Config.PeerAs != b.Global.Config.As {
				n.Config.PeerType = PEER_TYPE_EXTERNAL
			} else {
				n.Config.PeerType = PEER_TYPE_INTERNAL
			}
		}
		b.Neighbors.NeighborList[idx] = n
	}

	for _, r := range b.RpkiServers.RpkiServerList {
		if r.Config.Port == 0 {
			r.Config.Port = bgp.RPKI_DEFAULT_PORT
		}
	}

	return nil
}
<commit_msg>config: set default bmp port when bmp port is not configured<commit_after>package config

import (
	"fmt"
	"github.com/osrg/gobgp/packet"
	"github.com/spf13/viper"
	"net"
	"strings"
)

const (
	DEFAULT_HOLDTIME                  = 90
	DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30
	DEFAULT_CONNECT_RETRY             = 120
	DEFAULT_MPLS_LABEL_MIN            = 16000
	DEFAULT_MPLS_LABEL_MAX            = 1048575
)

func SetDefaultConfigValues(v *viper.Viper, b *Bgp) error {
	if v == nil {
		v = viper.New()
	}
	if !v.IsSet("global.afisafis.afisafilist") {
		b.Global.AfiSafis.AfiSafiList = []AfiSafi{
			AfiSafi{AfiSafiName: "ipv4-unicast"},
			AfiSafi{AfiSafiName: "ipv6-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-unicast"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-unicast"},
			AfiSafi{AfiSafiName: "l2vpn-evpn"},
			AfiSafi{AfiSafiName: "encap"},
			AfiSafi{AfiSafiName: "rtc"},
			AfiSafi{AfiSafiName: "ipv4-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipv4-flowspec"},
			AfiSafi{AfiSafiName: "ipv6-flowspec"},
			AfiSafi{AfiSafiName: "l3vpn-ipv6-flowspec"},
		}
	}

	if b.Global.ListenConfig.Port == 0 {
		b.Global.ListenConfig.Port = bgp.BGP_PORT
	}

	for idx, server := range b.BmpServers.BmpServerList {
		if server.Config.Port == 0 {
			server.Config.Port = bgp.BMP_DEFAULT_PORT
		}
		b.BmpServers.BmpServerList[idx] = server
	}

	if !v.IsSet("global.mplslabelrange.minlabel") {
		b.Global.MplsLabelRange.MinLabel = DEFAULT_MPLS_LABEL_MIN
	}

	if !v.IsSet("global.mplslabelrange.maxlabel") {
		b.Global.MplsLabelRange.MaxLabel = DEFAULT_MPLS_LABEL_MAX
	}
	var list []interface{}
	for k, val := range v.GetStringMap("neighbors") {
		if strings.ToLower(k) == "neighborlist" {
			var ok bool
			// yaml is decoded as []interface{}
			// but toml is decoded as []map[string]interface{}.
			// currently, viper can't hide this difference.
			// handle the difference here.
			list, ok = val.([]interface{})
			if !ok {
				l, ok := val.([]map[string]interface{})
				if !ok {
					return fmt.Errorf("invalid configuration: neighborlist must be a list")
				}
				for _, m := range l {
					list = append(list, m)
				}
			}
		}
	}
	for idx, n := range b.Neighbors.NeighborList {
		vv := viper.New()
		if len(list) > idx {
			vv.Set("neighbor", list[idx])
		}
		if !vv.IsSet("neighbor.timers.config.connectretry") {
			n.Timers.Config.ConnectRetry = float64(DEFAULT_CONNECT_RETRY)
		}
		if !vv.IsSet("neighbor.timers.config.holdtime") {
			n.Timers.Config.HoldTime = float64(DEFAULT_HOLDTIME)
		}
		if !vv.IsSet("neighbor.timers.config.keepaliveinterval") {
			n.Timers.Config.KeepaliveInterval = n.Timers.Config.HoldTime / 3
		}
		if !vv.IsSet("neighbor.timers.config.idleholdtimeafterreset") {
			n.Timers.Config.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET)
		}

		if !vv.IsSet("neighbor.afisafis.afisafilist") {
			if ip := net.ParseIP(n.Config.NeighborAddress); ip.To4() != nil {
				n.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv4-unicast"},
				}
			} else if ip.To16() != nil {
				n.AfiSafis.AfiSafiList = []AfiSafi{
					AfiSafi{AfiSafiName: "ipv6-unicast"},
				}
			} else {
				return fmt.Errorf("invalid neighbor address: %s", n.Config.NeighborAddress)
			}
		}

		if !vv.IsSet("neighbor.config.peertype") {
			if n.Config.PeerAs != b.Global.Config.As {
				n.Config.PeerType = PEER_TYPE_EXTERNAL
			} else {
				n.Config.PeerType = PEER_TYPE_INTERNAL
			}
		}
		b.Neighbors.NeighborList[idx] = n
	}

	for _, r := range b.RpkiServers.RpkiServerList {
		if r.Config.Port == 0 {
			r.Config.Port = bgp.RPKI_DEFAULT_PORT
		}
	}

	return nil
}
<|endoftext|>