<commit_before>package loader

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/fatih/images/command/flags"
	"github.com/fatih/structs"
	"github.com/koding/multiconfig"
)

var (
	DefaultConfigName = "imagesrc"
)

// Load loads the given config to the rules of images CLI
func Load(conf interface{}, args []string) error {
	// only pass the config's field names arguments
	configArgs := []string{}

	addField := func(field *structs.Field) {
		fieldName := field.Name()
		fName := strings.ToLower(fieldName)

		fmt.Printf("fName = %+v\n", fName)
		val, err := flags.ParseValue(fName, args)
		if err != nil {
			return
		}

		configArgs = append(configArgs, "--"+fName, val)
	}

	for _, field := range structs.Fields(conf) {
		if field.Kind() == reflect.Struct {
			for _, f := range field.Fields() {
				addField(f)
			}
		}

		addField(field)
	}

	fmt.Printf("configArgs = %+v\n", configArgs)

	loaders := []multiconfig.Loader{}

	// check for any files
	path, ext, err := discoverConfigPath(DefaultConfigName)
	if err == nil {
		// Choose what while is passed
		switch ext {
		case "json":
			// .imagesrc.json
			loaders = append(loaders, &multiconfig.JSONLoader{Path: path})
		case "toml":
			fallthrough
		default:
			// .imagesrc or .imagesrc.toml
			loaders = append(loaders, &multiconfig.TOMLLoader{Path: path})
		}
	}

	e := &multiconfig.EnvironmentLoader{
		Prefix: "IMAGES",
	}
	f := &multiconfig.FlagLoader{
		Args:      configArgs,
		Flatten:   true,
		EnvPrefix: "IMAGES",
	}
	loaders = append(loaders, e, f)

	l := multiconfig.MultiLoader(loaders...)
	return l.Load(conf)
}

func discoverConfigPath(configName string) (string, string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	configPath := filepath.Join(cwd, "."+configName)

	if _, err := os.Stat(configPath); err == nil {
		return configPath, "", nil
	}

	// check for .toml
	tomlPath := filepath.Join(cwd, "."+configName+".toml")
	if _, err := os.Stat(tomlPath); err == nil {
		return tomlPath, "toml", nil
	}

	// check for .json
	jsonPath := filepath.Join(cwd, "."+configName+".json")
	if _, err := os.Stat(jsonPath); err == nil {
		return jsonPath, "json", nil
	}

	return "", "", errors.New("couldn't find any .imagesrc file")
}
<commit_msg>loader: we should get all nested structs, this is better<commit_after>package loader

import (
	"errors"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/fatih/images/command/flags"
	"github.com/fatih/structs"
	"github.com/koding/multiconfig"
)

var (
	DefaultConfigName = "imagesrc"
)

// Load loads the given config to the rules of images CLI
func Load(conf interface{}, args []string) error {
	// only pass the config's field names arguments
	configArgs := []string{}

	// need to be declared so we can call it recursively :)
	var addFields func(fields []*structs.Field)

	addFields = func(fields []*structs.Field) {
		for _, field := range fields {
			// don't forget nested structs
			if field.Kind() == reflect.Struct {
				addFields(field.Fields())
			}

			fieldName := field.Name()
			fName := strings.ToLower(fieldName)

			val, err := flags.ParseValue(fName, args)
			if err != nil {
				return
			}

			configArgs = append(configArgs, "--"+fName, val)
		}
	}

	addFields(structs.Fields(conf))

	loaders := []multiconfig.Loader{}

	// check for any files
	path, ext, err := discoverConfigPath(DefaultConfigName)
	if err == nil {
		// Choose what while is passed
		switch ext {
		case "json":
			// .imagesrc.json
			loaders = append(loaders, &multiconfig.JSONLoader{Path: path})
		case "toml":
			fallthrough
		default:
			// .imagesrc or .imagesrc.toml
			loaders = append(loaders, &multiconfig.TOMLLoader{Path: path})
		}
	}

	e := &multiconfig.EnvironmentLoader{
		Prefix: "IMAGES",
	}
	f := &multiconfig.FlagLoader{
		Args:      configArgs,
		Flatten:   true,
		EnvPrefix: "IMAGES",
	}
	loaders = append(loaders, e, f)

	l := multiconfig.MultiLoader(loaders...)
	return l.Load(conf)
}

func discoverConfigPath(configName string) (string, string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	configPath := filepath.Join(cwd, "."+configName)

	if _, err := os.Stat(configPath); err == nil {
		return configPath, "", nil
	}

	// check for .toml
	tomlPath := filepath.Join(cwd, "."+configName+".toml")
	if _, err := os.Stat(tomlPath); err == nil {
		return tomlPath, "toml", nil
	}

	// check for .json
	jsonPath := filepath.Join(cwd, "."+configName+".json")
	if _, err := os.Stat(jsonPath); err == nil {
		return jsonPath, "json", nil
	}

	return "", "", errors.New("couldn't find any .imagesrc file")
}
<|endoftext|>


<commit_before>package deprecate

import (
	"bytes"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
)

func TestNotice(t *testing.T) {
	var out bytes.Buffer
	cli.Default.Writer = &out
	log.SetHandler(cli.Default)
	log.Info("first")
	Notice("foo.bar.whatever")
	log.Info("last")

	assert.Contains(t, out.String(), "   • first")
	assert.Contains(t, out.String(), "      • DEPRECATED: `foo.bar.whatever` should not be used anymore, check https://goreleaser.com/deprecations#foo-bar-whatever for more info.")
	assert.Contains(t, out.String(), "   • last")
}
<commit_msg>test: disable colors on tests<commit_after>package deprecate

import (
	"bytes"
	"testing"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"github.com/fatih/color"
	"github.com/stretchr/testify/assert"
)

func TestNotice(t *testing.T) {
	var out bytes.Buffer
	cli.Default.Writer = &out
	log.SetHandler(cli.Default)
	log.Info("first")
	Notice("foo.bar.whatever")
	log.Info("last")
	color.NoColor = true

	assert.Contains(t, out.String(), "   • first")
	assert.Contains(t, out.String(), "      • DEPRECATED: `foo.bar.whatever` should not be used anymore, check https://goreleaser.com/deprecations#foo-bar-whatever for more info.")
	assert.Contains(t, out.String(), "   • last")
}
<|endoftext|>


<commit_before>package monitor

import (
	"fmt"
	"time"
	"encoding/json"
)

const (
	NameSpaceQceDocker = "qce/docker"
	NameSpaceQceCvm    = "qce/cvm"

	QCloudMonitorAPITimeTemplate = "2006-01-02 15:04:05"
)

type QCloudMonitorAPITime struct {
	time.Time
}

func (qmat QCloudMonitorAPITime) MarshalJSON() ([]byte, error) {

	return []byte(
		fmt.Sprintf(
			"%d-%d-%d %d:%d:%d",
			qmat.Year(),
			qmat.Month(),
			qmat.Day(),
			qmat.Hour(),
			qmat.Minute(),
			qmat.Second()),
	), nil
}

func (qmat QCloudMonitorAPITime) UnmarshalJSON(b []byte) error {
	var tmp string
	if err := json.Unmarshal(b, &tmp); err != nil {
		return nil
	}

	t, err := time.Parse(QCloudMonitorAPITimeTemplate, tmp)
	if err != nil {
		return err
	}
	qmat = QCloudMonitorAPITime{t}

	return nil
}

type Response struct {
	Code     int    `json:"code"`
	Message  string `json:"message"`
	CodeDesc string `json:"codeDesc"`
}

type GetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Dimensions []Dimension           `qcloud_arg:"dimensions"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Dimension struct {
	Name  string `qcloud_arg:"name"`
	Value string `qcloud_arg:"value"`
}

type GetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints []float64            `json:"dataPoints"`
}

type BatchGetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Batch      []Batch               `qcloud_arg:"batch"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Batch struct {
	Dimensions []Dimension `qcloud_arg:"dimensions"`
}

type BatchGetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints map[string][]float64 `json:"dataPoints"`
}

func (client *Client) GetMonitorData(args *GetMonitorDataArgs) (*GetMonitorDataResponse, error) {
	response := &GetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &GetMonitorDataResponse{}, err
	}
	return response, nil
}

func (client *Client) BatchGetMonitorData(args *BatchGetMonitorDataArgs) (*BatchGetMonitorDataResponse, error) {
	response := &BatchGetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &BatchGetMonitorDataResponse{}, err
	}
	return response, nil
}
<commit_msg>fix unmarshal bug<commit_after>package monitor

import (
	"fmt"
	"time"
	"encoding/json"
)

const (
	NameSpaceQceDocker = "qce/docker"
	NameSpaceQceCvm    = "qce/cvm"

	QCloudMonitorAPITimeTemplate = "2006-01-02 15:04:05"
)

type QCloudMonitorAPITime struct {
	time.Time
}

func (qmat *QCloudMonitorAPITime) MarshalJSON() ([]byte, error) {

	return []byte(
		fmt.Sprintf(
			"%d-%d-%d %d:%d:%d",
			qmat.Year(),
			qmat.Month(),
			qmat.Day(),
			qmat.Hour(),
			qmat.Minute(),
			qmat.Second()),
	), nil
}

func (qmat *QCloudMonitorAPITime) UnmarshalJSON(b []byte) error {
	var tmp string
	if err := json.Unmarshal(b, &tmp); err != nil {
		return nil
	}

	t, err := time.Parse(QCloudMonitorAPITimeTemplate, tmp)
	if err != nil {
		return err
	}
	qmat.Time = t

	return nil
}

type Response struct {
	Code     int    `json:"code"`
	Message  string `json:"message"`
	CodeDesc string `json:"codeDesc"`
}

type GetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Dimensions []Dimension           `qcloud_arg:"dimensions"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Dimension struct {
	Name  string `qcloud_arg:"name"`
	Value string `qcloud_arg:"value"`
}

type GetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints []float64            `json:"dataPoints"`
}

type BatchGetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Batch      []Batch               `qcloud_arg:"batch"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Batch struct {
	Dimensions []Dimension `qcloud_arg:"dimensions"`
}

type BatchGetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints map[string][]float64 `json:"dataPoints"`
}

func (client *Client) GetMonitorData(args *GetMonitorDataArgs) (*GetMonitorDataResponse, error) {
	response := &GetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &GetMonitorDataResponse{}, err
	}
	return response, nil
}

func (client *Client) BatchGetMonitorData(args *BatchGetMonitorDataArgs) (*BatchGetMonitorDataResponse, error) {
	response := &BatchGetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &BatchGetMonitorDataResponse{}, err
	}
	return response, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"sync"
	"time"

	"github.com/MJKWoolnough/minewebgen/internal/data"
)

type runner struct {
	s        *data.Server
	shutdown chan struct{}
	io.Writer
}

type Controller struct {
	c *Config

	mu      sync.RWMutex
	running map[int]*runner

	w sync.WaitGroup
}

func NewController(c *Config) *Controller {
	return &Controller{
		c:       c,
		running: make(map[int]*runner),
	}
}

func (c Controller) StartServer(id int, _ *struct{}) error {
	s := c.c.Server(id)
	if s == nil {
		return ErrUnknownServer
	}
	s.Lock()
	defer s.Unlock()
	if s.State != data.StateStopped {
		return ErrServerRunning
	}
	m := c.c.Map(s.Map)
	if m == nil {
		return ErrUnknownServer
	}
	m.RLock()
	defer m.RUnlock()
	mapPath := m.Path
	if !path.IsAbs(mapPath) {
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}
		mapPath = path.Join(pwd, mapPath)
	}
	serverMapPath := path.Join(s.Path, "world")
	if err := os.Remove(serverMapPath); err != nil && !os.IsNotExist(err) {
		return err
	}
	if err := os.Symlink(mapPath, serverMapPath); err != nil {
		return err
	}
	sp := make(ServerProperties)
	f, err := os.Open(path.Join(s.Path, "properties.server"))
	if err != nil {
		return err
	}
	sp.ReadFrom(f)
	f.Close()
	if err != nil {
		return err
	}
	f, err = os.Open(path.Join(m.Path, "properties.map"))
	if err != nil {
		return err
	}
	err = sp.ReadFrom(f)
	f.Close()
	if err != nil {
		return err
	}
	sp["level-name"] = "world"
	f, err = os.Create(path.Join(s.Path, "server.properties"))
	if err != nil {
		return err
	}
	sp.WriteTo(f)
	f.Close()
	s.State = data.StateStarting
	r := &runner{
		s:        s,
		shutdown: make(chan struct{}, 1),
	}
	go c.run(r)
	return nil
}

func (c *Controller) StopServer(id int, _ *struct{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	r, ok := c.running[id]
	if !ok {
		return errors.New("server not running")
	}
	close(r.shutdown)
	delete(c.running, id)
	return nil
}

func (c *Controller) StopAll(_ struct{}, _ *struct{}) {
	for id, r := range c.running {
		close(r.shutdown)
		delete(c.running, id)
	}
	c.w.Wait()
}

var stopCmd = []byte{'s', 't', 'o', 'p', '\r', '\n'}

// runs in its own goroutine
func (c *Controller) run(r *runner) {
	c.w.Add(1)
	defer c.w.Done()
	cmd := exec.Command("java", append(r.s.Args, "-jar", "server.jar", "nogui")...)
	cmd.Dir = r.s.Path
	r.Writer, _ = cmd.StdinPipe()
	err := cmd.Start()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		c.mu.Lock()
		c.running[r.s.ID] = r
		c.mu.Unlock()
		r.s.Lock()
		r.s.State = data.StateRunning
		r.s.Unlock()
		died := make(chan struct{})
		go func() {
			select {
			case <-r.shutdown:
				r.s.Lock()
				r.s.State = data.StateStopping
				r.s.Unlock()
				t := time.NewTimer(time.Second * 10)
				defer t.Stop()
				for i := 0; i < 6; i++ {
					r.Write(stopCmd)
					select {
					case <-died:
						return
					case <-t.C:
					}
				}
				cmd.Process.Kill()
			case <-died:
				c.mu.Lock()
				delete(c.running, r.s.ID)
				c.mu.Unlock()
			}
		}()
		cmd.Wait()
		r.shutdown = nil
		close(died)
	}
	r.s.Lock()
	r.s.State = data.StateStopped
	r.s.Unlock()
}

func (c *Controller) WriteCmd(d data.WriteCmd, _ *struct{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	r, ok := c.running[d.ID]
	if !ok {
		return ErrUnknownServer
	}
	toWrite := make([]byte, 0, len(d.Cmd)+2)
	toWrite = append(toWrite, d.Cmd...)
	toWrite = append(toWrite, '\r', '\n')
	_, err := r.Write(toWrite)
	return err
}
<commit_msg>Removed pointless map deletion<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"sync"
	"time"

	"github.com/MJKWoolnough/minewebgen/internal/data"
)

type runner struct {
	s        *data.Server
	shutdown chan struct{}
	io.Writer
}

type Controller struct {
	c *Config

	mu      sync.RWMutex
	running map[int]*runner

	w sync.WaitGroup
}

func NewController(c *Config) *Controller {
	return &Controller{
		c:       c,
		running: make(map[int]*runner),
	}
}

func (c Controller) StartServer(id int, _ *struct{}) error {
	s := c.c.Server(id)
	if s == nil {
		return ErrUnknownServer
	}
	s.Lock()
	defer s.Unlock()
	if s.State != data.StateStopped {
		return ErrServerRunning
	}
	m := c.c.Map(s.Map)
	if m == nil {
		return ErrUnknownServer
	}
	m.RLock()
	defer m.RUnlock()
	mapPath := m.Path
	if !path.IsAbs(mapPath) {
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}
		mapPath = path.Join(pwd, mapPath)
	}
	serverMapPath := path.Join(s.Path, "world")
	if err := os.Remove(serverMapPath); err != nil && !os.IsNotExist(err) {
		return err
	}
	if err := os.Symlink(mapPath, serverMapPath); err != nil {
		return err
	}
	sp := make(ServerProperties)
	f, err := os.Open(path.Join(s.Path, "properties.server"))
	if err != nil {
		return err
	}
	sp.ReadFrom(f)
	f.Close()
	if err != nil {
		return err
	}
	f, err = os.Open(path.Join(m.Path, "properties.map"))
	if err != nil {
		return err
	}
	err = sp.ReadFrom(f)
	f.Close()
	if err != nil {
		return err
	}
	sp["level-name"] = "world"
	f, err = os.Create(path.Join(s.Path, "server.properties"))
	if err != nil {
		return err
	}
	sp.WriteTo(f)
	f.Close()
	s.State = data.StateStarting
	r := &runner{
		s:        s,
		shutdown: make(chan struct{}, 1),
	}
	go c.run(r)
	return nil
}

func (c *Controller) StopServer(id int, _ *struct{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	r, ok := c.running[id]
	if !ok {
		return errors.New("server not running")
	}
	close(r.shutdown)
	delete(c.running, id)
	return nil
}

func (c *Controller) StopAll(_ struct{}, _ *struct{}) {
	for id, r := range c.running {
		close(r.shutdown)
	}
	c.w.Wait()
}

var stopCmd = []byte{'s', 't', 'o', 'p', '\r', '\n'}

// runs in its own goroutine
func (c *Controller) run(r *runner) {
	c.w.Add(1)
	defer c.w.Done()
	cmd := exec.Command("java", append(r.s.Args, "-jar", "server.jar", "nogui")...)
	cmd.Dir = r.s.Path
	r.Writer, _ = cmd.StdinPipe()
	err := cmd.Start()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		c.mu.Lock()
		c.running[r.s.ID] = r
		c.mu.Unlock()
		r.s.Lock()
		r.s.State = data.StateRunning
		r.s.Unlock()
		died := make(chan struct{})
		go func() {
			select {
			case <-r.shutdown:
				r.s.Lock()
				r.s.State = data.StateStopping
				r.s.Unlock()
				t := time.NewTimer(time.Second * 10)
				defer t.Stop()
				for i := 0; i < 6; i++ {
					r.Write(stopCmd)
					select {
					case <-died:
						return
					case <-t.C:
					}
				}
				cmd.Process.Kill()
			case <-died:
				c.mu.Lock()
				delete(c.running, r.s.ID)
				c.mu.Unlock()
			}
		}()
		cmd.Wait()
		r.shutdown = nil
		close(died)
	}
	r.s.Lock()
	r.s.State = data.StateStopped
	r.s.Unlock()
}

func (c *Controller) WriteCmd(d data.WriteCmd, _ *struct{}) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	r, ok := c.running[d.ID]
	if !ok {
		return ErrUnknownServer
	}
	toWrite := make([]byte, 0, len(d.Cmd)+2)
	toWrite = append(toWrite, d.Cmd...)
	toWrite = append(toWrite, '\r', '\n')
	_, err := r.Write(toWrite)
	return err
}
<|endoftext|>


<commit_before>// Copyright 2015 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import "github.com/spf13/cobra"

func init() {
	// This message to show to Windows users if Hugo is opened from explorer.exe
	cobra.MousetrapHelpText = `

  Hugo is a command-line tool for generating static website.

  You need to open cmd.exe and run Hugo from there.

  Visit https://gohugo.io/ for more information.`
}
<commit_msg>Import time/tzdata on Windows<commit_after>// Copyright 2015 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	// For time zone lookups on Windows without Go installed.
	// See #8892
	_ "time/tzdata"

	"github.com/spf13/cobra"
)

func init() {
	// This message to show to Windows users if Hugo is opened from explorer.exe
	cobra.MousetrapHelpText = `

  Hugo is a command-line tool for generating static website.

  You need to open cmd.exe and run Hugo from there.

  Visit https://gohugo.io/ for more information.`
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/wait"
)

const (
	tprName = "etcd-cluster.coreos.com"
)

type Event struct {
	Type   string
	Object EtcdCluster
}

type etcdClusterController struct {
	kclient  *unversioned.Client
	clusters map[string]*Cluster
}

func (c *etcdClusterController) Run() {
	watchVersion := "0"
	if err := c.createTPR(); err != nil {
		switch {
		case isKubernetesResourceAlreadyExistError(err):
			watchVersion, err = c.findAllClusters()
			if err != nil {
				panic(err)
			}
		default:
			panic(err)
		}
	}
	log.Println("etcd cluster controller starts running...")

	eventCh, errCh := monitorEtcdCluster(c.kclient.RESTClient.Client, watchVersion)
	for {
		select {
		case event := <-eventCh:
			clusterName := event.Object.ObjectMeta.Name
			switch event.Type {
			case "ADDED":
				nc := newCluster(c.kclient, clusterName, &event.Object.Spec)
				nc.init(&event.Object.Spec)
				c.clusters[clusterName] = nc
			case "MODIFIED":
				c.clusters[clusterName].update(&event.Object.Spec)
			case "DELETED":
				c.clusters[clusterName].Delete()
				delete(c.clusters, clusterName)
			}
		case err := <-errCh:
			panic(err)
		}
	}
}

func (c *etcdClusterController) findAllClusters() (string, error) {
	log.Println("finding existing clusters...")
	resp, err := listETCDCluster(c.kclient.RESTClient.Client)
	if err != nil {
		return "", err
	}
	d := json.NewDecoder(resp.Body)
	list := &EtcdClusterList{}
	if err := d.Decode(list); err != nil {
		return "", err
	}
	for _, item := range list.Items {
		nc := newCluster(c.kclient, item.Name, &item.Spec)
		c.clusters[item.Name] = nc
	}
	return list.ListMeta.ResourceVersion, nil
}

func (c *etcdClusterController) createTPR() error {
	tpr := &extensions.ThirdPartyResource{
		ObjectMeta: api.ObjectMeta{
			Name: tprName,
		},
		Versions: []extensions.APIVersion{
			{Name: "v1"},
		},
		Description: "Managed etcd clusters",
	}
	_, err := c.kclient.ThirdPartyResources().Create(tpr)
	if err != nil {
		return err
	}

	err = wait.Poll(5*time.Second, 100*time.Second,
		func() (done bool, err error) {
			resp, err := watchETCDCluster(c.kclient.RESTClient.Client, "0")
			if err != nil {
				return false, err
			}
			if resp.StatusCode == 200 {
				return true, nil
			}
			if resp.StatusCode == 404 {
				return false, nil
			}
			return false, errors.New("Invalid status code: " + resp.Status)
		})
	return err
}

func monitorEtcdCluster(httpClient *http.Client, watchVersion string) (<-chan *Event, <-chan error) {
	events := make(chan *Event)
	errc := make(chan error, 1)
	go func() {
		resp, err := watchETCDCluster(httpClient, watchVersion)
		if err != nil {
			errc <- err
			return
		}
		if resp.StatusCode != 200 {
			errc <- errors.New("Invalid status code: " + resp.Status)
			return
		}
		log.Println("start watching...")
		for {
			decoder := json.NewDecoder(resp.Body)
			ev := new(Event)
			err = decoder.Decode(ev)
			if err != nil {
				errc <- err
			}
			log.Printf("etcd cluster event: %v %#v\n", ev.Type, ev.Object)
			events <- ev
		}
	}()

	return events, errc
}
<commit_msg>handle eof on http stream<commit_after>package main

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/util/wait"
)

const (
	tprName = "etcd-cluster.coreos.com"
)

type Event struct {
	Type   string
	Object EtcdCluster
}

type etcdClusterController struct {
	kclient  *unversioned.Client
	clusters map[string]*Cluster
}

func (c *etcdClusterController) Run() {
	watchVersion := "0"
	if err := c.createTPR(); err != nil {
		switch {
		case isKubernetesResourceAlreadyExistError(err):
			watchVersion, err = c.findAllClusters()
			if err != nil {
				panic(err)
			}
		default:
			panic(err)
		}
	}
	log.Println("etcd cluster controller starts running...")

	eventCh, errCh := monitorEtcdCluster(c.kclient.RESTClient.Client, watchVersion)
	for {
		select {
		case event := <-eventCh:
			clusterName := event.Object.ObjectMeta.Name
			switch event.Type {
			case "ADDED":
				nc := newCluster(c.kclient, clusterName, &event.Object.Spec)
				nc.init(&event.Object.Spec)
				c.clusters[clusterName] = nc
			case "MODIFIED":
				c.clusters[clusterName].update(&event.Object.Spec)
			case "DELETED":
				c.clusters[clusterName].Delete()
				delete(c.clusters, clusterName)
			}
		case err := <-errCh:
			panic(err)
		}
	}
}

func (c *etcdClusterController) findAllClusters() (string, error) {
	log.Println("finding existing clusters...")
	resp, err := listETCDCluster(c.kclient.RESTClient.Client)
	if err != nil {
		return "", err
	}
	d := json.NewDecoder(resp.Body)
	list := &EtcdClusterList{}
	if err := d.Decode(list); err != nil {
		return "", err
	}
	for _, item := range list.Items {
		nc := newCluster(c.kclient, item.Name, &item.Spec)
		c.clusters[item.Name] = nc
	}
	return list.ListMeta.ResourceVersion, nil
}

func (c *etcdClusterController) createTPR() error {
	tpr := &extensions.ThirdPartyResource{
		ObjectMeta: api.ObjectMeta{
			Name: tprName,
		},
		Versions: []extensions.APIVersion{
			{Name: "v1"},
		},
		Description: "Managed etcd clusters",
	}
	_, err := c.kclient.ThirdPartyResources().Create(tpr)
	if err != nil {
		return err
	}

	err = wait.Poll(5*time.Second, 100*time.Second,
		func() (done bool, err error) {
			resp, err := watchETCDCluster(c.kclient.RESTClient.Client, "0")
			if err != nil {
				return false, err
			}
			if resp.StatusCode == 200 {
				return true, nil
			}
			if resp.StatusCode == 404 {
				return false, nil
			}
			return false, errors.New("Invalid status code: " + resp.Status)
		})
	return err
}

func monitorEtcdCluster(httpClient *http.Client, watchVersion string) (<-chan *Event, <-chan error) {
	events := make(chan *Event)
	errc := make(chan error, 1)
	go func() {
		for {
			resp, err := watchETCDCluster(httpClient, watchVersion)
			if err != nil {
				errc <- err
				return
			}
			if resp.StatusCode != 200 {
				errc <- errors.New("Invalid status code: " + resp.Status)
				return
			}
			log.Println("start watching...")
			for {
				decoder := json.NewDecoder(resp.Body)
				ev := new(Event)
				err = decoder.Decode(ev)
				if err != nil {
					if err == io.EOF {
						break
					}
					errc <- err
				}
				log.Printf("etcd cluster event: %v %#v\n", ev.Type, ev.Object)
				events <- ev
			}
		}
	}()

	return events, errc
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"regexp"
	"time"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common/errors"
)

// Constants directly related to interacting with the package model in the
// cassandra database.
const (
	// TableNamePackages is the name of the table containing the package model.
	TableNamePackages = "gophr.packages"
	// IndexNamePackages is the name of the lucene index
	IndexNamePackages             = "packages_index"
	ColumnNamePackagesRepo        = "repo"
	ColumnNamePackagesStars       = "stars"
	ColumnNamePackagesExists      = "exists"
	ColumnNamePackagesAuthor      = "author"
	ColumnNamePackagesVersions    = "versions"
	ColumnNamePackagesGodocURL    = "godoc_url"
	ColumnNamePackagesIndexTime   = "index_time"
	ColumnNamePackagesAwesomeGo   = "awesome_go"
	ColumnNamePackagesSearchBlob  = "search_blob"
	ColumnNamePackagesDescription = "description"
)

const (
	packagesSearchBlobTemplate = "%s %s %s"
)

var (
	cqlQueryFuzzySearchPackagesTemplate = fmt.Sprintf(
		`SELECT %s,%s,%s FROM %s WHERE expr(%s,'{query:{type:"fuzzy",field:"%s",value:"%s"}}') LIMIT 10`,
		ColumnNamePackagesRepo,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesDescription,
		TableNamePackages,
		IndexNamePackages,
		ColumnNamePackagesSearchBlob,
		"%s",
	)

	cqlQuerySelectPackageVersions = fmt.Sprintf(
		`SELECT %s FROM %s WHERE %s = ? AND %s = ? LIMIT 1`,
		ColumnNamePackagesVersions,
		TableNamePackages,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesRepo,
	)

	cqlQueryInsertPackage = fmt.Sprintf(
		`INSERT INTO %s (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) VALUES (?,?,?,?,?,?,?,?,?,?)`,
		TableNamePackages,
		ColumnNamePackagesRepo,
		ColumnNamePackagesStars,
		ColumnNamePackagesExists,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesVersions,
		ColumnNamePackagesGodocURL,
		ColumnNamePackagesIndexTime,
		ColumnNamePackagesAwesomeGo,
		ColumnNamePackagesSearchBlob,
		ColumnNamePackagesDescription,
	)
)

var (
	alphanumericFilterRegex = regexp.MustCompile(`[^\sa-zA-Z0-9\-_]+`)
)

// PackageModel is a struct representing one individual package in the database.
type PackageModel struct {
	Repo        *string
	Stars       *int
	Exists      *bool
	Author      *string
	Versions    []string
	GodocURL    *string
	IndexTime   *time.Time
	AwesomeGo   *bool
	SearchBlob  *string
	Description *string
}

// NewPackageModelForInsert creates an instance of PackageModel that is
// optimized and validated for the insert operation in the database.
func NewPackageModelForInsert(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	indexTime time.Time,
	awesomeGo bool,
	description string,
	stars int,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	searchBlob := fmt.Sprintf(
		packagesSearchBlobTemplate,
		author,
		repo,
		description,
	)

	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		IndexTime:   &indexTime,
		AwesomeGo:   &awesomeGo,
		SearchBlob:  &searchBlob,
		Description: &description,
	}, nil
}

// NewPackageModelFromBulkSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// multiple packages from the database.
func NewPackageModelFromBulkSelect(
	author string,
	repo string,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}

	return &PackageModel{
		Repo:        &repo,
		Author:      &author,
		Description: &description,
	}, nil
}

func NewPackageModelTest(
	author string,
	repo string,
	awesome_go bool,
	description string,
	exists bool,
	godoc_url string,
	index_time time.Time,
	search_blob string,
	versions []string,
	stars int,
) *PackageModel {
	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godoc_url,
		IndexTime:   &index_time,
		AwesomeGo:   &awesome_go,
		SearchBlob:  &search_blob,
		Description: &description,
	}
}

// NewPackageModelFromSingleSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// a single package from the database.
func NewPackageModelFromSingleSelect(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	awesomeGo bool,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	return &PackageModel{
		Repo:        &repo,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		AwesomeGo:   &awesomeGo,
		Description: &description,
	}, nil
}

// FindPackageVersions gets the versions of a package from the database. If
// no such package exists, or there were no versions for said package, then nil
// is returned.
func FindPackageVersions(session *gocql.Session, author string, repo string) ([]string, error) {
	var (
		err      error
		versions []string
	)

	iter := session.Query(cqlQuerySelectPackageVersions, author, repo).Iter()

	if !iter.Scan(&versions) {
		return nil, nil
	}

	if err = iter.Close(); err != nil {
		return nil, errors.NewQueryScanError(nil, err)
	}

	return versions, nil
}

// FuzzySearchPackages finds a list of packages relevant to a query phrase
// string. The search takes author, package and description into account.
func FuzzySearchPackages(
	session *gocql.Session,
	searchText string,
) ([]*PackageModel, error) {
	// First, remove all non-essential characters
	searchText = alphanumericFilterRegex.ReplaceAllString(searchText, "")
	// Next put the search text into a query string
	query := fmt.Sprintf(cqlQueryFuzzySearchPackagesTemplate, searchText)
	// Return the processed results of the query
	return scanPackageModels(session.Query(query))
}

// InsertPackage inserts an individual package into the database.
func InsertPackage(
	session *gocql.Session,
	packageModel *PackageModel,
) error {
	err := session.Query(cqlQueryInsertPackage,
		*packageModel.Repo,
		*packageModel.Stars,
		*packageModel.Exists,
		*packageModel.Author,
		packageModel.Versions,
		*packageModel.GodocURL,
		*packageModel.IndexTime,
		*packageModel.AwesomeGo,
		*packageModel.SearchBlob,
		*packageModel.Description,
	).Exec()

	return err
}

// InsertPackages inserts a slice of package models into the database.
func InsertPackages(
	session *gocql.Session,
	packageModels []*PackageModel,
) error {
	batch := gocql.NewBatch(gocql.LoggedBatch)

	if packageModels == nil || len(packageModels) == 0 {
		return errors.NewInvalidParameterError("packageModels", packageModels)
	}

	for _, packageModel := range packageModels {
		if packageModel != nil &&
			packageModel.Repo != nil &&
			packageModel.Exists != nil &&
			packageModel.Author != nil &&
			packageModel.GodocURL != nil &&
			packageModel.IndexTime != nil &&
			packageModel.AwesomeGo != nil &&
			packageModel.SearchBlob != nil &&
			packageModel.Description != nil {
			batch.Query(
				cqlQueryInsertPackage,
				*packageModel.Repo,
				*packageModel.Exists,
				*packageModel.Author,
				packageModel.Versions,
				*packageModel.GodocURL,
				*packageModel.IndexTime,
				*packageModel.AwesomeGo,
				*packageModel.SearchBlob,
				*packageModel.Description,
			)
		} else {
			return errors.NewInvalidParameterError(
				"packageModels",
				fmt.Sprintf("[ ..., %v, ... ]", packageModel),
			)
		}
	}

	err := session.ExecuteBatch(batch)
	if err != nil {
		return err
	}

	return nil
}

/********************************** HELPERS ***********************************/

// TODO(skeswa): implement this for querying single packages
func scanPackageModel(query *gocql.Query) ([]*PackageModel, error) {
	return nil, nil
}

func scanPackageModels(query *gocql.Query) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		repo        string
		author      string
		description string

		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&repo, &author, &description) {
		packageModel, err = NewPackageModelFromBulkSelect(author, repo, description)
		if err != nil {
			scanError = err
			break
		} else {
			packageModels = append(packageModels, packageModel)
		}
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}

func ScanAllPackageModels(session *gocql.Session) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		author      string
		repo        string
		awesome_go  bool
		description string
		exists      bool
		godoc_url   string
		index_time  time.Time
		search_blob string
		versions    []string
		stars       int

		query = session.Query(`SELECT
			author,
			repo,
			awesome_go,
			description,
			exists,
			godoc_url,
			index_time,
			search_blob,
			versions,
			stars
			FROM gophr.packages`)
		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&author, &repo, &awesome_go, &description, &exists, &godoc_url, &index_time, &search_blob, &versions, &stars) {
		packageModel = NewPackageModelTest(author, repo, awesome_go, description, exists, godoc_url, index_time, search_blob, versions, stars)
		packageModels = append(packageModels, packageModel)
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}
<commit_msg>added delete func to common/models/package<commit_after>package models

import (
	"fmt"
	"regexp"
	"time"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common/errors"
)

// Constants directly related to interacting with the package model in the
// cassandra database.
const (
	// TableNamePackages is the name of the table containing the package model.
	TableNamePackages = "gophr.packages"
	// IndexNamePackages is the name of the lucene index
	IndexNamePackages             = "packages_index"
	ColumnNamePackagesRepo        = "repo"
	ColumnNamePackagesStars       = "stars"
	ColumnNamePackagesExists      = "exists"
	ColumnNamePackagesAuthor      = "author"
	ColumnNamePackagesVersions    = "versions"
	ColumnNamePackagesGodocURL    = "godoc_url"
	ColumnNamePackagesIndexTime   = "index_time"
	ColumnNamePackagesAwesomeGo   = "awesome_go"
	ColumnNamePackagesSearchBlob  = "search_blob"
	ColumnNamePackagesDescription = "description"
)

const (
	packagesSearchBlobTemplate = "%s %s %s"
)

var (
	cqlQueryFuzzySearchPackagesTemplate = fmt.Sprintf(
		`SELECT %s,%s,%s FROM %s WHERE expr(%s,'{query:{type:"fuzzy",field:"%s",value:"%s"}}') LIMIT 10`,
		ColumnNamePackagesRepo,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesDescription,
		TableNamePackages,
		IndexNamePackages,
		ColumnNamePackagesSearchBlob,
		"%s",
	)

	cqlQuerySelectPackageVersions = fmt.Sprintf(
		`SELECT %s FROM %s WHERE %s = ? AND %s = ? LIMIT 1`,
		ColumnNamePackagesVersions,
		TableNamePackages,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesRepo,
	)

	cqlQueryInsertPackage = fmt.Sprintf(
		`INSERT INTO %s (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) VALUES (?,?,?,?,?,?,?,?,?,?)`,
		TableNamePackages,
		ColumnNamePackagesRepo,
		ColumnNamePackagesStars,
		ColumnNamePackagesExists,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesVersions,
		ColumnNamePackagesGodocURL,
		ColumnNamePackagesIndexTime,
		ColumnNamePackagesAwesomeGo,
		ColumnNamePackagesSearchBlob,
		ColumnNamePackagesDescription,
	)

	cqlQueryDeletePackage = fmt.Sprintf(
		`DELETE FROM %s WHERE %s = ? AND %s = ?`,
		TableNamePackages,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesRepo,
	)
)

var (
	alphanumericFilterRegex = regexp.MustCompile(`[^\sa-zA-Z0-9\-_]+`)
)

// PackageModel is a struct representing one individual package in the database.
type PackageModel struct {
	Repo        *string
	Stars       *int
	Exists      *bool
	Author      *string
	Versions    []string
	GodocURL    *string
	IndexTime   *time.Time
	AwesomeGo   *bool
	SearchBlob  *string
	Description *string
}

// NewPackageModelForInsert creates an instance of PackageModel that is
// optimized and validated for the insert operation in the database.
func NewPackageModelForInsert(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	indexTime time.Time,
	awesomeGo bool,
	description string,
	stars int,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	searchBlob := fmt.Sprintf(
		packagesSearchBlobTemplate,
		author,
		repo,
		description,
	)

	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		IndexTime:   &indexTime,
		AwesomeGo:   &awesomeGo,
		SearchBlob:  &searchBlob,
		Description: &description,
	}, nil
}

// NewPackageModelFromBulkSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// multiple packages from the database.
func NewPackageModelFromBulkSelect(
	author string,
	repo string,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}

	return &PackageModel{
		Repo:        &repo,
		Author:      &author,
		Description: &description,
	}, nil
}

func NewPackageModelTest(
	author string,
	repo string,
	awesome_go bool,
	description string,
	exists bool,
	godoc_url string,
	index_time time.Time,
	search_blob string,
	versions []string,
	stars int,
) *PackageModel {
	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godoc_url,
		IndexTime:   &index_time,
		AwesomeGo:   &awesome_go,
		SearchBlob:  &search_blob,
		Description: &description,
	}
}

// NewPackageModelFromSingleSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// a single package from the database.
func NewPackageModelFromSingleSelect(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	awesomeGo bool,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	return &PackageModel{
		Repo:        &repo,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		AwesomeGo:   &awesomeGo,
		Description: &description,
	}, nil
}

// FindPackageVersions gets the versions of a package from the database. If
// no such package exists, or there were no versions for said package, then nil
// is returned.
func FindPackageVersions(session *gocql.Session, author string, repo string) ([]string, error) {
	var (
		err      error
		versions []string
	)

	iter := session.Query(cqlQuerySelectPackageVersions, author, repo).Iter()

	if !iter.Scan(&versions) {
		return nil, nil
	}

	if err = iter.Close(); err != nil {
		return nil, errors.NewQueryScanError(nil, err)
	}

	return versions, nil
}

// FuzzySearchPackages finds a list of packages relevant to a query phrase
// string. The search takes author, package and description into account.
func FuzzySearchPackages(
	session *gocql.Session,
	searchText string,
) ([]*PackageModel, error) {
	// First, remove all non-essential characters
	searchText = alphanumericFilterRegex.ReplaceAllString(searchText, "")
	// Next put the search text into a query string
	query := fmt.Sprintf(cqlQueryFuzzySearchPackagesTemplate, searchText)
	// Return the processed results of the query
	return scanPackageModels(session.Query(query))
}

// InsertPackage inserts an individual package into the database.
func InsertPackage(
	session *gocql.Session,
	packageModel *PackageModel,
) error {
	err := session.Query(cqlQueryInsertPackage,
		*packageModel.Repo,
		*packageModel.Stars,
		*packageModel.Exists,
		*packageModel.Author,
		packageModel.Versions,
		*packageModel.GodocURL,
		*packageModel.IndexTime,
		*packageModel.AwesomeGo,
		*packageModel.SearchBlob,
		*packageModel.Description,
	).Exec()

	return err
}

// InsertPackages inserts a slice of package models into the database.
func InsertPackages(
	session *gocql.Session,
	packageModels []*PackageModel,
) error {
	batch := gocql.NewBatch(gocql.LoggedBatch)

	if packageModels == nil || len(packageModels) == 0 {
		return errors.NewInvalidParameterError("packageModels", packageModels)
	}

	for _, packageModel := range packageModels {
		if packageModel != nil &&
			packageModel.Repo != nil &&
			packageModel.Exists != nil &&
			packageModel.Author != nil &&
			packageModel.GodocURL != nil &&
			packageModel.IndexTime != nil &&
			packageModel.AwesomeGo != nil &&
			packageModel.SearchBlob != nil &&
			packageModel.Description != nil {
			batch.Query(
				cqlQueryInsertPackage,
				*packageModel.Repo,
				*packageModel.Exists,
				*packageModel.Author,
				packageModel.Versions,
				*packageModel.GodocURL,
				*packageModel.IndexTime,
				*packageModel.AwesomeGo,
				*packageModel.SearchBlob,
				*packageModel.Description,
			)
		} else {
			return errors.NewInvalidParameterError(
				"packageModels",
				fmt.Sprintf("[ ..., %v, ... ]", packageModel),
			)
		}
	}

	err := session.ExecuteBatch(batch)
	if err != nil {
		return err
	}

	return nil
}

/********************************** HELPERS ***********************************/

// TODO(skeswa): implement this for querying single packages
func scanPackageModel(query *gocql.Query) ([]*PackageModel, error) {
	return nil, nil
}

func scanPackageModels(query *gocql.Query) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		repo        string
		author      string
		description string

		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&repo, &author, &description) {
		packageModel, err = NewPackageModelFromBulkSelect(author, repo, description)
		if err != nil {
			scanError = err
			break
		} else {
			packageModels = append(packageModels, packageModel)
		}
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}

func ScanAllPackageModels(session *gocql.Session) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		author      string
		repo        string
		awesome_go  bool
		description string
		exists      bool
		godoc_url   string
		index_time  time.Time
		search_blob string
		versions    []string
		stars       int

		query = session.Query(`SELECT
			author,
			repo,
			awesome_go,
			description,
			exists,
			godoc_url,
			index_time,
			search_blob,
			versions,
			stars
			FROM gophr.packages`)
		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&author, &repo, &awesome_go, &description, &exists, &godoc_url, &index_time, &search_blob, &versions, &stars) {
		packageModel = NewPackageModelTest(author, repo, awesome_go, description, exists, godoc_url, index_time, search_blob, versions, stars)
		packageModels = append(packageModels, packageModel)
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}

func DeletePackageModel(session *gocql.Session, packageModel *PackageModel) error {
	author := *packageModel.Author
	repo := *packageModel.Repo
	query := session.Query(cqlQueryDeletePackage, author, repo)
	err := query.Exec()

	return err
}
<|endoftext|>


<commit_before>// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/clientv3/concurrency"
)

func main() {
	log.SetFlags(log.Lmicroseconds)

	endpointStr := flag.String("endpoints", "localhost:2379", "endpoints of etcd cluster")
	mode := flag.String("mode", "lock-racer", "test mode (lock-racer)")
	round := flag.Int("rounds", 100, "number of rounds to run")
	flag.Parse()
	eps := strings.Split(*endpointStr, ",")

	switch *mode {
	case "lock-racer":
		runRacer(eps, *round)
	case "lease-renewer":
		runLeaseRenewer(eps)
	default:
		fmt.Fprintf(os.Stderr, "unsupported mode %v\n", *mode)
	}
}

func runLeaseRenewer(eps []string) {
	c := randClient(eps)
	ctx := context.Background()

	for {
		var (
			l   *clientv3.LeaseGrantResponse
			lk  *clientv3.LeaseKeepAliveResponse
			err error
		)
		for {
			l, err = c.Lease.Grant(ctx, 5)
			if err == nil {
				break
			}
		}
		expire := time.Now().Add(time.Duration(l.TTL-1) * time.Second)

		for {
			lk, err = c.Lease.KeepAliveOnce(ctx, l.ID)
			if grpc.Code(err) == codes.NotFound {
				if time.Since(expire) < 0 {
					log.Printf("bad renew! exceeded: %v", time.Since(expire))
					for {
						lk, err = c.Lease.KeepAliveOnce(ctx, l.ID)
						fmt.Println(lk, err)
						time.Sleep(time.Second)
					}
				}
				log.Printf("lost lease %d, expire: %v\n", l.ID, expire)
				break
			}
			if err != nil {
				continue
			}
			expire = time.Now().Add(time.Duration(lk.TTL-1) * time.Second)
			log.Printf("renewed lease %d, expire: %v\n", lk.ID, expire)
			time.Sleep(time.Duration(lk.TTL-2) * time.Second)
		}
	}
}

func runRacer(eps []string, round int) {
	nrace := 15
	prefix := "racers"
	racers := make([]*concurrency.Mutex, nrace)
	clis := make([]*clientv3.Client, nrace)
	progress := make([]int, nrace)
	finished := make(chan struct{}, 0)

	var (
		mu  sync.Mutex
		cnt int
	)
	ctx := context.Background()

	var wg sync.WaitGroup

	for i := range racers {
		clis[i] = randClient(eps)
		racers[i] = concurrency.NewMutex(clis[i], prefix)
		wg.Add(1)

		go func(i int) {
			defer wg.Done()

			for {
				if progress[i] >= round {
					return
				}

				for {
					err := racers[i].Lock(ctx)
					if err == nil {
						break
					}
				}

				mu.Lock()
				if cnt > 0 {
					log.Fatalf("bad lock")
				}
				cnt = 1
				mu.Unlock()

				time.Sleep(10 * time.Millisecond)
				progress[i]++
				finished <- struct{}{}

				mu.Lock()
				for {
					err := racers[i].Unlock()
					if err == nil {
						break
					}
				}
				cnt = 0
				mu.Unlock()
			}
		}(i)
	}

	start := time.Now()
	for i := 1; i < nrace*round+1; i++ {
		select {
		case <-finished:
			if i%100 == 0 {
				fmt.Printf("finished %d, took %v\n", i, time.Since(start))
				start = time.Now()
			}
		case <-time.After(time.Minute):
			log.Panic("no progress after 1 minute!")
		}
	}

	wg.Wait()

	for _, cli := range clis {
		cli.Close()
	}
}

func randClient(eps []string) *clientv3.Client {
	neps := make([]string, len(eps))
	copy(neps, eps)

	for i := range neps {
		j := rand.Intn(i + 1)
		neps[i], neps[j] = neps[j], neps[i]
	}

	c, err := clientv3.New(clientv3.Config{
		Endpoints:   eps,
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Fatal(err)
	}
	return c
}
<commit_msg>etcd-runner: refactor round code<commit_after>// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/clientv3/concurrency"
)

func main() {
	log.SetFlags(log.Lmicroseconds)

	endpointStr := flag.String("endpoints", "localhost:2379", "endpoints of etcd cluster")
	mode := flag.String("mode", "lock-racer", "test mode (lock-racer, lease-renewer)")
	round := flag.Int("rounds", 100, "number of rounds to run")
	flag.Parse()
	eps := strings.Split(*endpointStr, ",")

	switch *mode {
	case "lock-racer":
		runRacer(eps, *round)
	case "lease-renewer":
		runLeaseRenewer(eps)
	default:
		fmt.Fprintf(os.Stderr, "unsupported mode %v\n", *mode)
	}
}

func runLeaseRenewer(eps []string) {
	c := randClient(eps)
	ctx := context.Background()

	for {
		var (
			l   *clientv3.LeaseGrantResponse
			lk  *clientv3.LeaseKeepAliveResponse
			err error
		)
		for {
			l, err = c.Lease.Grant(ctx, 5)
			if err == nil {
				break
			}
		}
		expire := time.Now().Add(time.Duration(l.TTL-1) * time.Second)

		for {
			lk, err = c.Lease.KeepAliveOnce(ctx, l.ID)
			if grpc.Code(err) == codes.NotFound {
				if time.Since(expire) < 0 {
					log.Printf("bad renew! exceeded: %v", time.Since(expire))
					for {
						lk, err = c.Lease.KeepAliveOnce(ctx, l.ID)
						fmt.Println(lk, err)
						time.Sleep(time.Second)
					}
				}
				log.Printf("lost lease %d, expire: %v\n", l.ID, expire)
				break
			}
			if err != nil {
				continue
			}
			expire = time.Now().Add(time.Duration(lk.TTL-1) * time.Second)
			log.Printf("renewed lease %d, expire: %v\n", lk.ID, expire)
			time.Sleep(time.Duration(lk.TTL-2) * time.Second)
		}
	}
}

func runRacer(eps []string, round int) {
	rcs := make([]roundClient, 15)
	ctx := context.Background()
	cnt := 0
	for i := range rcs {
		rcs[i].c = randClient(eps)
		m := concurrency.NewMutex(rcs[i].c, "racers")
		rcs[i].acquire = func() error { return m.Lock(ctx) }
		rcs[i].validate = func() error {
			if cnt++; cnt != 1 {
				return fmt.Errorf("bad lock; count: %d", cnt)
			}
			return nil
		}
		rcs[i].release = func() error {
			if err := m.Unlock(); err != nil {
				return err
			}
			cnt = 0
			return nil
		}
	}
	doRounds(rcs, round)
}

func randClient(eps []string) *clientv3.Client {
	neps := make([]string, len(eps))
	copy(neps, eps)

	for i := range neps {
		j := rand.Intn(i + 1)
		neps[i], neps[j] = neps[j], neps[i]
	}

	c, err := clientv3.New(clientv3.Config{
		Endpoints:   eps,
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		log.Fatal(err)
	}
	return c
}

type roundClient struct {
	c        *clientv3.Client
	progress int
	acquire  func() error
	validate func() error
	release  func() error
}

func doRounds(rcs []roundClient, rounds int) {
	var mu sync.Mutex
	var wg sync.WaitGroup

	wg.Add(len(rcs))
	finished := make(chan struct{}, 0)
	for i := range rcs {
		go func(rc *roundClient) {
			defer wg.Done()
			for rc.progress < rounds {
				for rc.acquire() != nil { /* spin */
				}

				mu.Lock()
				if err := rc.validate(); err != nil {
					log.Fatal(err)
				}
				mu.Unlock()

				time.Sleep(10 * time.Millisecond)
				rc.progress++
				finished <- struct{}{}

				mu.Lock()
				for rc.release() != nil {
					mu.Unlock()
					mu.Lock()
				}
				mu.Unlock()
			}
		}(&rcs[i])
	}

	start := time.Now()
	for i := 1; i < len(rcs)*rounds+1; i++ {
		select {
		case <-finished:
			if i%100 == 0 {
				fmt.Printf("finished %d, took %v\n", i, time.Since(start))
				start = time.Now()
			}
		case <-time.After(time.Minute):
			log.Panic("no progress after 1 minute!")
		}
	}

	wg.Wait()
	for _, rc := range rcs {
		rc.c.Close()
	}
}
<|endoftext|>


<commit_before>package bots

import "errors"

// ErrNotImplemented if some feature is not implemented yet
var ErrNotImplemented = errors.New("Not implemented")

const (
	// MessageTextBotDidNotUnderstandTheCommand is an i18n constant
	MessageTextBotDidNotUnderstandTheCommand = "MessageTextBotDidNotUnderstandTheCommand"

	// MessageTextOopsSomethingWentWrong is an i18n constant
	MessageTextOopsSomethingWentWrong = "MessageTextOopsSomethingWentWrong"
)
<commit_msg>error msg fixed: Not implemented => not implemented<commit_after>package bots

import "errors"

// ErrNotImplemented if some feature is not implemented yet
var ErrNotImplemented = errors.New("not implemented")

const (
	// MessageTextBotDidNotUnderstandTheCommand is an i18n constant
	MessageTextBotDidNotUnderstandTheCommand = "MessageTextBotDidNotUnderstandTheCommand"

	// MessageTextOopsSomethingWentWrong is an i18n constant
	MessageTextOopsSomethingWentWrong = "MessageTextOopsSomethingWentWrong"
)
<|endoftext|>


<commit_before>// Copyright 2014 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package core

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"math/big"
	"sync"
)

// MaxUsed defines the maximum number of Nonces we're willing to hold in
// memory.
const MaxUsed = 65536
const nonceLen = 32

var errInvalidNonceLength = errors.New("invalid nonce length")

// NonceService generates, cancels, and tracks Nonces.
type NonceService struct {
	mu       sync.Mutex
	latest   int64
	earliest int64
	used     map[int64]bool
	gcm      cipher.AEAD
	maxUsed  int
}

// NewNonceService constructs a NonceService with defaults
func NewNonceService() (*NonceService, error) {
	key := make([]byte, 16)
	if _, err := rand.Read(key); err != nil {
		return nil, err
	}

	c, err := aes.NewCipher(key)
	if err != nil {
		panic("Failure in NewCipher: " + err.Error())
	}
	gcm, _ := cipher.NewGCM(c)
	if err != nil {
		panic("Failure in NewGCM: " + err.Error())
	}

	return &NonceService{
		earliest: 0,
		latest:   0,
		used:     make(map[int64]bool, MaxUsed),
		gcm:      gcm,
		maxUsed:  MaxUsed,
	}, nil
}

func (ns *NonceService) encrypt(counter int64) (string, error) {
	// Generate a nonce with upper 4 bytes zero
	nonce := make([]byte, 12)
	for i := 0; i < 4; i++ {
		nonce[i] = 0
	}
	if _, err := rand.Read(nonce[4:]); err != nil {
		return "", err
	}

	// Encode counter to plaintext
	pt := make([]byte, 8)
	ctr := big.NewInt(counter)
	pad := 8 - len(ctr.Bytes())
	copy(pt[pad:], ctr.Bytes())

	// Encrypt
	ret := make([]byte, nonceLen)
	ct := ns.gcm.Seal(nil, nonce, pt, nil)
	copy(ret, nonce[4:])
	copy(ret[8:], ct)
	return base64.RawURLEncoding.EncodeToString(ret), nil
}

func (ns *NonceService) decrypt(nonce string) (int64, error) {
	decoded, err := base64.RawURLEncoding.DecodeString(nonce)
	if err != nil {
		return 0, err
	}
	if len(decoded) != nonceLen {
		return 0, errInvalidNonceLength
	}

	n := make([]byte, 12)
	for i := 0; i < 4; i++ {
		n[i] = 0
	}
	copy(n[4:], decoded[:8])

	pt, err := ns.gcm.Open(nil, n, decoded[8:], nil)
	if err != nil {
		return 0, err
	}

	ctr := big.NewInt(0)
	ctr.SetBytes(pt)
	return ctr.Int64(), nil
}

// Nonce provides a new Nonce.
func (ns *NonceService) Nonce() (string, error) {
	ns.mu.Lock()
	ns.latest++
	latest := ns.latest
	ns.mu.Unlock()
	return ns.encrypt(latest)
}

// minUsed returns the lowest key in the used map. Requires that a lock be held
// by caller.
func (ns *NonceService) minUsed() int64 {
	min := ns.latest
	for t := range ns.used {
		if t < min {
			min = t
		}
	}
	return min
}

// Valid determines whether the provided Nonce string is valid, returning
// true if so.
func (ns *NonceService) Valid(nonce string) bool {
	c, err := ns.decrypt(nonce)
	if err != nil {
		return false
	}

	ns.mu.Lock()
	defer ns.mu.Unlock()
	if c > ns.latest {
		return false
	}

	if c <= ns.earliest {
		return false
	}

	if ns.used[c] {
		return false
	}

	ns.used[c] = true
	if len(ns.used) > ns.maxUsed {
		ns.earliest = ns.minUsed()
		delete(ns.used, ns.earliest)
	}

	return true
}
<commit_msg>Fixed usage of wrong err object<commit_after>// Copyright 2014 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package core

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"math/big"
	"sync"
)

// MaxUsed defines the maximum number of Nonces we're willing to hold in
// memory.
const MaxUsed = 65536
const nonceLen = 32

var errInvalidNonceLength = errors.New("invalid nonce length")

// NonceService generates, cancels, and tracks Nonces.
type NonceService struct {
	mu       sync.Mutex
	latest   int64
	earliest int64
	used     map[int64]bool
	gcm      cipher.AEAD
	maxUsed  int
}

// NewNonceService constructs a NonceService with defaults
func NewNonceService() (*NonceService, error) {
	key := make([]byte, 16)
	if _, err := rand.Read(key); err != nil {
		return nil, err
	}

	c, err := aes.NewCipher(key)
	if err != nil {
		panic("Failure in NewCipher: " + err.Error())
	}
	gcm, err := cipher.NewGCM(c)
	if err != nil {
		panic("Failure in NewGCM: " + err.Error())
	}

	return &NonceService{
		earliest: 0,
		latest:   0,
		used:     make(map[int64]bool, MaxUsed),
		gcm:      gcm,
		maxUsed:  MaxUsed,
	}, nil
}

func (ns *NonceService) encrypt(counter int64) (string, error) {
	// Generate a nonce with upper 4 bytes zero
	nonce := make([]byte, 12)
	for i := 0; i < 4; i++ {
		nonce[i] = 0
	}
	if _, err := rand.Read(nonce[4:]); err != nil {
		return "", err
	}

	// Encode counter to plaintext
	pt := make([]byte, 8)
	ctr := big.NewInt(counter)
	pad := 8 - len(ctr.Bytes())
	copy(pt[pad:], ctr.Bytes())

	// Encrypt
	ret := make([]byte, nonceLen)
	ct := ns.gcm.Seal(nil, nonce, pt, nil)
	copy(ret, nonce[4:])
	copy(ret[8:], ct)
	return base64.RawURLEncoding.EncodeToString(ret), nil
}

func (ns *NonceService) decrypt(nonce string) (int64, error) {
	decoded, err := base64.RawURLEncoding.DecodeString(nonce)
	if err != nil {
		return 0, err
	}
	if len(decoded) != nonceLen {
		return 0, errInvalidNonceLength
	}

	n := make([]byte, 12)
	for i := 0; i < 4; i++ {
		n[i] = 0
	}
	copy(n[4:], decoded[:8])

	pt, err := ns.gcm.Open(nil, n, decoded[8:], nil)
	if err != nil {
		return 0, err
	}

	ctr := big.NewInt(0)
	ctr.SetBytes(pt)
	return ctr.Int64(), nil
}

// Nonce provides a new Nonce.
func (ns *NonceService) Nonce() (string, error) {
	ns.mu.Lock()
	ns.latest++
	latest := ns.latest
	ns.mu.Unlock()
	return ns.encrypt(latest)
}

// minUsed returns the lowest key in the used map. Requires that a lock be held
// by caller.
func (ns *NonceService) minUsed() int64 {
	min := ns.latest
	for t := range ns.used {
		if t < min {
			min = t
		}
	}
	return min
}

// Valid determines whether the provided Nonce string is valid, returning
// true if so.
func (ns *NonceService) Valid(nonce string) bool {
	c, err := ns.decrypt(nonce)
	if err != nil {
		return false
	}

	ns.mu.Lock()
	defer ns.mu.Unlock()
	if c > ns.latest {
		return false
	}

	if c <= ns.earliest {
		return false
	}

	if ns.used[c] {
		return false
	}

	ns.used[c] = true
	if len(ns.used) > ns.maxUsed {
		ns.earliest = ns.minUsed()
		delete(ns.used, ns.earliest)
	}

	return true
}
<|endoftext|>


<commit_before>package core

import (
	"sync"

	"github.com/degdb/degdb/protocol"
	"github.com/degdb/degdb/query"
)

func (s *server) ExecuteQuery(q *protocol.QueryRequest) ([]*protocol.Triple, error) {
	var triples []*protocol.Triple
	switch q.Type {
	case protocol.BASIC:
		for i, step := range q.Steps {
			if i != 0 {
				var midTriples []*protocol.Triple
				for _, triple := range triples {
					midTriples = append(midTriples, &protocol.Triple{
						Subj: triple.Obj,
					})
				}
				step = &protocol.ArrayOp{
					Arguments: []*protocol.ArrayOp{step},
					Mode:      protocol.AND,
					Triples:   midTriples,
				}
			}

			// External request and is already sharded.
			if q.Sharded {
				return s.ts.QueryArrayOp(step, int(q.Limit))
			}

			var wg sync.WaitGroup
			var triplesLock sync.RWMutex
			triples = nil
			shards := query.ShardQueryByHash(step)

			// Unrooted queries
			if arrayOp, ok := shards[0]; ok {
				// TODO localnode
				set := s.network.MinimumCoveringPeers()
				s.Printf("Minimum covering set %+v", set)
				_ = arrayOp
				wg.Add(len(set))
				req := basicReq(arrayOp)
				var err error
				for _, conn := range set {
					conn := conn
					go func() {
						var msg *protocol.Message
						msg, err = conn.Request(req)
						if err != nil {
							return
						}
						triplesLock.Lock()
						triples = append(triples, msg.GetQueryResponse().Triples...)
						triplesLock.Unlock()
						wg.Done()
					}()
				}
				wg.Wait()
				return triples, err
			}

			// Rooted queries
			for hash, arrayOp := range shards {
				if hash == 0 {
					return nil, query.ErrUnRooted
				}
				if s.network.LocalPeer().Keyspace.Includes(hash) {
					trips, err := s.ts.QueryArrayOp(arrayOp, int(q.Limit))
					if err != nil {
						return nil, err
					}
					triples = append(triples, trips...)
					continue
				}
			Peers:
				for _, conn := range s.network.Peers {
					if conn == nil || conn.Peer == nil {
						continue
					}
					if conn.Peer.Keyspace.Includes(hash) {
						req := basicReq(arrayOp)
						// TODO(d4l3k) Parallelize
						msg, err := conn.Request(req)
						if err != nil {
							return nil, err
						}
						triples = append(triples, msg.GetQueryResponse().Triples...)
						break Peers
					}
				}
			}
		}

	//case protocol.GREMLIN:
	//case protocol.MQL:
	default:
		return nil, query.ErrNotImplemented
	}
	return triples, nil
}

func basicReq(arrayOp *protocol.ArrayOp) *protocol.Message {
	return &protocol.Message{Message: &protocol.Message_QueryRequest{
		QueryRequest: &protocol.QueryRequest{
			Type:    protocol.BASIC,
			Steps:   []*protocol.ArrayOp{arrayOp},
			Sharded: true,
		}}}
}
<commit_msg>Added timeout to unrooted queries<commit_after>package core

import (
	"sync"
	"time"

	"github.com/degdb/degdb/protocol"
	"github.com/degdb/degdb/query"
)

func (s *server) ExecuteQuery(q *protocol.QueryRequest) ([]*protocol.Triple, error) {
	var triples []*protocol.Triple
	switch q.Type {
	case protocol.BASIC:
		for i, step := range q.Steps {
			if i != 0 {
				var midTriples []*protocol.Triple
				for _, triple := range triples {
					midTriples = append(midTriples, &protocol.Triple{
						Subj: triple.Obj,
					})
				}
				step = &protocol.ArrayOp{
					Arguments: []*protocol.ArrayOp{step},
					Mode:      protocol.AND,
					Triples:   midTriples,
				}
			}

			// External request and is already sharded.
			if q.Sharded {
				return s.ts.QueryArrayOp(step, int(q.Limit))
			}

			var wg sync.WaitGroup
			var triplesLock sync.RWMutex
			triples = nil
			shards := query.ShardQueryByHash(step)

			// Unrooted queries
			if arrayOp, ok := shards[0]; ok {
				// TODO localnode
				set := s.network.MinimumCoveringPeers()
				s.Printf("Minimum covering set %+v", set)
				_ = arrayOp
				wg.Add(len(set))
				req := basicReq(arrayOp)
				var err error
				for _, conn := range set {
					conn := conn
					go func() {
						var msg *protocol.Message
						msg, err = conn.Request(req)
						if err != nil {
							return
						}
						triplesLock.Lock()
						// TODO(d4l3k): Deduplicate triples
						triples = append(triples, msg.GetQueryResponse().Triples...)
						triplesLock.Unlock()
						done := make(chan bool, 1)
						go func() {
							wg.Done()
							done <- true
						}()
						go func() {
							time.Sleep(10 * time.Second)
							done <- true
						}()
						<-done
					}()
				}
				wg.Wait()
				return triples, err
			}

			// Rooted queries
			for hash, arrayOp := range shards {
				if hash == 0 {
					return nil, query.ErrUnRooted
				}
				if s.network.LocalPeer().Keyspace.Includes(hash) {
					trips, err := s.ts.QueryArrayOp(arrayOp, int(q.Limit))
					if err != nil {
						return nil, err
					}
					triples = append(triples, trips...)
					continue
				}
			Peers:
				for _, conn := range s.network.Peers {
					if conn == nil || conn.Peer == nil {
						continue
					}
					if conn.Peer.Keyspace.Includes(hash) {
						req := basicReq(arrayOp)
						// TODO(d4l3k) Parallelize
						msg, err := conn.Request(req)
						if err != nil {
							return nil, err
						}
						triples = append(triples, msg.GetQueryResponse().Triples...)
						break Peers
					}
				}
			}
		}

	//case protocol.GREMLIN:
	//case protocol.MQL:
	default:
		return nil, query.ErrNotImplemented
	}
	return triples, nil
}

func basicReq(arrayOp *protocol.ArrayOp) *protocol.Message {
	return &protocol.Message{Message: &protocol.Message_QueryRequest{
		QueryRequest: &protocol.QueryRequest{
			Type:    protocol.BASIC,
			Steps:   []*protocol.ArrayOp{arrayOp},
			Sharded: true,
		}}}
}
<|endoftext|>


<commit_before>// -*- tab-width: 4 -*-
package couch

import (
	"bytes"
	"encoding/base64"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"testing"
	"time"
)

func TestHttpError(t *testing.T) {
	err := HttpError{404, "four oh four"}
	if err.Error() != "four oh four" {
		t.Errorf(`Expected "four oh four", got %q`, err.Error())
	}
}

func tGetCreds(r *http.Request) (string, string) {
	ah := r.Header.Get("Authorization")
	if ah == "" {
		return "", ""
	}
	parts := strings.Fields(ah)
	if len(parts) < 2 {
		return "", ""
	}
	dec, err := base64.StdEncoding.DecodeString(parts[1])
	if err != nil {
		return "", ""
	}
	parts = strings.SplitN(string(dec), ":", 2)
	if len(parts) != 2 {
		return "", ""
	}
	return parts[0], parts[1]
}

func TestReqGen(t *testing.T) {
	tests := []struct {
		in         string
		user, pass string
		fails      bool
	}{
		{"http://localhost:5984/%", "", "", true},
		{"http://localhost:5984/", "", "", false},
		{"http://me:secret@localhost:5984/", "me", "secret", false},
	}

	for _, test := range tests {
		req, err := createReq(test.in)
		switch {
		case err == nil && !test.fails:
			u, p := tGetCreds(req)
			if u != test.user || p != test.pass {
				t.Errorf("Expected user=%q, pass=%q, got %q/%q",
					test.user, test.pass, u, p)
			}
		case err == nil && test.fails:
			t.Errorf("Expected failure on %q, got %v", test.in, req)
		case err != nil && !test.fails:
			t.Errorf("Unexpected failure on %q: %v", test.in, err)
		}
	}
}

type mocktrip struct {
	expurl string
	res    []byte
	rc     int
	hdrs   http.Header
}

func (m *mocktrip) RoundTrip(req *http.Request) (*http.Response, error) {
	if m.expurl != req.URL.String() {
		return nil, &HttpError{400, "Incorrect url: " + req.URL.String()}
	}
	m.hdrs = req.Header
	return &http.Response{
		Body:       ioutil.NopCloser(bytes.NewReader(m.res)),
		Status:     "200 OK",
		StatusCode: m.rc,
	}, nil
}

func installClient(c *http.Client) {
	HttpClient = c
}

func TestUnmarshalURLGolden(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 200, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	err := unmarshal_url(u, &idr)
	if err != nil {
		t.Fatalf("Error unmarshaling: %v", err)
	}

	if idr.Id != "theid" || idr.Rev != "therev" {
		t.Fatalf("Expected theid/therev, got %v", idr)
	}
}

func TestUnmarshURLError(t *testing.T) {
	err := unmarshal_url("http://%", nil)
	if err == nil {
		t.Fatalf("Successfully unmarshalled from nothing?")
	} else if !strings.Contains(err.Error(), "hexadecimal escape") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestUnmarshSchemeError(t *testing.T) {
	err := unmarshal_url("mailto:dustin@arpa.in", nil)
	if err == nil {
		t.Fatalf("Successfully unmarshalled from nothing?")
	} else if !strings.Contains(err.Error(), "unsupported protocol") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestInteractGolden(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 200, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	n, err := interact("POST", u, map[string][]string{}, []byte{'{', '}'}, &idr)
	if n != 200 || err != nil {
		t.Fatalf("Error unmarshaling: %v/%v", n, err)
	}

	if m.hdrs.Get("Content-Type") != "application/json" {
		t.Errorf("Expected JSON header, got %q", m.hdrs.Get("Content-Type"))
	}

	if idr.Id != "theid" || idr.Rev != "therev" {
		t.Fatalf("Expected theid/therev, got %v", idr)
	}
}

func TestInteractBadResp(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 419, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	n, err := interact("POST", u, map[string][]string{}, []byte{'{', '}'}, &idr)
	if n != 419 || err == nil {
		t.Fatalf("Expected error 419, got: %v/%v", n, err)
	}
}

func TestInteractError(t *testing.T) {
	_, err := interact("POST", "http://%", map[string][]string{}, nil, nil)
	if err == nil {
		t.Fatalf("Successfully interacted with nothing?")
	} else if !strings.Contains(err.Error(), "hexadecimal escape") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestInteractSchemeError(t *testing.T) {
	_, err := interact("POST", "mailto:dustin@arpa.in", map[string][]string{}, nil, nil)
	if err == nil {
		t.Fatalf("Successfully interacted with nothing?")
	} else if !strings.Contains(err.Error(), "unsupported protocol") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

type fakeHttp http.Response

func (f fakeHttp) RoundTrip(*http.Request) (*http.Response, error) {
	p := http.Response(f)
	return &p, nil
}

func installFakeHttp(f fakeHttp) *http.Client {
	rv := HttpClient
	HttpClient = &http.Client{Transport: f}
	return rv
}

func uninstallFakeHttp(h *http.Client) {
	HttpClient = h
}

func TestUnmarshalBadReq(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 404,
		Status:     "404 four-oh-four",
		Body:       ioutil.NopCloser(&bytes.Buffer{}),
	}))

	err := unmarshal_url("http://www.example.com/", nil)
	if err == nil {
		t.Fatalf("Successfully got example?")
	} else if !strings.Contains(err.Error(), "four-oh-four") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestRunningSuccess(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`["adb"]`)),
	}))
	d := Database{}
	if !d.Running() {
		t.Fatalf("Expected DB to be considered running.  Wasn't.")
	}
}

func TestRunningEmpty(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`[]`)),
	}))
	d := Database{}
	if d.Running() {
		t.Fatalf("Expected DB to be considered not running.  Was.")
	}
}

func TestDBExists(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "x"}`)),
	}))
	d := Database{Name: "x"}
	if !d.Exists() {
		t.Errorf("Expected DB to exist.  Didn't.")
	}

	installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "y"}`)),
	})
	if d.Exists() {
		t.Errorf("Expected DB to not exist.  Did.")
	}

	installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "`)),
	})
	if d.Exists() {
		t.Errorf("Expected DB to not exist.  Did.")
	}
}

func TestRunningError(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`[`)),
	}))
	d := Database{}
	if d.Running() {
		t.Fatalf("Expected DB to be considered not running.  Was.")
	}
}

func TestURLs(t *testing.T) {
	tests := []struct {
		db  Database
		exp string
	}{
		{Database{"locohost", "5984", "dbx", nil},
			"http://locohost:5984/dbx"},
		{Database{"locohost", "5984", "dbx", url.UserPassword("a", "b")},
			"http://a:b@locohost:5984/dbx"},
	}
	for _, test := range tests {
		if test.db.DBURL() != test.exp {
			t.Errorf("Error on %v, expected %v, got %v",
				test.db, test.exp, test.db.DBURL())
		}
	}
}

type testRC struct {
	bytes, reads int
	err          error
}

func (t *testRC) Read(b []byte) (int, error) {
	t.reads++
	t.bytes += len(b)
	return len(b), t.err
}

func (t *testRC) Close() error {
	t.err = io.EOF
	return nil
}

type testDeadliner int

func (t *testDeadliner) SetReadDeadline(time.Time) error {
	*t++
	return nil
}

func TestTimeoutClient(t *testing.T) {
	trc := &testRC{}
	var td testDeadliner
	tc := timeoutClient{trc, &td, 13}
	buf := make([]byte, 4096)

	_, err := tc.Read(buf)
	if err != nil {
		t.Fatalf("Failed first read: %v", err)
	}
	tc.Close()
	_, err = tc.Read(buf)
	if err == nil {
		t.Fatalf("Didn't fail second read")
	}

	if trc.reads != 2 || trc.bytes != 8192 {
		t.Errorf("Expected %v reads at %v bytes, got %v / %v",
			2, 8912, trc.reads, trc.bytes)
	}
}

func TestI64Opt(t *testing.T) {
	m := map[string]interface{}{
		"a": 1,
		"b": int64(2),
		"c": 3.14,
		"d": "4",
		"e": "five",
		"f": TestI64Opt,
	}

	tests := map[string]int64{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
		"e": 99,
		"f": 99,
	}

	for k, exp := range tests {
		got := i64defopt(m, k, 99)
		if got != exp {
			t.Errorf("Expected %v for %v (%v), got %v",
				exp, k, m[k], got)
		}
	}
}
<commit_msg>Validate custom headers<commit_after>// -*- tab-width: 4 -*-
package couch

import (
	"bytes"
	"encoding/base64"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"testing"
	"time"
)

func TestHttpError(t *testing.T) {
	err := HttpError{404, "four oh four"}
	if err.Error() != "four oh four" {
		t.Errorf(`Expected "four oh four", got %q`, err.Error())
	}
}

func tGetCreds(r *http.Request) (string, string) {
	ah := r.Header.Get("Authorization")
	if ah == "" {
		return "", ""
	}
	parts := strings.Fields(ah)
	if len(parts) < 2 {
		return "", ""
	}
	dec, err := base64.StdEncoding.DecodeString(parts[1])
	if err != nil {
		return "", ""
	}
	parts = strings.SplitN(string(dec), ":", 2)
	if len(parts) != 2 {
		return "", ""
	}
	return parts[0], parts[1]
}

func TestReqGen(t *testing.T) {
	tests := []struct {
		in         string
		user, pass string
		fails      bool
	}{
		{"http://localhost:5984/%", "", "", true},
		{"http://localhost:5984/", "", "", false},
		{"http://me:secret@localhost:5984/", "me", "secret", false},
	}

	for _, test := range tests {
		req, err := createReq(test.in)
		switch {
		case err == nil && !test.fails:
			u, p := tGetCreds(req)
			if u != test.user || p != test.pass {
				t.Errorf("Expected user=%q, pass=%q, got %q/%q",
					test.user, test.pass, u, p)
			}
		case err == nil && test.fails:
			t.Errorf("Expected failure on %q, got %v", test.in, req)
		case err != nil && !test.fails:
			t.Errorf("Unexpected failure on %q: %v", test.in, err)
		}
	}
}

type mocktrip struct {
	expurl string
	res    []byte
	rc     int
	hdrs   http.Header
}

func (m *mocktrip) RoundTrip(req *http.Request) (*http.Response, error) {
	if m.expurl != req.URL.String() {
		return nil, &HttpError{400, "Incorrect url: " + req.URL.String()}
	}
	m.hdrs = req.Header
	return &http.Response{
		Body:       ioutil.NopCloser(bytes.NewReader(m.res)),
		Status:     "200 OK",
		StatusCode: m.rc,
	}, nil
}

func installClient(c *http.Client) {
	HttpClient = c
}

func TestUnmarshalURLGolden(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 200, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	err := unmarshal_url(u, &idr)
	if err != nil {
		t.Fatalf("Error unmarshaling: %v", err)
	}

	if idr.Id != "theid" || idr.Rev != "therev" {
		t.Fatalf("Expected theid/therev, got %v", idr)
	}
}

func TestUnmarshURLError(t *testing.T) {
	err := unmarshal_url("http://%", nil)
	if err == nil {
		t.Fatalf("Successfully unmarshalled from nothing?")
	} else if !strings.Contains(err.Error(), "hexadecimal escape") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestUnmarshSchemeError(t *testing.T) {
	err := unmarshal_url("mailto:dustin@arpa.in", nil)
	if err == nil {
		t.Fatalf("Successfully unmarshalled from nothing?")
	} else if !strings.Contains(err.Error(), "unsupported protocol") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestInteractGolden(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 200, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	n, err := interact("POST", u, map[string][]string{"X-What": []string{"a"}},
		[]byte{'{', '}'}, &idr)
	if n != 200 || err != nil {
		t.Fatalf("Error unmarshaling: %v/%v", n, err)
	}

	if m.hdrs.Get("Content-Type") != "application/json" {
		t.Errorf("Expected JSON header, got %q", m.hdrs.Get("Content-Type"))
	}
	if m.hdrs.Get("X-What") != "a" {
		t.Errorf("Expected custom header, got %q\n%v", m.hdrs.Get("X-What"), m.hdrs)
	}

	if idr.Id != "theid" || idr.Rev != "therev" {
		t.Fatalf("Expected theid/therev, got %v", idr)
	}
}

func TestInteractBadResp(t *testing.T) {
	defer installClient(http.DefaultClient)

	u := "http://localhost:8654/thing"
	m := mocktrip{u, []byte(`{"_id": "theid", "_rev": "therev"}`), 419, nil}

	installClient(&http.Client{Transport: &m})

	idr := IdAndRev{}
	n, err := interact("POST", u, map[string][]string{}, []byte{'{', '}'}, &idr)
	if n != 419 || err == nil {
		t.Fatalf("Expected error 419, got: %v/%v", n, err)
	}
}

func TestInteractError(t *testing.T) {
	_, err := interact("POST", "http://%", map[string][]string{}, nil, nil)
	if err == nil {
		t.Fatalf("Successfully interacted with nothing?")
	} else if !strings.Contains(err.Error(), "hexadecimal escape") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestInteractSchemeError(t *testing.T) {
	_, err := interact("POST", "mailto:dustin@arpa.in", map[string][]string{}, nil, nil)
	if err == nil {
		t.Fatalf("Successfully interacted with nothing?")
	} else if !strings.Contains(err.Error(), "unsupported protocol") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

type fakeHttp http.Response

func (f fakeHttp) RoundTrip(*http.Request) (*http.Response, error) {
	p := http.Response(f)
	return &p, nil
}

func installFakeHttp(f fakeHttp) *http.Client {
	rv := HttpClient
	HttpClient = &http.Client{Transport: f}
	return rv
}

func uninstallFakeHttp(h *http.Client) {
	HttpClient = h
}

func TestUnmarshalBadReq(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 404,
		Status:     "404 four-oh-four",
		Body:       ioutil.NopCloser(&bytes.Buffer{}),
	}))

	err := unmarshal_url("http://www.example.com/", nil)
	if err == nil {
		t.Fatalf("Successfully got example?")
	} else if !strings.Contains(err.Error(), "four-oh-four") {
		t.Fatalf("Unexpected error: %q", err.Error())
	}
}

func TestRunningSuccess(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`["adb"]`)),
	}))
	d := Database{}
	if !d.Running() {
		t.Fatalf("Expected DB to be considered running.  Wasn't.")
	}
}

func TestRunningEmpty(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`[]`)),
	}))
	d := Database{}
	if d.Running() {
		t.Fatalf("Expected DB to be considered not running.  Was.")
	}
}

func TestDBExists(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "x"}`)),
	}))
	d := Database{Name: "x"}
	if !d.Exists() {
		t.Errorf("Expected DB to exist.  Didn't.")
	}

	installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "y"}`)),
	})
	if d.Exists() {
		t.Errorf("Expected DB to not exist.  Did.")
	}

	installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`{"db_name": "`)),
	})
	if d.Exists() {
		t.Errorf("Expected DB to not exist.  Did.")
	}
}

func TestRunningError(t *testing.T) {
	defer uninstallFakeHttp(installFakeHttp(fakeHttp{
		StatusCode: 200,
		Body:       ioutil.NopCloser(strings.NewReader(`[`)),
	}))
	d := Database{}
	if d.Running() {
		t.Fatalf("Expected DB to be considered not running.  Was.")
	}
}

func TestURLs(t *testing.T) {
	tests := []struct {
		db  Database
		exp string
	}{
		{Database{"locohost", "5984", "dbx", nil},
			"http://locohost:5984/dbx"},
		{Database{"locohost", "5984", "dbx", url.UserPassword("a", "b")},
			"http://a:b@locohost:5984/dbx"},
	}
	for _, test := range tests {
		if test.db.DBURL() != test.exp {
			t.Errorf("Error on %v, expected %v, got %v",
				test.db, test.exp, test.db.DBURL())
		}
	}
}

type testRC struct {
	bytes, reads int
	err          error
}

func (t *testRC) Read(b []byte) (int, error) {
	t.reads++
	t.bytes += len(b)
	return len(b), t.err
}

func (t *testRC) Close() error {
	t.err = io.EOF
	return nil
}

type testDeadliner int

func (t *testDeadliner) SetReadDeadline(time.Time) error {
	*t++
	return nil
}

func TestTimeoutClient(t *testing.T) {
	trc := &testRC{}
	var td testDeadliner
	tc := timeoutClient{trc, &td, 13}
	buf := make([]byte, 4096)

	_, err := tc.Read(buf)
	if err != nil {
		t.Fatalf("Failed first read: %v", err)
	}
	tc.Close()
	_, err = tc.Read(buf)
	if err == nil {
		t.Fatalf("Didn't fail second read")
	}

	if trc.reads != 2 || trc.bytes != 8192 {
		t.Errorf("Expected %v reads at %v bytes, got %v / %v",
			2, 8912, trc.reads, trc.bytes)
	}
}

func TestI64Opt(t *testing.T) {
	m := map[string]interface{}{
		"a": 1,
		"b": int64(2),
		"c": 3.14,
		"d": "4",
		"e": "five",
		"f": TestI64Opt,
	}

	tests := map[string]int64{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
		"e": 99,
		"f": 99,
	}

	for k, exp := range tests {
		got := i64defopt(m, k, 99)
		if got != exp {
			t.Errorf("Expected %v for %v (%v), got %v",
				exp, k, m[k], got)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"math/big"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	agent     = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36"
	success   = "SUCCESS"
	auth_fail = "AUTH_FAILURE"
)

type LoginResponse struct {
	Context         string
	Type            string
	Opaque          string
	NextStateId     string
	OrgUrl          string
	keepAliveActive bool
	delayInterval   string
}

type LoginParamsRaw struct {
	M          string
	E          string
	LoginToken string
}

type LoginParams struct {
	PublicKey  rsa.PublicKey
	LoginToken string
}

type Attributes struct {
	CheckStatus        bool
	Authenticated      bool
	AgreementVerified  bool
	AgentConnected     bool
	OrgUrl             string
	AgentOsSupported   bool
	AgentRequired      bool
	TimeToEndOfSession int
	TextToEndOfSession string
	KeepaliveRequired  bool
	KeepaliveInterval  int
}

func (r *LoginResponse) String() string {
	return r.Type
}

func (a *Attributes) String() string {
	return fmt.Sprintf("authenticated: %v, end of session: %s", a.Authenticated, a.TextToEndOfSession)
}

func NewLoginParamsRaw(params []byte) (LoginParamsRaw, error) {
	var lpr LoginParamsRaw
	err := json.Unmarshal(params, &lpr)
	return lpr, err
}

func NewLoginParams(params LoginParamsRaw) (*LoginParams, error) {
	m := new(big.Int)
	m.SetString(params.M, 16)
	e, err := strconv.ParseInt(params.E, 16, 0)
	if err != nil {
		return nil, err
	}
	return &LoginParams{rsa.PublicKey{m, int(e)}, params.LoginToken}, nil
}

func login(client *http.Client, uri, user, password string, params *LoginParams) (*LoginResponse, error) {
	crypted_password, err := encrypt(rand.Reader, *params, password)
	if err != nil {
		log.Printf("Error encrypting password: %v", err)
		return nil, err
	}

	response, err := sendPassword(client, uri, user, crypted_password)
	if err != nil {
		log.Printf("Error sending login data: %v", err)
		return nil, err
	}

	if response.Type == auth_fail {
		log.Print("Invalid username/password")
		return nil, err
	}
	if response.Type != success {
		log.Printf("Error logging in: %s", *response)
		return nil, err
	}
	log.Printf("Logged in as %s", user)
	return response, nil
}

func postLogin(client *http.Client, uri string) (*Attributes, error) {
	_, err := fetch(client, uri, "/connect/GetStateAndView")
	if err != nil {
		log.Printf("Error loading post login page: %v", err)
		return nil, err
	}
	attr, err := fetchAttributes(client, uri)
	if err != nil {
		log.Printf("Error loading attributes: %v", err)
		return nil, err
	}
	return attr, nil
}

func checkConnection(client *http.Client, uri string) error {
	_, err := fetch(client, uri, "")
	if err != nil {
		log.Printf("Unable to reach %s: %v", uri, err)
		return err
	}
	log.Printf("Reached %s sucessfully", uri)
	return nil
}

func run(client *http.Client, uri, user, password, check string) error {
	if len(check) == 0 || checkConnection(client, check) != nil {
		lp, err := fetchLoginParams(client, uri)
		if err != nil {
			return err
		}
		_, err = login(client, uri, user, password, lp)
		if err != nil {
			log.Printf("Login failed: %v", err)
			return err
		}
		attr, err := postLogin(client, uri)
		if err != nil {
			log.Printf("Post login failed: %v", err)
			return err
		}
		if attr.TimeToEndOfSession > 0 {
			log.Printf("End of session: %s", attr.TextToEndOfSession)
		} else {
			return errors.New(fmt.Sprintf("Session setup failed: %v", attr))
		}

		if len(check) > 0 {
			return checkConnection(client, check)
		}
	}
	return nil
}

func main() {
	var uri string
	var user string
	var password string
	var checkUrl string
	var interval uint
	var insecure bool
	flag.StringVar(&uri, "url", os.Getenv("CPFW_AUTH_URL"), "login form base url, also: CPFW_AUTH_URL")
	flag.StringVar(&user, "user", os.Getenv("CPFW_AUTH_USER"), "login username, also: CPFW_AUTH_USER")
	flag.StringVar(&password, "password", os.Getenv("CPFW_AUTH_PASSWORD"), "login password, also: CPFW_AUTH_PASSWORD")
	flag.StringVar(&checkUrl, "check", os.Getenv("CPFW_AUTH_checkUrl"), "check url for successful login, also: CPFW_AUTH_checkUrl")
	flag.UintVar(&interval, "interval", 0, "recheck connection every Xs")
	flag.BoolVar(&insecure, "insecure", false, "don't verify SSL/TLS connections")
	flag.Parse()

	if len(uri) == 0 {
		log.Println("Missing mandatory parameter: uri")
		os.Exit(1)
	}
	if len(user) == 0 {
		log.Println("Missing mandatory parameter: user")
		os.Exit(1)
	}
	if len(password) == 0 {
		log.Println("Missing mandatory parameter: password")
		os.Exit(1)
	}
	log.Printf("Connecting to: %s", uri)

	client := httpClient(uri, user, insecure)
	for {
		err := run(client, uri, user, password, checkUrl)
		if interval <= 0 {
			// exit loop when not looping
			if err != nil {
				log.Printf("unexpected error: %v", err)
				os.Exit(1)
			}
			break
		}
		time.Sleep(time.Duration(interval) * time.Second)
	}
}
<commit_msg>fix ENV var for --check arg<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"math/big"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	agent     = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36"
	success   = "SUCCESS"
	auth_fail = "AUTH_FAILURE"
)

type LoginResponse struct {
	Context         string
	Type            string
	Opaque          string
	NextStateId     string
	OrgUrl          string
	keepAliveActive bool
	delayInterval   string
}

type LoginParamsRaw struct {
	M          string
	E          string
	LoginToken string
}

type LoginParams struct {
	PublicKey  rsa.PublicKey
	LoginToken string
}

type Attributes struct {
	CheckStatus        bool
	Authenticated      bool
	AgreementVerified  bool
	AgentConnected     bool
	OrgUrl             string
	AgentOsSupported   bool
	AgentRequired      bool
	TimeToEndOfSession int
	TextToEndOfSession string
	KeepaliveRequired  bool
	KeepaliveInterval  int
}

func (r *LoginResponse) String() string {
	return r.Type
}

func (a *Attributes) String() string {
	return fmt.Sprintf("authenticated: %v, end of session: %s", a.Authenticated, a.TextToEndOfSession)
}

func NewLoginParamsRaw(params []byte) (LoginParamsRaw, error) {
	var lpr LoginParamsRaw
	err := json.Unmarshal(params, &lpr)
	return lpr, err
}

func NewLoginParams(params LoginParamsRaw) (*LoginParams, error) {
	m := new(big.Int)
	m.SetString(params.M, 16)
	e, err := strconv.ParseInt(params.E, 16, 0)
	if err != nil {
		return nil, err
	}
	return &LoginParams{rsa.PublicKey{m, int(e)}, params.LoginToken}, nil
}

func login(client *http.Client, uri, user, password string, params *LoginParams) (*LoginResponse, error) {
	crypted_password, err := encrypt(rand.Reader, *params, password)
	if err != nil {
		log.Printf("Error encrypting password: %v", err)
		return nil, err
	}

	response, err := sendPassword(client, uri, user, crypted_password)
	if err != nil {
		log.Printf("Error sending login data: %v", err)
		return nil, err
	}

	if response.Type == auth_fail {
		log.Print("Invalid username/password")
		return nil, err
	}
	if response.Type != success {
		log.Printf("Error logging in: %s", *response)
		return nil, err
	}
	log.Printf("Logged in as %s", user)
	return response, nil
}

func postLogin(client *http.Client, uri string) (*Attributes, error) {
	_, err := fetch(client, uri, "/connect/GetStateAndView")
	if err != nil {
		log.Printf("Error loading post login page: %v", err)
		return nil, err
	}
	attr, err := fetchAttributes(client, uri)
	if err != nil {
		log.Printf("Error loading attributes: %v", err)
		return nil, err
	}
	return attr, nil
}

func checkConnection(client *http.Client, uri string) error {
	_, err := fetch(client, uri, "")
	if err != nil {
		log.Printf("Unable to reach %s: %v", uri, err)
		return err
	}
	log.Printf("Reached %s sucessfully", uri)
	return nil
}

func run(client *http.Client, uri, user, password, check string) error {
	if len(check) == 0 || checkConnection(client, check) != nil {
		lp, err := fetchLoginParams(client, uri)
		if err != nil {
			return err
		}
		_, err = login(client, uri, user, password, lp)
		if err != nil {
			log.Printf("Login failed: %v", err)
			return err
		}
		attr, err := postLogin(client, uri)
		if err != nil {
			log.Printf("Post login failed: %v", err)
			return err
		}
		if attr.TimeToEndOfSession > 0 {
			log.Printf("End of session: %s", attr.TextToEndOfSession)
		} else {
			return errors.New(fmt.Sprintf("Session setup failed: %v", attr))
		}

		if len(check) > 0 {
			return checkConnection(client, check)
		}
	}
	return nil
}

func main() {
	var uri string
	var user string
	var password string
	var checkUrl string
	var interval uint
	var insecure bool
	flag.StringVar(&uri, "url", os.Getenv("CPFW_AUTH_URL"), "login form base url, also: CPFW_AUTH_URL")
	flag.StringVar(&user, "user", os.Getenv("CPFW_AUTH_USER"), "login username, also: CPFW_AUTH_USER")
	flag.StringVar(&password, "password", os.Getenv("CPFW_AUTH_PASSWORD"), "login password, also: CPFW_AUTH_PASSWORD")
	flag.StringVar(&checkUrl, "check", os.Getenv("CPFW_AUTH_CHECK_URL"), "check url for successful login, also: CPFW_AUTH_CHECK_URL")
	flag.UintVar(&interval, "interval", 0, "recheck connection every Xs")
	flag.BoolVar(&insecure, "insecure", false, "don't verify SSL/TLS connections")
	flag.Parse()

	if len(uri) == 0 {
		log.Println("Missing mandatory parameter: uri")
		os.Exit(1)
	}
	if len(user) == 0 {
		log.Println("Missing mandatory parameter: user")
		os.Exit(1)
	}
	if len(password) == 0 {
		log.Println("Missing mandatory parameter: password")
		os.Exit(1)
	}
	log.Printf("Connecting to: %s", uri)

	client := httpClient(uri, user, insecure)
	for {
		err := run(client, uri, user, password, checkUrl)
		if interval <= 0 {
			// exit loop when not looping
			if err != nil {
				log.Printf("unexpected error: %v", err)
				os.Exit(1)
			}
			break
		}
		time.Sleep(time.Duration(interval) * time.Second)
	}
}
<|endoftext|>