<commit_before>package cmd

import (
	"fmt"
	"path/filepath"

	"github.com/mattes/migrate"
	_ "github.com/mattes/migrate/database/postgres"
	_ "github.com/mattes/migrate/source/file"

	"gopkg.in/src-d/go-kallax.v1/generator"
	cli "gopkg.in/urfave/cli.v1"
)

var Migrate = cli.Command{
	Name:   "migrate",
	Usage:  "Generate migrations for current kallax models",
	Action: migrateAction,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "out, o",
			Usage: "Output directory of migrations",
		},
		cli.StringFlag{
			Name:  "name, n",
			Usage: "Descriptive name for the migration",
			Value: "migration",
		},
		cli.StringSliceFlag{
			Name:  "input, i",
			Usage: "List of directories to scan models from. You can use this flag as many times as you want.",
		},
	},
	Subcommands: cli.Commands{
		Up,
		Down,
	},
}

var migrationFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "dir, d",
		Value: "./migrations",
		Usage: "Directory where your migrations are stored",
	},
	cli.StringFlag{
		Name:  "dsn",
		Usage: "PostgreSQL data source name. Example: `user:pass@localhost:5432/database?sslmode=enable`",
	},
	cli.UintFlag{
		Name:  "steps, n",
		Usage: "Number of migrations to run",
	},
	cli.UintFlag{
		Name:  "version, v",
		Usage: "Migrate to a specific version. If `steps` and this flag are given, this will be used.",
	},
}

var Up = cli.Command{
	Name:   "up",
	Usage:  "Executes the migrations from the current version until the specified version.",
	Action: runMigrationAction(upAction),
	Flags:  migrationFlags,
}

var Down = cli.Command{
	Name:   "down",
	Usage:  "Downgrades the database a certain number of migrations or until a certain version.",
	Action: runMigrationAction(downAction),
	Flags:  migrationFlags,
}

func upAction(m *migrate.Migrate, steps, version uint) error {
	if version > 0 {
		if err := m.Migrate(version); err != nil {
			return fmt.Errorf("kallax: unable to upgrade up to version %d: %s", version, err)
		}
	} else if steps > 0 {
		if err := m.Steps(int(steps)); err != nil {
			return fmt.Errorf("kallax: unable to execute %d migration(s) up: %s", steps, err)
		}
	} else {
		fmt.Println("WARN: No `version` or `steps` provided, upgrading all the way up.")
		if err := m.Up(); err != nil {
			return fmt.Errorf("kallax: unable to upgrade the database all the way up: %s", err)
		}
	}
	reportMigrationSuccess(m)
	return nil
}

func downAction(m *migrate.Migrate, steps, version uint) error {
	if version > 0 {
		if err := m.Migrate(version); err != nil {
			return fmt.Errorf("kallax: unable to upgrade up to version %d: %s", version, err)
		}
	} else if steps > 0 {
		if err := m.Steps(-int(steps)); err != nil {
			return fmt.Errorf("kallax: unable to execute %d migration(s) up: %s", steps, err)
		}
	} else {
		return fmt.Errorf("kallax: no `version` or `steps` provided. You need to specify one of them.")
	}
	reportMigrationSuccess(m)
	return nil
}

func reportMigrationSuccess(m *migrate.Migrate) {
	fmt.Println("Success! the migration has been run.")

	if v, _, err := m.Version(); err != nil {
		fmt.Printf("Unable to check the latest version of the database: %s.\n", err)
	} else {
		fmt.Printf("Database is now at version %d.\n", v)
	}
}

type runMigrationFunc func(m *migrate.Migrate, steps, version uint) error

func runMigrationAction(fn runMigrationFunc) cli.ActionFunc {
	return func(c *cli.Context) error {
		var (
			dir     = c.String("dir")
			dsn     = c.String("dsn")
			steps   = c.Uint("steps")
			version = c.Uint("version")
		)

		ok, err := isDirectory(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot check if `dir` is a directory: %s", err)
		}

		if !ok {
			return fmt.Errorf("kallax: argument `dir` must be a valid directory")
		}

		dir, err = filepath.Abs(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot get absolute path of `dir`: %s", err)
		}

		m, err := migrate.New(fmt.Sprintf("file://%s", dir), fmt.Sprintf("postgres://%s", dsn))
		if err != nil {
			return fmt.Errorf("kallax: unable to open a connection with the database: %s", err)
		}

		return fn(m, steps, version)
	}
}

func migrateAction(c *cli.Context) error {
	dirs := c.StringSlice("input")
	dir := c.String("out")
	name := c.String("name")

	var pkgs []*generator.Package
	for _, dir := range dirs {
		ok, err := isDirectory(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot check directory in `input`: %s", err)
		}

		if !ok {
			return fmt.Errorf("kallax: `input` must be a valid directory")
		}

		p := generator.NewProcessor(dir, nil)
		p.Silent()
		pkg, err := p.Do()
		if err != nil {
			return err
		}

		pkgs = append(pkgs, pkg)
	}

	ok, err := isDirectory(dir)
	if err != nil {
		return fmt.Errorf("kallax: cannot check directory in `out`: %s", err)
	}

	if !ok {
		return fmt.Errorf("kallax: `out` must be a valid directory")
	}

	g := generator.NewMigrationGenerator(name, dir)
	migration, err := g.Build(pkgs...)
	if err != nil {
		return err
	}

	return g.Generate(migration)
}
<commit_msg>add --all flag to migrate all the way up<commit_after>package cmd

import (
	"fmt"
	"path/filepath"

	"github.com/mattes/migrate"
	_ "github.com/mattes/migrate/database/postgres"
	_ "github.com/mattes/migrate/source/file"

	"gopkg.in/src-d/go-kallax.v1/generator"
	cli "gopkg.in/urfave/cli.v1"
)

var Migrate = cli.Command{
	Name:   "migrate",
	Usage:  "Generate migrations for current kallax models",
	Action: migrateAction,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "out, o",
			Usage: "Output directory of migrations",
		},
		cli.StringFlag{
			Name:  "name, n",
			Usage: "Descriptive name for the migration",
			Value: "migration",
		},
		cli.StringSliceFlag{
			Name:  "input, i",
			Usage: "List of directories to scan models from. You can use this flag as many times as you want.",
		},
	},
	Subcommands: cli.Commands{
		Up,
		Down,
	},
}

var migrationFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "dir, d",
		Value: "./migrations",
		Usage: "Directory where your migrations are stored",
	},
	cli.StringFlag{
		Name:  "dsn",
		Usage: "PostgreSQL data source name. Example: `user:pass@localhost:5432/database?sslmode=enable`",
	},
	cli.UintFlag{
		Name:  "steps, n",
		Usage: "Number of migrations to run",
	},
	cli.UintFlag{
		Name:  "version, v",
		Usage: "Migrate to a specific version. If `steps` and this flag are given, this will be used.",
	},
}

var Up = cli.Command{
	Name:   "up",
	Usage:  "Executes the migrations from the current version until the specified version.",
	Action: runMigrationAction(upAction),
	Flags: append(migrationFlags, cli.BoolFlag{
		Name:  "all",
		Usage: "If this flag is used, the database will be migrated all the way up.",
	}),
}

var Down = cli.Command{
	Name:   "down",
	Usage:  "Downgrades the database a certain number of migrations or until a certain version.",
	Action: runMigrationAction(downAction),
	Flags:  migrationFlags,
}

func upAction(m *migrate.Migrate, steps, version uint, all bool) error {
	if all {
		if err := m.Up(); err != nil {
			return fmt.Errorf("kallax: unable to upgrade the database all the way up: %s", err)
		}
	} else if version > 0 {
		if err := m.Migrate(version); err != nil {
			return fmt.Errorf("kallax: unable to upgrade up to version %d: %s", version, err)
		}
	} else if steps > 0 {
		if err := m.Steps(int(steps)); err != nil {
			return fmt.Errorf("kallax: unable to execute %d migration(s) up: %s", steps, err)
		}
	} else {
		return fmt.Errorf("WARN: No `version` or `steps` provided")
	}
	reportMigrationSuccess(m)
	return nil
}

func downAction(m *migrate.Migrate, steps, version uint, all bool) error {
	if version > 0 {
		if err := m.Migrate(version); err != nil {
			return fmt.Errorf("kallax: unable to upgrade up to version %d: %s", version, err)
		}
	} else if steps > 0 {
		if err := m.Steps(-int(steps)); err != nil {
			return fmt.Errorf("kallax: unable to execute %d migration(s) up: %s", steps, err)
		}
	} else {
		return fmt.Errorf("kallax: no `version` or `steps` provided. You need to specify one of them.")
	}
	reportMigrationSuccess(m)
	return nil
}

func reportMigrationSuccess(m *migrate.Migrate) {
	fmt.Println("Success! the migration has been run.")

	if v, _, err := m.Version(); err != nil {
		fmt.Printf("Unable to check the latest version of the database: %s.\n", err)
	} else {
		fmt.Printf("Database is now at version %d.\n", v)
	}
}

type runMigrationFunc func(m *migrate.Migrate, steps, version uint, all bool) error

func runMigrationAction(fn runMigrationFunc) cli.ActionFunc {
	return func(c *cli.Context) error {
		var (
			dir     = c.String("dir")
			dsn     = c.String("dsn")
			steps   = c.Uint("steps")
			version = c.Uint("version")
			all     = c.Bool("all")
		)

		ok, err := isDirectory(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot check if `dir` is a directory: %s", err)
		}

		if !ok {
			return fmt.Errorf("kallax: argument `dir` must be a valid directory")
		}

		dir, err = filepath.Abs(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot get absolute path of `dir`: %s", err)
		}

		m, err := migrate.New(fmt.Sprintf("file://%s", dir), fmt.Sprintf("postgres://%s", dsn))
		if err != nil {
			return fmt.Errorf("kallax: unable to open a connection with the database: %s", err)
		}

		return fn(m, steps, version, all)
	}
}

func migrateAction(c *cli.Context) error {
	dirs := c.StringSlice("input")
	dir := c.String("out")
	name := c.String("name")

	var pkgs []*generator.Package
	for _, dir := range dirs {
		ok, err := isDirectory(dir)
		if err != nil {
			return fmt.Errorf("kallax: cannot check directory in `input`: %s", err)
		}

		if !ok {
			return fmt.Errorf("kallax: `input` must be a valid directory")
		}

		p := generator.NewProcessor(dir, nil)
		p.Silent()
		pkg, err := p.Do()
		if err != nil {
			return err
		}

		pkgs = append(pkgs, pkg)
	}

	ok, err := isDirectory(dir)
	if err != nil {
		return fmt.Errorf("kallax: cannot check directory in `out`: %s", err)
	}

	if !ok {
		return fmt.Errorf("kallax: `out` must be a valid directory")
	}

	g := generator.NewMigrationGenerator(name, dir)
	migration, err := g.Build(pkgs...)
	if err != nil {
		return err
	}

	return g.Generate(migration)
}
<|endoftext|>


<commit_before>// Copyright 2013 commandmocker authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package commandmocker is a simple utility for tests in Go. It adds command
// with expected output/failure to the path.
package commandmocker

import (
	"bufio"
	"crypto/rand"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"syscall"
	"text/template"
	"time"
)

var source = `#!/bin/sh -e

echo=$(which echo)
output="{{.output}}"
dirname=$(dirname ${0})
$echo -n "${output}"{{if .status}} >&2{{end}} | tee -a ${dirname}/.out
for i in "$@"
do
	$echo $i >> ${dirname}/.params
done
touch ${dirname}/.ran
exit {{.status}}
`
var running map[string]string
var runningMutex sync.RWMutex
var pathMutex sync.Mutex

func init() {
	running = map[string]string{}
}

func add(name, output string, status int) (string, error) {
	for {
		runningMutex.RLock()
		_, ok := running[name]
		runningMutex.RUnlock()
		if !ok {
			break
		}
		time.Sleep(1)
	}
	runningMutex.Lock()
	var buf [8]byte
	rand.Read(buf[:])
	tempdir := path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
	_, err := os.Stat(tempdir)
	for !os.IsNotExist(err) {
		rand.Read(buf[:])
		tempdir = path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
		_, err = os.Stat(tempdir)
	}
	running[name] = tempdir
	runningMutex.Unlock()
	err = os.MkdirAll(tempdir, 0777)
	if err != nil {
		return "", err
	}
	f, err := os.OpenFile(path.Join(tempdir, name), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0755)
	if err != nil {
		return "", err
	}
	defer f.Close()
	t, err := template.New(name).Parse(source)
	if err != nil {
		return "", err
	}
	param := map[string]interface{}{
		"output": output,
		"status": status,
	}
	err = t.Execute(f, param)
	if err != nil {
		return "", err
	}
	pathMutex.Lock()
	path := os.Getenv("PATH")
	path = tempdir + ":" + path
	err = os.Setenv("PATH", path)
	pathMutex.Unlock()
	return tempdir, nil
}

// Add creates a temporary directory containing an executable file named "name"
// that prints "output" when executed. It also adds the temporary directory to
// the first position of $PATH.
//
// It returns the temporary directory path (for future removing, using the
// Remove function) and an error if any happen.
func Add(name, output string) (string, error) {
	return add(name, output, 0)
}

// Error works like Add, but the created executable returns a non-zero status
// code (an error). The returned status code will be the value provided by
// status.
func Error(name, output string, status int) (string, error) {
	return add(name, output, status)
}

// Ran indicates whether the mocked executable was called or not.
//
// It just checks if the given tempdir contains a .ran file.
func Ran(tempdir string) bool {
	p := path.Join(tempdir, ".ran")
	_, err := os.Stat(p)
	return err == nil || !os.IsNotExist(err)
}

// Output returns the output generated by the previously added command
// execution.
func Output(tempdir string) string {
	p := path.Join(tempdir, ".out")
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return ""
	}
	return string(b)
}

// Parameters returns a slice containing all positional parameters given to the
// command mocked in tempdir in its last execution.
func Parameters(tempdir string) []string {
	p := path.Join(tempdir, ".params")
	f, err := os.Open(p)
	if err != nil {
		return nil
	}
	defer f.Close()
	var params []string
	reader := bufio.NewReader(f)
	line, err := reader.ReadString('\n')
	for err == nil {
		params = append(params, strings.TrimSpace(line))
		line, err = reader.ReadString('\n')
	}
	return params
}

// Remove removes the tempdir from $PATH and from file system.
//
// This function is intended only to undo what Add does. It returns error if
// the given tempdir is not a temporary directory.
func Remove(tempdir string) error {
	defer func() {
		var k string
		runningMutex.Lock()
		for key, value := range running {
			if value == tempdir {
				k = key
			}
		}
		delete(running, k)
		runningMutex.Unlock()
	}()
	if !strings.HasPrefix(tempdir, os.TempDir()) {
		return errors.New("Remove can only remove temporary directories, tryied to remove " + tempdir)
	}
	path := os.Getenv("PATH")
	index := strings.Index(path, tempdir)
	if index < 0 {
		return errors.New(fmt.Sprintf("%q is not in $PATH", tempdir))
	}
	path = path[:index] + path[index+len(tempdir)+1:]
	err := os.Setenv("PATH", path)
	if err != nil {
		return err
	}
	return os.RemoveAll(tempdir)
}
<commit_msg>mocker: use bufio.Scanner instead of bufio.Reader<commit_after>// Copyright 2013 commandmocker authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package commandmocker is a simple utility for tests in Go. It adds command
// with expected output/failure to the path.
package commandmocker

import (
	"bufio"
	"crypto/rand"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"syscall"
	"text/template"
	"time"
)

var source = `#!/bin/sh -e

echo=$(which echo)
output="{{.output}}"
dirname=$(dirname ${0})
$echo -n "${output}"{{if .status}} >&2{{end}} | tee -a ${dirname}/.out
for i in "$@"
do
	$echo $i >> ${dirname}/.params
done
touch ${dirname}/.ran
exit {{.status}}
`
var running map[string]string
var runningMutex sync.RWMutex
var pathMutex sync.Mutex

func init() {
	running = map[string]string{}
}

func add(name, output string, status int) (string, error) {
	for {
		runningMutex.RLock()
		_, ok := running[name]
		runningMutex.RUnlock()
		if !ok {
			break
		}
		time.Sleep(1)
	}
	runningMutex.Lock()
	var buf [8]byte
	rand.Read(buf[:])
	tempdir := path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
	_, err := os.Stat(tempdir)
	for !os.IsNotExist(err) {
		rand.Read(buf[:])
		tempdir = path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
		_, err = os.Stat(tempdir)
	}
	running[name] = tempdir
	runningMutex.Unlock()
	err = os.MkdirAll(tempdir, 0777)
	if err != nil {
		return "", err
	}
	f, err := os.OpenFile(path.Join(tempdir, name), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0755)
	if err != nil {
		return "", err
	}
	defer f.Close()
	t, err := template.New(name).Parse(source)
	if err != nil {
		return "", err
	}
	param := map[string]interface{}{
		"output": output,
		"status": status,
	}
	err = t.Execute(f, param)
	if err != nil {
		return "", err
	}
	pathMutex.Lock()
	path := os.Getenv("PATH")
	path = tempdir + ":" + path
	err = os.Setenv("PATH", path)
	pathMutex.Unlock()
	return tempdir, nil
}

// Add creates a temporary directory containing an executable file named "name"
// that prints "output" when executed. It also adds the temporary directory to
// the first position of $PATH.
//
// It returns the temporary directory path (for future removing, using the
// Remove function) and an error if any happen.
func Add(name, output string) (string, error) {
	return add(name, output, 0)
}

// Error works like Add, but the created executable returns a non-zero status
// code (an error). The returned status code will be the value provided by
// status.
func Error(name, output string, status int) (string, error) {
	return add(name, output, status)
}

// Ran indicates whether the mocked executable was called or not.
//
// It just checks if the given tempdir contains a .ran file.
func Ran(tempdir string) bool {
	p := path.Join(tempdir, ".ran")
	_, err := os.Stat(p)
	return err == nil || !os.IsNotExist(err)
}

// Output returns the output generated by the previously added command
// execution.
func Output(tempdir string) string {
	p := path.Join(tempdir, ".out")
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return ""
	}
	return string(b)
}

// Parameters returns a slice containing all positional parameters given to the
// command mocked in tempdir in its last execution.
func Parameters(tempdir string) []string {
	p := path.Join(tempdir, ".params")
	f, err := os.Open(p)
	if err != nil {
		return nil
	}
	defer f.Close()
	var params []string
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		params = append(params, scanner.Text())
	}
	return params
}

// Remove removes the tempdir from $PATH and from file system.
//
// This function is intended only to undo what Add does. It returns error if
// the given tempdir is not a temporary directory.
func Remove(tempdir string) error {
	defer func() {
		var k string
		runningMutex.Lock()
		for key, value := range running {
			if value == tempdir {
				k = key
			}
		}
		delete(running, k)
		runningMutex.Unlock()
	}()
	if !strings.HasPrefix(tempdir, os.TempDir()) {
		return errors.New("Remove can only remove temporary directories, tryied to remove " + tempdir)
	}
	path := os.Getenv("PATH")
	index := strings.Index(path, tempdir)
	if index < 0 {
		return errors.New(fmt.Sprintf("%q is not in $PATH", tempdir))
	}
	path = path[:index] + path[index+len(tempdir)+1:]
	err := os.Setenv("PATH", path)
	if err != nil {
		return err
	}
	return os.RemoveAll(tempdir)
}
<|endoftext|>


<commit_before>package backend

import (
	"github.com/Sirupsen/logrus"
	"github.com/asdine/storm"
	"github.com/labstack/echo"
)

// ProxyProtocol represents the protocol a proxy uses
type ProxyProtocol string

const (
	// HTTPProxyProtocol represents http protocol
	HTTPProxyProtocol = ProxyProtocol("Http")
	// HTTPSProxyProtocol represents https protocol
	HTTPSProxyProtocol = ProxyProtocol("Https")
	// Socks4ProxyProtocol represents socks 4 protocol
	Socks4ProxyProtocol = ProxyProtocol("Socks 4")
	// Socks5ProxyProtocol represents socks 5 protocol
	Socks5ProxyProtocol = ProxyProtocol("Socks 5")
)

// ProxyType represents the anonymity type of the proxy
type ProxyType string

const (
	// HighProxyType is high anonymity
	HighProxyType = ProxyType("High")
	// MiddleProxyType is middle anonymity
	MiddleProxyType = ProxyType("Middle")
	// LowProxyType is low anonymity
	LowProxyType = ProxyType("Low")
)

// Proxy represents a proxy
type Proxy struct {
	ID           int    `storm:"id,increment"`
	Identifier   string `storm:"unique"`
	IP           string
	Port         int
	DeadSince    int
	Alive        bool
	Type         ProxyType     `storm:"index"`
	Protocol     ProxyProtocol `storm:"index"`
	Joined       int64
	LastCheck    int64
	Checks       []Check
	ChecksLength int
	SubmittedBy  int
}

// Check represents a proxy check
type Check struct {
	ResponseTime int
	Alive        bool
	DoneBy       int
	Key          string
}

// User represents a user
type User struct {
	ID         int   `storm:"id,increment" json:"-"`
	Submitted  int   `json:"submitted"`
	Checked    int   `json:"checked"`
	Points     int   `json:"points"`
	Joined     int64 `json:"-"`
	LastActive int64 `json:"-"`
}

// Instance represents a server instance
type Instance struct {
	Database      *storm.DB
	Log           *logrus.Logger
	Router        *echo.Echo
	IncomingProxy chan AddRequest
}

// AddRequest represents a request to add a proxie to the database
type AddRequest struct {
	Proxies []string
	By      int
}

// CheckRequest represents a request for the client
type CheckRequest struct {
	Token    string
	IP       string
	Port     int
	Protocol ProxyProtocol
}

// CheckResult represents a result from the client
type CheckResult struct {
	Token string
	Alive bool
	Ms    int64
}
<commit_msg>Added checkid and some json tags.<commit_after>package backend

import (
	"github.com/Sirupsen/logrus"
	"github.com/asdine/storm"
	"github.com/labstack/echo"
)

// ProxyProtocol represents the protocol a proxy uses
type ProxyProtocol string

const (
	// HTTPProxyProtocol represents http protocol
	HTTPProxyProtocol = ProxyProtocol("Http")
	// HTTPSProxyProtocol represents https protocol
	HTTPSProxyProtocol = ProxyProtocol("Https")
	// Socks4ProxyProtocol represents socks 4 protocol
	Socks4ProxyProtocol = ProxyProtocol("Socks 4")
	// Socks5ProxyProtocol represents socks 5 protocol
	Socks5ProxyProtocol = ProxyProtocol("Socks 5")
)

// ProxyType represents the anonymity type of the proxy
type ProxyType string

const (
	// HighProxyType is high anonymity
	HighProxyType = ProxyType("High")
	// MiddleProxyType is middle anonymity
	MiddleProxyType = ProxyType("Middle")
	// LowProxyType is low anonymity
	LowProxyType = ProxyType("Low")
)

// Proxy represents a proxy
type Proxy struct {
	ID           int    `storm:"id,increment"`
	Identifier   string `storm:"unique"`
	IP           string
	Port         int
	DeadSince    int
	Alive        bool
	CheckID      int
	Type         ProxyType     `storm:"index"`
	Protocol     ProxyProtocol `storm:"index"`
	Joined       int64
	LastCheck    int64
	Checks       []Check
	ChecksLength int
	SubmittedBy  int
}

// Check represents a proxy check
type Check struct {
	ResponseTime int
	Alive        bool
	DoneBy       int
	Key          string
}

// User represents a user
type User struct {
	ID         int   `storm:"id,increment" json:"-"`
	Submitted  int   `json:"submitted"`
	Checked    int   `json:"checked"`
	Points     int   `json:"points"`
	Joined     int64 `json:"-"`
	LastActive int64 `json:"-"`
}

// Instance represents a server instance
type Instance struct {
	Database       *storm.DB
	Log            *logrus.Logger
	Router         *echo.Echo
	IncomingProxy  chan AddRequest
	IncomingResult chan CheckResult
}

// AddRequest represents a request to add a proxie to the database
type AddRequest struct {
	Proxies []string
	By      int
}

// CheckRequest represents a request for the client
type CheckRequest struct {
	Token    string        `json:"token"`
	IP       string        `json:"ip"`
	Port     int           `json:"port"`
	Protocol ProxyProtocol `json:"protocol"`
}

// CheckResult represents a result from the client
type CheckResult struct {
	Token string `json:"token"`
	Alive bool   `json:"alive"`
	Ms    int    `json:"ms"`
}
<|endoftext|>


<commit_before>package mpris2

import dbus "github.com/guelfey/go.dbus"

type Player struct {
	name string // name of the player, e.g "spotify"
}

func NewPlayer(name string) *Player {
	player := new(Player)
	player.name = "org.mpris.MediaPlayer2." + name
	return player
}

func (player *Player) object() (obj *dbus.Object, err error) {
	conn, err := dbus.SessionBus()
	if err != nil {
		return
	}

	obj = conn.Object(player.name, "/org/mpris/MediaPlayer2")
	return
}

func (player *Player) Next() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Next", 0)
	return
}

func (player *Player) Previous() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Previous", 0)
	return
}

func (player *Player) Pause() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Pause", 0)
	return
}

func (player *Player) PlayPause() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.PlayPause", 0)
	return
}

func (player *Player) Stop() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Stop", 0)
	return
}

func (player *Player) Play() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Play", 0)
	return
}

// TODO: fix this function
func (player *Player) Seek(offset uint32) (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Seek", 0, offset)
	return
}
<commit_msg>update<commit_after>package mpris2

import dbus "github.com/guelfey/go.dbus"

type Player struct {
	name string // name of the player, e.g "spotify"
}

func Players() (players []*Player, err error) {
	conn, err := dbus.SessionBus()
	if err != nil {
		return
	}

	for i, name := range conn.Names() {
		players = players[0:i]
		players[i] = NewPlayer(name)
	}
	return
}

func NewPlayer(name string) *Player {
	player := new(Player)
	player.name = "org.mpris.MediaPlayer2." + name
	return player
}

func (player *Player) object() (obj *dbus.Object, err error) {
	conn, err := dbus.SessionBus()
	if err != nil {
		return
	}

	obj = conn.Object(player.name, "/org/mpris/MediaPlayer2")
	return
}

func (player *Player) Next() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Next", 0)
	return
}

func (player *Player) Previous() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Previous", 0)
	return
}

func (player *Player) Pause() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Pause", 0)
	return
}

func (player *Player) PlayPause() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.PlayPause", 0)
	return
}

func (player *Player) Stop() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Stop", 0)
	return
}

func (player *Player) Play() (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Play", 0)
	return
}

// TODO: fix this function
func (player *Player) Seek(offset uint32) (err error) {
	obj, err := player.object()
	if err != nil {
		return
	}

	obj.Call("org.mpris.MediaPlayer2.Player.Seek", 0, offset)
	return
}
<|endoftext|>


<commit_before>package middleware

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

// ResponseWriter is a wrapper around http.ResponseWriter that provides extra
// information about the response.
type ResponseWriter interface {
	http.ResponseWriter

	// Status returns the status code of the response or 0 if the response has
	// not be written.
	Status() int
}

// NewResponseWriter create a new ResponseWriter.
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
	return &responseWriter{rw, 0}
}

type responseWriter struct {
	http.ResponseWriter
	status int
}

// Write writes the data to the connection as part of an HTTP reply.
func (rw *responseWriter) Write(b []byte) (int, error) {
	if rw.status == 0 {
		rw.status = http.StatusOK
	}

	return rw.ResponseWriter.Write(b)
}

// WriteHeader sends an HTTP response header with status code.
func (rw *responseWriter) WriteHeader(s int) {
	rw.status = s
	rw.ResponseWriter.WriteHeader(s)
}

// Status returns the status code of the response or 0 if the response has
// not be written.
func (rw *responseWriter) Status() int {
	return rw.status
}
<commit_msg>Remove uneeded imports<commit_after>package middleware

import (
	"net/http"
)

// ResponseWriter is a wrapper around http.ResponseWriter that provides extra
// information about the response.
type ResponseWriter interface {
	http.ResponseWriter

	// Status returns the status code of the response or 0 if the response has
	// not be written.
	Status() int
}

// NewResponseWriter create a new ResponseWriter.
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
	return &responseWriter{rw, 0}
}

type responseWriter struct {
	http.ResponseWriter
	status int
}

// Write writes the data to the connection as part of an HTTP reply.
func (rw *responseWriter) Write(b []byte) (int, error) {
	if rw.status == 0 {
		rw.status = http.StatusOK
	}

	return rw.ResponseWriter.Write(b)
}

// WriteHeader sends an HTTP response header with status code.
func (rw *responseWriter) WriteHeader(s int) {
	rw.status = s
	rw.ResponseWriter.WriteHeader(s)
}

// Status returns the status code of the response or 0 if the response has
// not be written.
func (rw *responseWriter) Status() int {
	return rw.status
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"io/ioutil"
	"launchpad.net/gnuflag"
	"net/http"
)

type AppCreate struct {
	tsuru.GuessingCommand
	memory int
	fs     *gnuflag.FlagSet
}

func (c *AppCreate) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "app-create",
		Usage:   "app-create <appname> <platform> [--memory/-m memory_in_mb]",
		Desc:    "create a new app.",
		MinArgs: 2,
	}
}

func (c *AppCreate) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = c.GuessingCommand.Flags()
		c.fs.IntVar(&c.memory, "memory", 0, "The maximum amount of memory reserved to each container for this app")
		c.fs.IntVar(&c.memory, "m", 0, "The maximum amount of memory reserved to each container for this app")
	}
	return c.fs
}

func (c *AppCreate) Run(context *cmd.Context, client *cmd.Client) error {
	appName := context.Args[0]
	platform := context.Args[1]
	b := bytes.NewBufferString(fmt.Sprintf(`{"name":"%s","platform":"%s","memory":"%d"}`, appName, platform, c.memory))
	url, err := cmd.GetURL("/apps")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, b)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	out := make(map[string]string)
	err = json.Unmarshal(result, &out)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, "App %q is being created!\n", appName)
	fmt.Fprintln(context.Stdout, "Use app-info to check the status of the app and its units.")
	fmt.Fprintf(context.Stdout, "Your repository for %q project is %q\n", appName, out["repository_url"])
	return nil
}

type AppRemove struct {
	tsuru.GuessingCommand
	yes bool
	fs  *gnuflag.FlagSet
}

func (c *AppRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "app-remove",
		Usage: "app-remove [--app appname] [--assume-yes]",
		Desc: `removes an app.

If you don't provide the app name, tsuru will try to guess it.`,
		MinArgs: 0,
	}
}

func (c *AppRemove) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	var answer string
	if !c.yes {
		fmt.Fprintf(context.Stdout, `Are you sure you want to remove app "%s"? (y/n) `, appName)
		fmt.Fscanf(context.Stdin, "%s", &answer)
		if answer != "y" {
			fmt.Fprintln(context.Stdout, "Abort.")
			return nil
		}
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s", appName))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, `App "%s" successfully removed!`+"\n", appName)
	return nil
}

func (c *AppRemove) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = c.GuessingCommand.Flags()
		c.fs.BoolVar(&c.yes, "assume-yes", false, "Don't ask for confirmation, just remove the app.")
		c.fs.BoolVar(&c.yes, "y", false, "Don't ask for confirmation, just remove the app.")
	}
	return c.fs
}

type UnitAdd struct {
	tsuru.GuessingCommand
}

func (c *UnitAdd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit-add",
		Usage:   "unit-add <# of units> [--app appname]",
		Desc:    "add new units to an app.",
		MinArgs: 1,
	}
}

func (c *UnitAdd) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("PUT", url, bytes.NewBufferString(context.Args[0]))
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Units successfully added!")
	return nil
}

type UnitRemove struct {
	tsuru.GuessingCommand
}

func (c *UnitRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit-remove",
		Usage:   "unit-remove <# of units> [--app appname]",
		Desc:    "remove units from an app.",
		MinArgs: 1,
	}
}

func (c *UnitRemove) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
	if err != nil {
		return err
	}
	body := bytes.NewBufferString(context.Args[0])
	request, err := http.NewRequest("DELETE", url, body)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Units successfully removed!")
	return nil
}
<commit_msg>Small improvement<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"io/ioutil"
	"launchpad.net/gnuflag"
	"net/http"
)

type AppCreate struct {
	tsuru.GuessingCommand
	memory int
	fs     *gnuflag.FlagSet
}

func (c *AppCreate) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "app-create",
		Usage:   "app-create <appname> <platform> [--memory/-m memory_in_mb]",
		Desc:    "create a new app.",
		MinArgs: 2,
	}
}

func (c *AppCreate) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		infoMessage := "The maximum amount of memory reserved to each container for this app"
		c.fs = c.GuessingCommand.Flags()
		c.fs.IntVar(&c.memory, "memory", 0, infoMessage)
		c.fs.IntVar(&c.memory, "m", 0, infoMessage)
	}
	return c.fs
}

func (c *AppCreate) Run(context *cmd.Context, client *cmd.Client) error {
	appName := context.Args[0]
	platform := context.Args[1]
	b := bytes.NewBufferString(fmt.Sprintf(`{"name":"%s","platform":"%s","memory":"%d"}`, appName, platform, c.memory))
	url, err := cmd.GetURL("/apps")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, b)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	out := make(map[string]string)
	err = json.Unmarshal(result, &out)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, "App %q is being created!\n", appName)
	fmt.Fprintln(context.Stdout, "Use app-info to check the status of the app and its units.")
	fmt.Fprintf(context.Stdout, "Your repository for %q project is %q\n", appName, out["repository_url"])
	return nil
}

type AppRemove struct {
	tsuru.GuessingCommand
	yes bool
	fs  *gnuflag.FlagSet
}

func (c *AppRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "app-remove",
		Usage: "app-remove [--app appname] [--assume-yes]",
		Desc: `removes an app.

If you don't provide the app name, tsuru will try to guess it.`,
		MinArgs: 0,
	}
}

func (c *AppRemove) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	var answer string
	if !c.yes {
		fmt.Fprintf(context.Stdout, `Are you sure you want to remove app "%s"? (y/n) `, appName)
		fmt.Fscanf(context.Stdin, "%s", &answer)
		if answer != "y" {
			fmt.Fprintln(context.Stdout, "Abort.")
			return nil
		}
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s", appName))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintf(context.Stdout, `App "%s" successfully removed!`+"\n", appName)
	return nil
}

func (c *AppRemove) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = c.GuessingCommand.Flags()
		c.fs.BoolVar(&c.yes, "assume-yes", false, "Don't ask for confirmation, just remove the app.")
		c.fs.BoolVar(&c.yes, "y", false, "Don't ask for confirmation, just remove the app.")
	}
	return c.fs
}

type UnitAdd struct {
	tsuru.GuessingCommand
}

func (c *UnitAdd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit-add",
		Usage:   "unit-add <# of units> [--app appname]",
		Desc:    "add new units to an app.",
		MinArgs: 1,
	}
}

func (c *UnitAdd) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("PUT", url, bytes.NewBufferString(context.Args[0]))
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Units successfully added!")
	return nil
}

type UnitRemove struct {
	tsuru.GuessingCommand
}

func (c *UnitRemove) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "unit-remove",
		Usage:   "unit-remove <# of units> [--app appname]",
		Desc:    "remove units from an app.",
		MinArgs: 1,
	}
}

func (c *UnitRemove) Run(context *cmd.Context, client *cmd.Client) error {
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	url, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
	if err != nil {
		return err
	}
	body := bytes.NewBufferString(context.Args[0])
	request, err := http.NewRequest("DELETE", url, body)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	if err != nil {
		return err
	}
	fmt.Fprintln(context.Stdout, "Units successfully removed!")
	return nil
}
<|endoftext|>


<commit_before>package web

import (
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
)

type appHandler struct {
	settings      *appSettings
	routerRuleReg *regexp.Regexp
	patternMap    map[string]RequestHandler
}

func newAppHandler(settings *appSettings) *appHandler {
	return &appHandler{
		settings:      settings,
		routerRuleReg: regexp.MustCompile("/:.+"),
		patternMap:    make(map[string]RequestHandler),
	}
}

func (handler *appHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	url := req.URL.String()
	reqHandler, exist := handler.patternMap[url]
	if exist {
		reqHandler.HandleRequest(
			&Request{
				req, nil,
			},
			&Response{
				res,
				handler.settings,
			},
		)
	} else {
		served := false
		// check the situation /xx/:xxx
		for k, v := range handler.patternMap {
			matches := handler.routerRuleReg.FindAllString(k, -1)
			if len(matches) != 1 {
				continue
			}
			k = strings.Replace(k, matches[0], "", -1)
			if url != k && strings.HasPrefix(url, k) {
				paramKey := strings.Replace(matches[0], "/:", "", -1)
				paramValue := ""
				for i := len(url) - 1; i >= 0; i-- {
					if url[i] == '/' {
						break
					}
					paramValue = string(url[i]) + paramValue
				}
				params, _ := NewKeyValues(paramKey, paramValue)
				v.HandleRequest(
					&Request{
						req, params,
					},
					&Response{
						res,
						handler.settings,
					},
				)
				served = true
				break
			}
		}
		if !served {
			log.Printf("unrecognized url: %s\n", url)
		}
	}
}

func (handler *appHandler) addPatternHandler(pattern string, reqHandler RequestHandler) error {
	pattern = strings.Replace(pattern, " ", "", -1)
	_, exist := handler.patternMap[pattern]
	if exist {
		return fmt.Errorf("the pattern is exist: %s", pattern)
	}
	handler.patternMap[pattern] = reqHandler
	return nil
}
<commit_msg>fix the bug when handing router rule.<commit_after>package web

import (
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
)

type appHandler struct {
	settings      *appSettings
	routerRuleReg *regexp.Regexp
	patternMap    map[string]RequestHandler
}

func newAppHandler(settings *appSettings) *appHandler {
	return &appHandler{
		settings:      settings,
		routerRuleReg: regexp.MustCompile("/:.+"),
		patternMap:    make(map[string]RequestHandler),
	}
}

func (handler *appHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	url := req.URL.String()
	reqHandler, exist := handler.patternMap[url]
	if exist {
		reqHandler.HandleRequest(
			&Request{
				req, nil,
			},
			&Response{
				res,
				handler.settings,
			},
		)
	} else {
		served := false
		// check the situation /xx/:xxx
		for k, v := range handler.patternMap {
			matches := handler.routerRuleReg.FindAllString(k, -1)
			if len(matches) != 1 {
				continue
			}
			urlSplits := strings.Split(url, "/")
			urlSplitsLen := len(urlSplits)
			if urlSplitsLen < 2 {
				continue
			}
			fixedURL := ""
			for i := 0; i < urlSplitsLen - 1; i++ {
				fixedURL += urlSplits[i]
				if i < urlSplitsLen - 2 {
					fixedURL += "/"
				}
			}
			k = strings.Replace(k, matches[0], "", -1)
			if k == fixedURL {
				paramKey := strings.Replace(matches[0], "/:", "", -1)
				paramValue := urlSplits[len(urlSplits) - 1]
				params, _ := NewKeyValues(paramKey, paramValue)
				v.HandleRequest(
					&Request{
						req, params,
					},
					&Response{
						res,
						handler.settings,
					},
				)
				served = true
				break
			}
		}
		if !served {
			log.Printf("unrecognized url: %s\n", url)
		}
	}
}

func (handler *appHandler) addPatternHandler(pattern string, reqHandler RequestHandler) error {
	pattern = strings.Replace(pattern, " ", "", -1)
	_, exist := handler.patternMap[pattern]
	if exist {
		return fmt.Errorf("the pattern is exist: %s", pattern)
	}
	handler.patternMap[pattern] = reqHandler
	return nil
}
<|endoftext|>


<commit_before>package dbsampler

import (
	"fmt"
	"github.com/howeyc/gopass"
	"gopkg.in/alecthomas/kingpin.v2"
	"strings"
	"os"
	"os/user"
)

const (
	DriverMySQL = "mysql"
)

// ConnectionArgs...
type ConnectionArgs struct {
	Driver   string
	Name     string
	Host     string
	Port     string
	User     string
	Pass     string
	Protocol string
}

func (c *ConnectionArgs) dsn() string {
	return fmt.Sprintf(
		"%s:%s@%s(%s:%s)/%s",
		c.User,
		c.Pass,
		c.Protocol,
		c.Host,
		c.Port,
		c.Name,
	)
}

// DumpArgs...
type DumpArgs struct {
	Limit              int
	Routines           bool
	Triggers           bool
	RenameDatabase     string
	SkipCreateDatabase bool
	SkipLockTables     bool
	SkipAddDropTable   bool
	ExtendedInsert     bool
	Dependencies       map[string][]*Dependency
}

// ParseFlags parses the command line flags.
func ParseFlags() (*ConnectionArgs, *DumpArgs, error) {
	conn := &ConnectionArgs{
		Driver: DriverMySQL,
	}
	args := &DumpArgs{
		Dependencies: map[string][]*Dependency{},
	}

	for i, a := range os.Args {
		if a == "-p" || a == "--password" {
			os.Args[i] = "--password=\000"
		}
	}

	kingpin.Version(Version)
	kingpin.Flag("host", "The database host.").Default("127.0.0.1").Short('h').StringVar(&conn.Host)
	kingpin.Flag("port", "The database port.").Default("3306").Short('P').StringVar(&conn.Port)
	kingpin.Flag("protocol", "The protocol to use for the connection (tcp, socket, pip, memory).").Default("tcp").StringVar(&conn.Protocol)
	kingpin.Flag("user", "User for login if not current user.").Short('u').StringVar(&conn.User)
	kingpin.Flag("password", "Password to use when connecting to server. If password is not given it's asked from stderr.").Short('p').StringVar(&conn.Pass)

	kingpin.Flag("debug", "").Hidden().BoolVar(&IsDebugging)
	kingpin.Flag("routines", "Dump procedures and functions.").BoolVar(&args.Routines)
	kingpin.Flag("triggers", "Dump triggers.").BoolVar(&args.Triggers)
	kingpin.Flag("limit", "Max number of rows from each table to dump.").Default("100").Short('l').IntVar(&args.Limit)
	kingpin.Flag("skip-create-database", "Disable adding CREATE DATABASE statement.").BoolVar(&args.SkipCreateDatabase)
	kingpin.Flag("skip-lock-tables", "Disable locking tables on read.").BoolVar(&args.SkipLockTables)
	kingpin.Flag("skip-add-drop-table", "Disable adding DROP TABLE statements.").BoolVar(&args.SkipAddDropTable)
	kingpin.Flag("extended-insert", "Use multiple-row INSERT syntax that include several VALUES lists.").BoolVar(&args.ExtendedInsert)
	kingpin.Flag("rename-database", "Use this database name in the dump.").PlaceHolder("DUMP-NAME").StringVar(&args.RenameDatabase)
	fks := kingpin.Flag("foreign-key", "Assigns one or more mock foreign keys.").Short('f').Strings()
	kingpin.Arg("database", "Name of the database to dump.").Required().StringVar(&conn.Name)
	kingpin.Parse()

	if conn.User == "" {
		u, err := user.Current()
		if err != nil {
			return nil, nil, err
		}
		conn.User = u.Username
	}
	if conn.Pass == "\000" {
		pass, _ := gopass.GetPasswdPrompt("Enter password: ", false, os.Stdin, os.Stderr)
		conn.Pass = string(pass)
	} else {
		warning("Warning: Using a password on the command line interface can be insecure.")
	}

	for _, fk := range *fks {
		halves := strings.Split(fk, " ")
		if len(halves) != 2 {
			return nil, nil, fmt.Errorf("Invalid foreign key specification %s", fk)
		}
		parts := strings.Split(halves[0], ".")
		if len(parts) != 2 {
			return nil, nil, fmt.Errorf("Invalid foreign key specification %s", fk)
		}
		table := parts[0]
		refCol := parts[1]
		parts = strings.Split(halves[1], ".")
		if len(parts) != 2 {
			return nil, nil, fmt.Errorf("Invalid foreign key specification %s", fk)
		}
		tblName := parts[0]
		colName := parts[1]

		if _, ok := args.Dependencies[table]; !ok {
			args.Dependencies[table] = []*Dependency{}
		}
		args.Dependencies[table] = append(args.Dependencies[table], &Dependency{
			TableName: tblName,
			ColumnName: colName,
			ReferencedColumnName: refCol,
		})
	}

	return conn, args, nil
}
<commit_msg>Parses --foreign-key with regexp<commit_after>package dbsampler

import (
	"fmt"
	"github.com/howeyc/gopass"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/user"
	"regexp"
)

const (
	DriverMySQL = "mysql"
)

// ConnectionArgs...
type ConnectionArgs struct {
	Driver   string
	Name     string
	Host     string
	Port     string
	User     string
	Pass     string
	Protocol string
}

func (c *ConnectionArgs) dsn() string {
	return fmt.Sprintf(
		"%s:%s@%s(%s:%s)/%s",
		c.User,
		c.Pass,
		c.Protocol,
		c.Host,
		c.Port,
		c.Name,
	)
}

// DumpArgs...
type DumpArgs struct {
	Limit              int
	Routines           bool
	Triggers           bool
	RenameDatabase     string
	SkipCreateDatabase bool
	SkipLockTables     bool
	SkipAddDropTable   bool
	ExtendedInsert     bool
	Dependencies       map[string][]*Dependency
}

// ParseFlags parses the command line flags.
func ParseFlags() (*ConnectionArgs, *DumpArgs, error) {
	conn := &ConnectionArgs{
		Driver: DriverMySQL,
	}
	args := &DumpArgs{
		Dependencies: map[string][]*Dependency{},
	}

	for i, a := range os.Args {
		if a == "-p" || a == "--password" {
			os.Args[i] = "--password=\000"
		}
	}

	kingpin.Version(Version)
	kingpin.Flag("host", "The database host.").Default("127.0.0.1").Short('h').StringVar(&conn.Host)
	kingpin.Flag("port", "The database port.").Default("3306").Short('P').StringVar(&conn.Port)
	kingpin.Flag("protocol", "The protocol to use for the connection (tcp, socket, pip, memory).").Default("tcp").StringVar(&conn.Protocol)
	kingpin.Flag("user", "User for login if not current user.").Short('u').StringVar(&conn.User)
	kingpin.Flag("password", "Password to use when connecting to server. If password is not given it's asked from stderr.").Short('p').StringVar(&conn.Pass)

	kingpin.Flag("debug", "").Hidden().BoolVar(&IsDebugging)
	kingpin.Flag("routines", "Dump procedures and functions.").BoolVar(&args.Routines)
	kingpin.Flag("triggers", "Dump triggers.").BoolVar(&args.Triggers)
	kingpin.Flag("limit", "Max number of rows from each table to dump.").Default("100").Short('l').IntVar(&args.Limit)
	kingpin.Flag("skip-create-database", "Disable adding CREATE DATABASE statement.").BoolVar(&args.SkipCreateDatabase)
	kingpin.Flag("skip-lock-tables", "Disable locking tables on read.").BoolVar(&args.SkipLockTables)
	kingpin.Flag("skip-add-drop-table", "Disable adding DROP TABLE statements.").BoolVar(&args.SkipAddDropTable)
	kingpin.Flag("extended-insert", "Use multiple-row INSERT syntax that include several VALUES lists.").BoolVar(&args.ExtendedInsert)
	kingpin.Flag("rename-database", "Use this database name in the dump.").PlaceHolder("DUMP-NAME").StringVar(&args.RenameDatabase)
	fks := kingpin.Flag("foreign-key", "Assigns one or more mock foreign keys.").Short('f').Strings()
	kingpin.Arg("database", "Name of the database to dump.").Required().StringVar(&conn.Name)
	kingpin.Parse()

	if conn.User == "" {
		u, err := user.Current()
		if err != nil {
			return nil, nil, err
		}
		conn.User = u.Username
	}
	if conn.Pass == "\000" {
		pass, _ := gopass.GetPasswdPrompt("Enter password: ", false, os.Stdin, os.Stderr)
		conn.Pass = string(pass)
	} else {
		warning("Warning: Using a password on the command line interface can be insecure.")
	}

	r := regexp.MustCompile(`([\w]+)\.([\w]+)\s+([\w]+)\.([\w]+)`)
	for _, fk := range *fks {
		m := r.FindStringSubmatch(fk)
		if len(m) != 5 {
			return nil, nil, fmt.Errorf(`Invalid foreign key "%s". Must be "table.column references.column"`, fk)
		}
		if _, ok := args.Dependencies[m[1]]; !ok {
			args.Dependencies[m[1]] = []*Dependency{}
		}
		args.Dependencies[m[1]] = append(args.Dependencies[m[1]], &Dependency{
			TableName: m[3],
			ColumnName: m[4],
			ReferencedColumnName: m[2],
		})
	}

	return conn, args, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

// ErrCannotParseDockercfg is the error returned by NewAuthConfigurations when the dockercfg cannot be parsed.
var ErrCannotParseDockercfg = errors.New("Failed to read authentication from dockercfg")

// AuthConfiguration represents authentication options to use in the PushImage
// method. It represents the authentication in the Docker index server.
type AuthConfiguration struct {
	Username      string `json:"username,omitempty"`
	Password      string `json:"password,omitempty"`
	Email         string `json:"email,omitempty"`
	ServerAddress string `json:"serveraddress,omitempty"`

	// IdentityToken can be supplied with the identitytoken response of the AuthCheck call
	// see https://godoc.org/github.com/docker/docker/api/types#AuthConfig
	// It can be used in place of password not in conjunction with it
	IdentityToken string `json:"identitytoken,omitempty"`
}

// AuthConfigurations represents authentication options to use for the
// PushImage method accommodating the new X-Registry-Config header
type AuthConfigurations struct {
	Configs map[string]AuthConfiguration `json:"configs"`
}

// AuthConfigurations119 is used to serialize a set of AuthConfigurations
// for Docker API >= 1.19.
type AuthConfigurations119 map[string]AuthConfiguration

// dockerConfig represents a registry authentation configuration from the
// .dockercfg file.
type dockerConfig struct {
	Auth          string `json:"auth"`
	Email         string `json:"email"`
	IdentityToken string `json:"identitytoken"`
}

// NewAuthConfigurationsFromFile returns AuthConfigurations from a path containing JSON
// in the same format as the .dockercfg file.
func NewAuthConfigurationsFromFile(path string) (*AuthConfigurations, error) {
	r, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	return NewAuthConfigurations(r)
}

func cfgPaths(dockerConfigEnv string, homeEnv string) []string {
	var paths []string
	if dockerConfigEnv != "" {
		paths = append(paths, path.Join(dockerConfigEnv, "config.json"))
	}
	if homeEnv != "" {
		paths = append(paths, path.Join(homeEnv, ".docker", "config.json"))
		paths = append(paths, path.Join(homeEnv, ".dockercfg"))
	}
	return paths
}

// NewAuthConfigurationsFromDockerCfg returns AuthConfigurations from
// system config files. The following files are checked in the order listed:
// - $DOCKER_CONFIG/config.json if DOCKER_CONFIG set in the environment,
// - $HOME/.docker/config.json
// - $HOME/.dockercfg
func NewAuthConfigurationsFromDockerCfg() (*AuthConfigurations, error) {
	err := fmt.Errorf("No docker configuration found")
	var auths *AuthConfigurations

	pathsToTry := cfgPaths(os.Getenv("DOCKER_CONFIG"), os.Getenv("HOME"))
	for _, path := range pathsToTry {
		auths, err = NewAuthConfigurationsFromFile(path)
		if err == nil {
			return auths, nil
		}
	}
	return auths, err
}

// NewAuthConfigurations returns AuthConfigurations from a JSON encoded string in the
// same format as the .dockercfg file.
func NewAuthConfigurations(r io.Reader) (*AuthConfigurations, error) {
	var auth *AuthConfigurations
	confs, err := parseDockerConfig(r)
	if err != nil {
		return nil, err
	}
	auth, err = authConfigs(confs)
	if err != nil {
		return nil, err
	}
	return auth, nil
}

func parseDockerConfig(r io.Reader) (map[string]dockerConfig, error) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r)
	byteData := buf.Bytes()

	confsWrapper := struct {
		Auths map[string]dockerConfig `json:"auths"`
	}{}
	if err := json.Unmarshal(byteData, &confsWrapper); err == nil {
		if len(confsWrapper.Auths) > 0 {
			return confsWrapper.Auths, nil
		}
	}

	var confs map[string]dockerConfig
	if err := json.Unmarshal(byteData, &confs); err != nil {
		return nil, err
	}
	return confs, nil
}

// authConfigs converts a dockerConfigs map to a AuthConfigurations object.
func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) {
	c := &AuthConfigurations{
		Configs: make(map[string]AuthConfiguration),
	}

	for reg, conf := range confs {
		if conf.Auth == "" {
			continue
		}
		data, err := base64.StdEncoding.DecodeString(conf.Auth)
		if err != nil {
			return nil, err
		}

		userpass := strings.SplitN(string(data), ":", 2)
		if len(userpass) != 2 {
			if conf.IdentityToken == "" {
				return nil, ErrCannotParseDockercfg
			}

			// docker config contains username and identitytoken
			c.Configs[reg] = AuthConfiguration{
				Username:      string(data),
				IdentityToken: conf.IdentityToken,
			}

			continue
		}

		c.Configs[reg] = AuthConfiguration{
			Email:         conf.Email,
			Username:      userpass[0],
			Password:      userpass[1],
			ServerAddress: reg,
		}
	}

	return c, nil
}

// AuthStatus returns the authentication status for Docker API versions >= 1.23.
type AuthStatus struct {
	Status        string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"`
	IdentityToken string `json:"IdentityToken,omitempty" yaml:"IdentityToken,omitempty" toml:"IdentityToken,omitempty"`
}

// AuthCheck validates the given credentials. It returns nil if successful.
//
// For Docker API versions >= 1.23, the AuthStatus struct will be populated, otherwise it will be empty.`
//
// See https://goo.gl/6nsZkH for more details.
func (c *Client) AuthCheck(conf *AuthConfiguration) (AuthStatus, error) {
	var authStatus AuthStatus
	if conf == nil {
		return authStatus, errors.New("conf is nil")
	}
	resp, err := c.do("POST", "/auth", doOptions{data: conf})
	if err != nil {
		return authStatus, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return authStatus, err
	}
	if len(data) == 0 {
		return authStatus, nil
	}
	if err := json.Unmarshal(data, &authStatus); err != nil {
		return authStatus, err
	}
	return authStatus, nil
}
<commit_msg>Expect auth field to contain colon in all cases<commit_after>// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

// ErrCannotParseDockercfg is the error returned by NewAuthConfigurations when the dockercfg cannot be parsed.
var ErrCannotParseDockercfg = errors.New("Failed to read authentication from dockercfg")

// AuthConfiguration represents authentication options to use in the PushImage
// method. It represents the authentication in the Docker index server.
type AuthConfiguration struct {
	Username      string `json:"username,omitempty"`
	Password      string `json:"password,omitempty"`
	Email         string `json:"email,omitempty"`
	ServerAddress string `json:"serveraddress,omitempty"`

	// IdentityToken can be supplied with the identitytoken response of the AuthCheck call
	// see https://godoc.org/github.com/docker/docker/api/types#AuthConfig
	// It can be used in place of password not in conjunction with it
	IdentityToken string `json:"identitytoken,omitempty"`
}

// AuthConfigurations represents authentication options to use for the
// PushImage method accommodating the new X-Registry-Config header
type AuthConfigurations struct {
	Configs map[string]AuthConfiguration `json:"configs"`
}

// AuthConfigurations119 is used to serialize a set of AuthConfigurations
// for Docker API >= 1.19.
type AuthConfigurations119 map[string]AuthConfiguration

// dockerConfig represents a registry authentation configuration from the
// .dockercfg file.
type dockerConfig struct {
	Auth          string `json:"auth"`
	Email         string `json:"email"`
	IdentityToken string `json:"identitytoken"`
}

// NewAuthConfigurationsFromFile returns AuthConfigurations from a path containing JSON
// in the same format as the .dockercfg file.
func NewAuthConfigurationsFromFile(path string) (*AuthConfigurations, error) {
	r, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	return NewAuthConfigurations(r)
}

func cfgPaths(dockerConfigEnv string, homeEnv string) []string {
	var paths []string
	if dockerConfigEnv != "" {
		paths = append(paths, path.Join(dockerConfigEnv, "config.json"))
	}
	if homeEnv != "" {
		paths = append(paths, path.Join(homeEnv, ".docker", "config.json"))
		paths = append(paths, path.Join(homeEnv, ".dockercfg"))
	}
	return paths
}

// NewAuthConfigurationsFromDockerCfg returns AuthConfigurations from
// system config files. The following files are checked in the order listed:
// - $DOCKER_CONFIG/config.json if DOCKER_CONFIG set in the environment,
// - $HOME/.docker/config.json
// - $HOME/.dockercfg
func NewAuthConfigurationsFromDockerCfg() (*AuthConfigurations, error) {
	err := fmt.Errorf("No docker configuration found")
	var auths *AuthConfigurations

	pathsToTry := cfgPaths(os.Getenv("DOCKER_CONFIG"), os.Getenv("HOME"))
	for _, path := range pathsToTry {
		auths, err = NewAuthConfigurationsFromFile(path)
		if err == nil {
			return auths, nil
		}
	}
	return auths, err
}

// NewAuthConfigurations returns AuthConfigurations from a JSON encoded string in the
// same format as the .dockercfg file.
func NewAuthConfigurations(r io.Reader) (*AuthConfigurations, error) {
	var auth *AuthConfigurations
	confs, err := parseDockerConfig(r)
	if err != nil {
		return nil, err
	}
	auth, err = authConfigs(confs)
	if err != nil {
		return nil, err
	}
	return auth, nil
}

func parseDockerConfig(r io.Reader) (map[string]dockerConfig, error) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r)
	byteData := buf.Bytes()

	confsWrapper := struct {
		Auths map[string]dockerConfig `json:"auths"`
	}{}
	if err := json.Unmarshal(byteData, &confsWrapper); err == nil {
		if len(confsWrapper.Auths) > 0 {
			return confsWrapper.Auths, nil
		}
	}

	var confs map[string]dockerConfig
	if err := json.Unmarshal(byteData, &confs); err != nil {
		return nil, err
	}
	return confs, nil
}

// authConfigs converts a dockerConfigs map to a AuthConfigurations object.
func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) {
	c := &AuthConfigurations{
		Configs: make(map[string]AuthConfiguration),
	}

	for reg, conf := range confs {
		if conf.Auth == "" {
			continue
		}
		data, err := base64.StdEncoding.DecodeString(conf.Auth)
		if err != nil {
			return nil, err
		}

		userpass := strings.SplitN(string(data), ":", 2)
		if len(userpass) != 2 {
			return nil, ErrCannotParseDockercfg
		}

		authConfig := AuthConfiguration{
			Email:         conf.Email,
			Username:      userpass[0],
			Password:      userpass[1],
			ServerAddress: reg,
		}

		// if identitytoken provided then zero the password and set it
		if conf.IdentityToken != "" {
			authConfig.Password = ""
			authConfig.IdentityToken = conf.IdentityToken
		}

		c.Configs[reg] = authConfig
	}

	return c, nil
}

// AuthStatus returns the authentication status for Docker API versions >= 1.23.
type AuthStatus struct {
	Status        string `json:"Status,omitempty" yaml:"Status,omitempty" toml:"Status,omitempty"`
	IdentityToken string `json:"IdentityToken,omitempty" yaml:"IdentityToken,omitempty" toml:"IdentityToken,omitempty"`
}

// AuthCheck validates the given credentials. It returns nil if successful.
//
// For Docker API versions >= 1.23, the AuthStatus struct will be populated, otherwise it will be empty.`
//
// See https://goo.gl/6nsZkH for more details.
func (c *Client) AuthCheck(conf *AuthConfiguration) (AuthStatus, error) {
	var authStatus AuthStatus
	if conf == nil {
		return authStatus, errors.New("conf is nil")
	}
	resp, err := c.do("POST", "/auth", doOptions{data: conf})
	if err != nil {
		return authStatus, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return authStatus, err
	}
	if len(data) == 0 {
		return authStatus, nil
	}
	if err := json.Unmarshal(data, &authStatus); err != nil {
		return authStatus, err
	}
	return authStatus, nil
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */package restapi

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/clientv3/concurrency"
	"github.com/creativesoftwarefdn/weaviate/auth/authentication/oidc"
	weaviateBroker "github.com/creativesoftwarefdn/weaviate/broker"
	"github.com/creativesoftwarefdn/weaviate/config"
	libcontextionary "github.com/creativesoftwarefdn/weaviate/contextionary"
	"github.com/creativesoftwarefdn/weaviate/database"
	dblisting "github.com/creativesoftwarefdn/weaviate/database/listing"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	databaseSchema "github.com/creativesoftwarefdn/weaviate/database/schema_contextionary"
	schemaContextionary "github.com/creativesoftwarefdn/weaviate/database/schema_contextionary"
	etcdSchemaManager "github.com/creativesoftwarefdn/weaviate/database/schema_manager/etcd"
	"github.com/creativesoftwarefdn/weaviate/graphqlapi"
	"github.com/creativesoftwarefdn/weaviate/graphqlapi/local/fetch"
	graphqlnetwork "github.com/creativesoftwarefdn/weaviate/graphqlapi/network"
	"github.com/creativesoftwarefdn/weaviate/messages"
	libnetwork "github.com/creativesoftwarefdn/weaviate/network"
	"github.com/creativesoftwarefdn/weaviate/network/common/peers"
	libnetworkFake "github.com/creativesoftwarefdn/weaviate/network/fake"
	libnetworkP2P "github.com/creativesoftwarefdn/weaviate/network/p2p"
	"github.com/creativesoftwarefdn/weaviate/restapi/state"
	"github.com/creativesoftwarefdn/weaviate/telemetry"
	"github.com/go-openapi/strfmt"
)

// As soon as server is initialized but not run yet, this function will be called.
// If you need to modify a config, store server instance to stop it individually later, this is the place.
// This function can be called multiple times, depending on the number of serving schemes.
// scheme value will be set accordingly: "http", "https" or "unix"
func configureServer(s *http.Server, scheme, addr string) {
	// context for the startup procedure. (So far the only subcommand respecting
	// the context is the schema initialization, as this uses the etcd client
	// requiring context. Nevertheless it would make sense to have everything
	// that goes on in here pay attention to the context, so we can have a
	// "startup in x seconds or fail")
	ctx := context.Background()
	// The timeout is arbitrary we have to adjust it as we go along, if we
	// realize it is to big/small
	ctx, cancel := context.WithTimeout(ctx, 120*time.Second)
	defer cancel()

	// Create message service
	messaging = &messages.Messaging{}
	appState.Messaging = messaging

	messaging.InfoMessage(fmt.Sprintf("created the context, nothing done yet, time left is: %s", timeTillDeadline(ctx)))

	// Load the config using the flags
	serverConfig = &config.WeaviateConfig{}
	appState.ServerConfig = serverConfig
	err := serverConfig.LoadConfig(connectorOptionGroup, messaging)
	messaging.InfoMessage(fmt.Sprintf("loaded the config, time left is: %s", timeTillDeadline(ctx)))

	appState.OIDC = configureOIDC(appState)
	messaging.InfoMessage(fmt.Sprintf("configured OIDC client, time left is: %s", timeTillDeadline(ctx)))

	// Extract environment variables needed for logging
	loggingInterval := appState.ServerConfig.Environment.Logging.Interval
	loggingUrl := appState.ServerConfig.Environment.Logging.Url
	loggingEnabled := appState.ServerConfig.Environment.Logging.Enabled
	loggingDebug := appState.ServerConfig.Environment.Debug

	if loggingEnabled != true && loggingEnabled != false {
		loggingEnabled = true
	}

	// Propagate the peer name (if any), debug toggle and the enabled toggle to the requestsLog
	mainLog.PeerName = appState.ServerConfig.Environment.Network.PeerName
	mainLog.Debug = loggingDebug
	mainLog.Enabled = loggingEnabled

	// Add properties to the config
	serverConfig.Hostname = addr
	serverConfig.Scheme = scheme

	// Fatal error loading config file
	if err != nil {
		messaging.ExitError(78, err.Error())
	}

	loadContextionary()
	messaging.InfoMessage(fmt.Sprintf("loaded the contextionary, time left is: %s", timeTillDeadline(ctx)))

	connectToNetwork()
	messaging.InfoMessage(fmt.Sprintf("connected to network, time left is: %s", timeTillDeadline(ctx)))

	// Connect to MQTT via Broker
	weaviateBroker.ConnectToMqtt(serverConfig.Environment.Broker.Host, serverConfig.Environment.Broker.Port)
	messaging.InfoMessage(fmt.Sprintf("connected to broker, time left is: %s", timeTillDeadline(ctx)))

	// Create the database connector using the config
	err, dbConnector := dblisting.NewConnector(serverConfig.Environment.Database.Name, serverConfig.Environment.Database.DatabaseConfig, serverConfig.Environment)
	// Could not find, or configure connector.
	if err != nil {
		messaging.ExitError(78, err.Error())
	}

	messaging.InfoMessage(fmt.Sprintf("created db connector, time left is: %s", timeTillDeadline(ctx)))

	// parse config store URL
	configURL := serverConfig.Environment.ConfigurationStorage.URL
	configStore, err := url.Parse(configURL)
	if err != nil || configURL == "" {
		messaging.ExitError(78, fmt.Sprintf("cannot parse config store URL: %s", err))
	}

	// Construct a distributed lock
	etcdClient, err := clientv3.New(clientv3.Config{Endpoints: []string{configStore.String()}})
	if err != nil {
		log.Fatal(err)
	}

	messaging.InfoMessage(fmt.Sprintf("created an etcd client, time left is: %s", timeTillDeadline(ctx)))

	s1, err := concurrency.NewSession(etcdClient)
	if err != nil {
		log.Fatal(err)
	}
	messaging.InfoMessage(fmt.Sprintf("created an etcd session, time left is: %s", timeTillDeadline(ctx)))

	manager, err := etcdSchemaManager.New(ctx, etcdClient, dbConnector, network)
	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not initialize local database state: %v", err))
	}

	messaging.InfoMessage(fmt.Sprintf("initialized the schema, time left is: %s", timeTillDeadline(ctx)))

	manager.RegisterSchemaUpdateCallback(updateSchemaCallback)

	// Initialize the reporter
	reporter = telemetry.NewReporter(ctx, mainLog, loggingInterval, loggingUrl, loggingEnabled, loggingDebug, etcdClient, messaging)

	// Start reporting
	go func() {
		reporter.Start()
	}()

	// initialize the contextinoary with the rawContextionary, it will get updated on each schema update
	contextionary = rawContextionary

	// Now instantiate a database, with the configured lock, manager and connector.
	dbParams := &database.Params{
		LockerKey:     "/weaviate/schema-connector-rw-lock",
		LockerSession: s1,
		SchemaManager: manager,
		Connector:     dbConnector,
		Contextionary: contextionary,
		Messaging:     messaging,
	}
	db, err = database.New(ctx, dbParams)
	if err != nil {
		messaging.ExitError(1, fmt.Sprintf("Could not initialize the database: %s", err.Error()))
	}
	appState.Database = db

	manager.TriggerSchemaUpdateCallbacks()
	network.RegisterUpdatePeerCallback(func(peers peers.Peers) {
		manager.TriggerSchemaUpdateCallbacks()
	})

	network.RegisterSchemaGetter(&schemaGetter{db: db})
}

func updateSchemaCallback(updatedSchema schema.Schema) {
	// Note that this is thread safe; we're running in a single go-routine, because the event
	// handlers are called when the SchemaLock is still held.
	rebuildContextionary(updatedSchema)
	rebuildGraphQL(updatedSchema)
}

func rebuildContextionary(updatedSchema schema.Schema) {
	// build new contextionary extended by the local schema
	schemaContextionary, err := databaseSchema.BuildInMemoryContextionaryFromSchema(updatedSchema, &rawContextionary)
	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not build in-memory contextionary from schema; %+v", err))
	}

	// Combine contextionaries
	contextionaries := []libcontextionary.Contextionary{rawContextionary, *schemaContextionary}
	combined, err := libcontextionary.CombineVectorIndices(contextionaries)

	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not combine the contextionary database with the in-memory generated contextionary; %+v", err))
	}

	messaging.InfoMessage("Contextionary extended with names in the schema")

	contextionary = libcontextionary.Contextionary(combined)
}

func rebuildGraphQL(updatedSchema schema.Schema) {
	peers, err := network.ListPeers()
	if err != nil {
		graphQL = nil
		messaging.ErrorMessage(fmt.Sprintf("could not list network peers to regenerate schema:\n%#v\n", err))
		return
	}

	c11y := schemaContextionary.New(contextionary)
	root := graphQLRoot{Database: db, Network: network, contextionary: c11y, log: mainLog}
	updatedGraphQL, err := graphqlapi.Build(&updatedSchema, peers, root, messaging, serverConfig.Environment)
	if err != nil {
		// TODO: turn on safe mode gh-520
		graphQL = nil
		messaging.ErrorMessage(fmt.Sprintf("Could not re-generate GraphQL schema, because:\n%#v\n", err))
	} else {
		messaging.InfoMessage("Updated GraphQL schema")
		graphQL = updatedGraphQL
	}
}

type schemaGetter struct {
	db database.Database
}

func (s *schemaGetter) Schema() (schema.Schema, error) {
	dbLock, err := s.db.ConnectorLock()
	if err != nil {
		return schema.Schema{}, err
	}

	defer dbLock.Unlock()
	return dbLock.GetSchema(), nil
}

type graphQLRoot struct {
	database.Database
	libnetwork.Network
	contextionary *schemaContextionary.Contextionary
	log           *telemetry.RequestsLog
}

func (r graphQLRoot) GetNetworkResolver() graphqlnetwork.Resolver {
	return r.Network
}

func (r graphQLRoot) GetContextionary() fetch.Contextionary {
	return r.contextionary
}

func (r graphQLRoot) GetRequestsLog() fetch.RequestsLog {
	return r.log
}

// configureOIDC will always be called, even if OIDC is disabled, this way the
// middleware will still be able to provide the user with a valuable error
// message, even when OIDC is globally disabled.
func configureOIDC(appState *state.State) *oidc.Client {
	c, err := oidc.New(appState.ServerConfig.Environment)
	if err != nil {
		appState.Messaging.ExitError(1, fmt.Sprintf("oidc client couldn't start up: %v", err))
	}

	return c
}

func timeTillDeadline(ctx context.Context) time.Duration {
	dl, _ := ctx.Deadline()
	return time.Until(dl)
}

// This function loads the Contextionary database, and creates
// an in-memory database for the centroids of the classes / properties in the Schema.
func loadContextionary() {
	// First load the file backed contextionary
	if serverConfig.Environment.Contextionary.KNNFile == "" {
		messaging.ExitError(78, "Contextionary KNN file not specified")
	}

	if serverConfig.Environment.Contextionary.IDXFile == "" {
		messaging.ExitError(78, "Contextionary IDX file not specified")
	}

	mmapedContextionary, err := libcontextionary.LoadVectorFromDisk(serverConfig.Environment.Contextionary.KNNFile, serverConfig.Environment.Contextionary.IDXFile)

	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not load Contextionary; %+v", err))
	}

	messaging.InfoMessage("Contextionary loaded from disk")

	rawContextionary = mmapedContextionary
}

func connectToNetwork() {
	if serverConfig.Environment.Network == nil {
		messaging.InfoMessage(fmt.Sprintf("No network configured, not joining one"))
		network = libnetworkFake.FakeNetwork{}
		appState.Network = network
	} else {
		genesis_url := strfmt.URI(serverConfig.Environment.Network.GenesisURL)
		public_url := strfmt.URI(serverConfig.Environment.Network.PublicURL)
		peer_name := serverConfig.Environment.Network.PeerName

		messaging.InfoMessage(fmt.Sprintf("Network configured, connecting to Genesis '%v'", genesis_url))
		new_net, err := libnetworkP2P.BootstrapNetwork(messaging, genesis_url, public_url, peer_name)
		if err != nil {
			messaging.ExitError(78, fmt.Sprintf("Could not connect to network! Reason: %+v", err))
		} else {
			network = *new_net
			appState.Network = *new_net
		}
	}
}
<commit_msg>gh-699: added non-expiring context for reporter<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */package restapi

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/clientv3/concurrency"
	"github.com/creativesoftwarefdn/weaviate/auth/authentication/oidc"
	weaviateBroker "github.com/creativesoftwarefdn/weaviate/broker"
	"github.com/creativesoftwarefdn/weaviate/config"
	libcontextionary "github.com/creativesoftwarefdn/weaviate/contextionary"
	"github.com/creativesoftwarefdn/weaviate/database"
	dblisting "github.com/creativesoftwarefdn/weaviate/database/listing"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	databaseSchema "github.com/creativesoftwarefdn/weaviate/database/schema_contextionary"
	schemaContextionary "github.com/creativesoftwarefdn/weaviate/database/schema_contextionary"
	etcdSchemaManager "github.com/creativesoftwarefdn/weaviate/database/schema_manager/etcd"
	"github.com/creativesoftwarefdn/weaviate/graphqlapi"
	"github.com/creativesoftwarefdn/weaviate/graphqlapi/local/fetch"
	graphqlnetwork "github.com/creativesoftwarefdn/weaviate/graphqlapi/network"
	"github.com/creativesoftwarefdn/weaviate/messages"
	libnetwork "github.com/creativesoftwarefdn/weaviate/network"
	"github.com/creativesoftwarefdn/weaviate/network/common/peers"
	libnetworkFake "github.com/creativesoftwarefdn/weaviate/network/fake"
	libnetworkP2P "github.com/creativesoftwarefdn/weaviate/network/p2p"
	"github.com/creativesoftwarefdn/weaviate/restapi/state"
	"github.com/creativesoftwarefdn/weaviate/telemetry"
	"github.com/go-openapi/strfmt"
)

// As soon as server is initialized but not run yet, this function will be called.
// If you need to modify a config, store server instance to stop it individually later, this is the place.
// This function can be called multiple times, depending on the number of serving schemes.
// scheme value will be set accordingly: "http", "https" or "unix"
func configureServer(s *http.Server, scheme, addr string) {
	// context for the startup procedure. (So far the only subcommand respecting
	// the context is the schema initialization, as this uses the etcd client
	// requiring context. Nevertheless it would make sense to have everything
	// that goes on in here pay attention to the context, so we can have a
	// "startup in x seconds or fail")
	ctx := context.Background()
	// The timeout is arbitrary we have to adjust it as we go along, if we
	// realize it is to big/small
	ctx, cancel := context.WithTimeout(ctx, 120*time.Second)
	defer cancel()

	// Create message service
	messaging = &messages.Messaging{}
	appState.Messaging = messaging

	messaging.InfoMessage(fmt.Sprintf("created the context, nothing done yet, time left is: %s", timeTillDeadline(ctx)))

	// Load the config using the flags
	serverConfig = &config.WeaviateConfig{}
	appState.ServerConfig = serverConfig
	err := serverConfig.LoadConfig(connectorOptionGroup, messaging)
	messaging.InfoMessage(fmt.Sprintf("loaded the config, time left is: %s", timeTillDeadline(ctx)))

	appState.OIDC = configureOIDC(appState)
	messaging.InfoMessage(fmt.Sprintf("configured OIDC client, time left is: %s", timeTillDeadline(ctx)))

	// Extract environment variables needed for logging
	loggingInterval := appState.ServerConfig.Environment.Logging.Interval
	loggingUrl := appState.ServerConfig.Environment.Logging.Url
	loggingEnabled := appState.ServerConfig.Environment.Logging.Enabled
	loggingDebug := appState.ServerConfig.Environment.Debug

	if loggingEnabled != true && loggingEnabled != false {
		loggingEnabled = true
	}

	// Propagate the peer name (if any), debug toggle and the enabled toggle to the requestsLog
	mainLog.PeerName = appState.ServerConfig.Environment.Network.PeerName
	mainLog.Debug = loggingDebug
	mainLog.Enabled = loggingEnabled

	// Add properties to the config
	serverConfig.Hostname = addr
	serverConfig.Scheme = scheme

	// Fatal error loading config file
	if err != nil {
		messaging.ExitError(78, err.Error())
	}

	loadContextionary()
	messaging.InfoMessage(fmt.Sprintf("loaded the contextionary, time left is: %s", timeTillDeadline(ctx)))

	connectToNetwork()
	messaging.InfoMessage(fmt.Sprintf("connected to network, time left is: %s", timeTillDeadline(ctx)))

	// Connect to MQTT via Broker
	weaviateBroker.ConnectToMqtt(serverConfig.Environment.Broker.Host, serverConfig.Environment.Broker.Port)
	messaging.InfoMessage(fmt.Sprintf("connected to broker, time left is: %s", timeTillDeadline(ctx)))

	// Create the database connector using the config
	err, dbConnector := dblisting.NewConnector(serverConfig.Environment.Database.Name, serverConfig.Environment.Database.DatabaseConfig, serverConfig.Environment)
	// Could not find, or configure connector.
	if err != nil {
		messaging.ExitError(78, err.Error())
	}

	messaging.InfoMessage(fmt.Sprintf("created db connector, time left is: %s", timeTillDeadline(ctx)))

	// parse config store URL
	configURL := serverConfig.Environment.ConfigurationStorage.URL
	configStore, err := url.Parse(configURL)
	if err != nil || configURL == "" {
		messaging.ExitError(78, fmt.Sprintf("cannot parse config store URL: %s", err))
	}

	// Construct a distributed lock
	etcdClient, err := clientv3.New(clientv3.Config{Endpoints: []string{configStore.String()}})
	if err != nil {
		log.Fatal(err)
	}

	messaging.InfoMessage(fmt.Sprintf("created an etcd client, time left is: %s", timeTillDeadline(ctx)))

	s1, err := concurrency.NewSession(etcdClient)
	if err != nil {
		log.Fatal(err)
	}
	messaging.InfoMessage(fmt.Sprintf("created an etcd session, time left is: %s", timeTillDeadline(ctx)))

	manager, err := etcdSchemaManager.New(ctx, etcdClient, dbConnector, network)
	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not initialize local database state: %v", err))
	}

	messaging.InfoMessage(fmt.Sprintf("initialized the schema, time left is: %s", timeTillDeadline(ctx)))

	manager.RegisterSchemaUpdateCallback(updateSchemaCallback)

	// Initialize a non-expiring context for the reporter
	reportingContext := context.Background()
	// Initialize the reporter
	reporter = telemetry.NewReporter(reportingContext, mainLog, loggingInterval, loggingUrl, loggingEnabled, loggingDebug, etcdClient, messaging)

	// Start reporting
	go func() {
		reporter.Start()
	}()

	// initialize the contextinoary with the rawContextionary, it will get updated on each schema update
	contextionary = rawContextionary

	// Now instantiate a database, with the configured lock, manager and connector.
	dbParams := &database.Params{
		LockerKey:     "/weaviate/schema-connector-rw-lock",
		LockerSession: s1,
		SchemaManager: manager,
		Connector:     dbConnector,
		Contextionary: contextionary,
		Messaging:     messaging,
	}
	db, err = database.New(ctx, dbParams)
	if err != nil {
		messaging.ExitError(1, fmt.Sprintf("Could not initialize the database: %s", err.Error()))
	}
	appState.Database = db

	manager.TriggerSchemaUpdateCallbacks()
	network.RegisterUpdatePeerCallback(func(peers peers.Peers) {
		manager.TriggerSchemaUpdateCallbacks()
	})

	network.RegisterSchemaGetter(&schemaGetter{db: db})
}

func updateSchemaCallback(updatedSchema schema.Schema) {
	// Note that this is thread safe; we're running in a single go-routine, because the event
	// handlers are called when the SchemaLock is still held.
	rebuildContextionary(updatedSchema)
	rebuildGraphQL(updatedSchema)
}

func rebuildContextionary(updatedSchema schema.Schema) {
	// build new contextionary extended by the local schema
	schemaContextionary, err := databaseSchema.BuildInMemoryContextionaryFromSchema(updatedSchema, &rawContextionary)
	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not build in-memory contextionary from schema; %+v", err))
	}

	// Combine contextionaries
	contextionaries := []libcontextionary.Contextionary{rawContextionary, *schemaContextionary}
	combined, err := libcontextionary.CombineVectorIndices(contextionaries)

	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not combine the contextionary database with the in-memory generated contextionary; %+v", err))
	}

	messaging.InfoMessage("Contextionary extended with names in the schema")

	contextionary = libcontextionary.Contextionary(combined)
}

func rebuildGraphQL(updatedSchema schema.Schema) {
	peers, err := network.ListPeers()
	if err != nil {
		graphQL = nil
		messaging.ErrorMessage(fmt.Sprintf("could not list network peers to regenerate schema:\n%#v\n", err))
		return
	}

	c11y := schemaContextionary.New(contextionary)
	root := graphQLRoot{Database: db, Network: network, contextionary: c11y, log: mainLog}
	updatedGraphQL, err := graphqlapi.Build(&updatedSchema, peers, root, messaging, serverConfig.Environment)
	if err != nil {
		// TODO: turn on safe mode gh-520
		graphQL = nil
		messaging.ErrorMessage(fmt.Sprintf("Could not re-generate GraphQL schema, because:\n%#v\n", err))
	} else {
		messaging.InfoMessage("Updated GraphQL schema")
		graphQL = updatedGraphQL
	}
}

type schemaGetter struct {
	db database.Database
}

func (s *schemaGetter) Schema() (schema.Schema, error) {
	dbLock, err := s.db.ConnectorLock()
	if err != nil {
		return schema.Schema{}, err
	}

	defer dbLock.Unlock()
	return dbLock.GetSchema(), nil
}

type graphQLRoot struct {
	database.Database
	libnetwork.Network
	contextionary *schemaContextionary.Contextionary
	log           *telemetry.RequestsLog
}

func (r graphQLRoot) GetNetworkResolver() graphqlnetwork.Resolver {
	return r.Network
}

func (r graphQLRoot) GetContextionary() fetch.Contextionary {
	return r.contextionary
}

func (r graphQLRoot) GetRequestsLog() fetch.RequestsLog {
	return r.log
}

// configureOIDC will always be called, even if OIDC is disabled, this way the
// middleware will still be able to provide the user with a valuable error
// message, even when OIDC is globally disabled.
func configureOIDC(appState *state.State) *oidc.Client {
	c, err := oidc.New(appState.ServerConfig.Environment)
	if err != nil {
		appState.Messaging.ExitError(1, fmt.Sprintf("oidc client couldn't start up: %v", err))
	}

	return c
}

func timeTillDeadline(ctx context.Context) time.Duration {
	dl, _ := ctx.Deadline()
	return time.Until(dl)
}

// This function loads the Contextionary database, and creates
// an in-memory database for the centroids of the classes / properties in the Schema.
func loadContextionary() {
	// First load the file backed contextionary
	if serverConfig.Environment.Contextionary.KNNFile == "" {
		messaging.ExitError(78, "Contextionary KNN file not specified")
	}

	if serverConfig.Environment.Contextionary.IDXFile == "" {
		messaging.ExitError(78, "Contextionary IDX file not specified")
	}

	mmapedContextionary, err := libcontextionary.LoadVectorFromDisk(serverConfig.Environment.Contextionary.KNNFile, serverConfig.Environment.Contextionary.IDXFile)

	if err != nil {
		messaging.ExitError(78, fmt.Sprintf("Could not load Contextionary; %+v", err))
	}

	messaging.InfoMessage("Contextionary loaded from disk")

	rawContextionary = mmapedContextionary
}

func connectToNetwork() {
	if serverConfig.Environment.Network == nil {
		messaging.InfoMessage(fmt.Sprintf("No network configured, not joining one"))
		network = libnetworkFake.FakeNetwork{}
		appState.Network = network
	} else {
		genesis_url := strfmt.URI(serverConfig.Environment.Network.GenesisURL)
		public_url := strfmt.URI(serverConfig.Environment.Network.PublicURL)
		peer_name := serverConfig.Environment.Network.PeerName

		messaging.InfoMessage(fmt.Sprintf("Network configured, connecting to Genesis '%v'", genesis_url))
		new_net, err := libnetworkP2P.BootstrapNetwork(messaging, genesis_url, public_url, peer_name)
		if err != nil {
			messaging.ExitError(78, fmt.Sprintf("Could not connect to network! Reason: %+v", err))
		} else {
			network = *new_net
			appState.Network = *new_net
		}
	}
}
<|endoftext|>


<commit_before>package xmpp // import "fluux.io/xmpp"

import (
	"encoding/base64"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
)

func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f streamFeatures, user string, password string) (err error) {
	// TODO: Implement other type of SASL Authentication
	havePlain := false
	for _, m := range f.Mechanisms.Mechanism {
		if m == "PLAIN" {
			havePlain = true
			break
		}
	}
	if !havePlain {
		return fmt.Errorf("PLAIN authentication is not supported by server: %v", f.Mechanisms.Mechanism)
	}

	return authPlain(socket, decoder, user, password)
}

// Plain authentication: send base64-encoded \x00 user \x00 password
func authPlain(socket io.ReadWriter, decoder *xml.Decoder, user string, password string) error {
	raw := "\x00" + user + "\x00" + password
	enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
	base64.StdEncoding.Encode(enc, []byte(raw))
	fmt.Fprintf(socket, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>", nsSASL, enc)

	// Next message should be either success or failure.
	val, err := next(decoder)
	if err != nil {
		return err
	}

	switch v := val.(type) {
	case *SASLSuccess:
	case *SASLFailure:
		// v.Any is type of sub-element in failure, which gives a description of what failed.
		return errors.New("auth failure: " + v.Any.Local)
	default:
		return errors.New("expected SASL success or failure, got " + v.Name())
	}
	return err
}

type saslMechanisms struct {
	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
	Mechanism []string `xml:"mechanism"`
}

// ============================================================================
// SASLSuccess

type SASLSuccess struct {
	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
}

func (SASLSuccess) Name() string {
	return "sasl:success"
}

type saslSuccessDecoder struct{}

var saslSuccess saslSuccessDecoder

func (saslSuccessDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLSuccess, error) {
	var packet SASLSuccess
	err := p.DecodeElement(&packet, &se)
	return packet, err
}

// ============================================================================
// SASLFailure

type SASLFailure struct {
	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
	Any     xml.Name // error reason is a subelement
}

func (SASLFailure) Name() string {
	return "sasl:failure"
}

type saslFailureDecoder struct{}

var saslFailure saslFailureDecoder

func (saslFailureDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLFailure, error) {
	var packet SASLFailure
	err := p.DecodeElement(&packet, &se)
	return packet, err
}

// ============================================================================

type auth struct {
	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
	Mechanism string   `xml:"mecanism,attr"`
	Value     string   `xml:",innerxml"`
}

type bindBind struct {
	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
	Resource string   `xml:"resource,omitempty"`
	Jid      string   `xml:"jid,omitempty"`
}

func (*bindBind) IsIQPayload() {
}

// Session is obsolete in RFC 6121.
// Added for compliance with RFC 3121.
// Remove when ejabberd purely conforms to RFC 6121.
type sessionSession struct {
	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"`
	optional xml.Name // If it does exist, it mean we are not required to open session
}
<commit_msg>Fix failing test<commit_after>package xmpp // import "fluux.io/xmpp"

import (
	"encoding/base64"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
)

func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f streamFeatures, user string, password string) (err error) {
	// TODO: Implement other type of SASL Authentication
	havePlain := false
	for _, m := range f.Mechanisms.Mechanism {
		if m == "PLAIN" {
			havePlain = true
			break
		}
	}
	if !havePlain {
		return fmt.Errorf("PLAIN authentication is not supported by server: %v", f.Mechanisms.Mechanism)
	}

	return authPlain(socket, decoder, user, password)
}

// Plain authentication: send base64-encoded \x00 user \x00 password
func authPlain(socket io.ReadWriter, decoder *xml.Decoder, user string, password string) error {
	raw := "\x00" + user + "\x00" + password
	enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
	base64.StdEncoding.Encode(enc, []byte(raw))
	fmt.Fprintf(socket, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>", nsSASL, enc)

	// Next message should be either success or failure.
	val, err := next(decoder)
	if err != nil {
		return err
	}

	switch v := val.(type) {
	case SASLSuccess:
	case SASLFailure:
		// v.Any is type of sub-element in failure, which gives a description of what failed.
		return errors.New("auth failure: " + v.Any.Local)
	default:
		return errors.New("expected SASL success or failure, got " + v.Name())
	}
	return err
}

type saslMechanisms struct {
	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
	Mechanism []string `xml:"mechanism"`
}

// ============================================================================
// SASLSuccess

type SASLSuccess struct {
	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
}

func (SASLSuccess) Name() string {
	return "sasl:success"
}

type saslSuccessDecoder struct{}

var saslSuccess saslSuccessDecoder

func (saslSuccessDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLSuccess, error) {
	var packet SASLSuccess
	err := p.DecodeElement(&packet, &se)
	return packet, err
}

// ============================================================================
// SASLFailure

type SASLFailure struct {
	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
	Any     xml.Name // error reason is a subelement
}

func (SASLFailure) Name() string {
	return "sasl:failure"
}

type saslFailureDecoder struct{}

var saslFailure saslFailureDecoder

func (saslFailureDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLFailure, error) {
	var packet SASLFailure
	err := p.DecodeElement(&packet, &se)
	return packet, err
}

// ============================================================================

type auth struct {
	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
	Mechanism string   `xml:"mecanism,attr"`
	Value     string   `xml:",innerxml"`
}

type bindBind struct {
	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
	Resource string   `xml:"resource,omitempty"`
	Jid      string   `xml:"jid,omitempty"`
}

func (*bindBind) IsIQPayload() {
}

// Session is obsolete in RFC 6121.
// Added for compliance with RFC 3121.
// Remove when ejabberd purely conforms to RFC 6121.
type sessionSession struct {
	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"`
	optional xml.Name // If it does exist, it mean we are not required to open session
}
<|endoftext|>


<commit_before>package login2

import (
	"encoding/json"
	"fmt"
	"net/http"

	"code.google.com/p/goauth2/oauth"
	"github.com/gorilla/mux"
)

type Provider struct {
	Name        string
	Key         string
	Secret      string
	RedirectURL string
	TokenURL    string
	AuthURL     string
	UserInfoURL string
	Scope       string
}

type BuilderConfig struct {
	Auth        *oauth.Config
	UserInfoURL string
}

type Builder struct {
	Providers map[string]*BuilderConfig
}

type User struct {
	Email string
}

func NewBuilder(userProviders []*Provider) *Builder {
	builder := new(Builder)
	builder.Providers = make(map[string]*BuilderConfig, 0)

	for _, p := range userProviders {
		config := &oauth.Config{
			ClientId:     p.Key,
			ClientSecret: p.Secret,
			RedirectURL:  p.RedirectURL,
			Scope:        p.Scope,
			AuthURL:      p.AuthURL,
			TokenURL:     p.TokenURL,
			TokenCache:   oauth.CacheFile("cache-" + p.Name + ".json"),
		}

		provider := new(BuilderConfig)
		provider.Auth = config
		provider.UserInfoURL = p.UserInfoURL

		builder.Providers[p.Name] = provider
	}

	return builder
}

func (b *Builder) Router(r *mux.Router) {
	for provider, _ := range b.Providers {
		r.HandleFunc("/auth/"+provider, b.Authorize(provider))

		r.HandleFunc("/auth/callback/{provider}", func(w http.ResponseWriter, request *http.Request) {
			vars := mux.Vars(request)
			provider := vars["provider"]

			user := b.Callback(provider, request)
			fmt.Println(provider, user)
		})
	}

}
func (b *Builder) Authorize(provider string) func(w http.ResponseWriter, r *http.Request) {
	config := b.Providers[provider]

	return func(w http.ResponseWriter, r *http.Request) {
		url := config.Auth.AuthCodeURL("")
		http.Redirect(w, r, url, http.StatusFound)
	}
}

func (b *Builder) Callback(provider string, r *http.Request) User {
	config := b.Providers[provider]
	code := r.FormValue("code")
	t := &oauth.Transport{Config: config.Auth}
	t.Exchange(code)
	responseAuth, _ := t.Client().Get(config.UserInfoURL)
	defer responseAuth.Body.Close()

	var user User
	decoder := json.NewDecoder(responseAuth.Body)
	err := decoder.Decode(&user)
	if err != nil {
		panic(err)
	}
	return user
}
<commit_msg>updated User data, saving sessions<commit_after>package login2

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"code.google.com/p/goauth2/oauth"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_SECRET")))

type Provider struct {
	Name        string
	Key         string
	Secret      string
	RedirectURL string
	TokenURL    string
	AuthURL     string
	UserInfoURL string
	Scope       string
}

type BuilderConfig struct {
	Auth        *oauth.Config
	UserInfoURL string
}

type Builder struct {
	Providers map[string]*BuilderConfig
}

type User struct {
	Id     int64
	Email  string
	Link   string
	Name   string
	Gender string
	Locale string
}

func NewBuilder(userProviders []*Provider) *Builder {
	builder := new(Builder)
	builder.Providers = make(map[string]*BuilderConfig, 0)

	for _, p := range userProviders {
		config := &oauth.Config{
			ClientId:     p.Key,
			ClientSecret: p.Secret,
			RedirectURL:  p.RedirectURL,
			Scope:        p.Scope,
			AuthURL:      p.AuthURL,
			TokenURL:     p.TokenURL,
			TokenCache:   oauth.CacheFile("cache-" + p.Name + ".json"),
		}

		provider := new(BuilderConfig)
		provider.Auth = config
		provider.UserInfoURL = p.UserInfoURL

		builder.Providers[p.Name] = provider
	}

	return builder
}

func (b *Builder) Router(r *mux.Router) {
	for provider, _ := range b.Providers {
		r.HandleFunc("/auth/"+provider, b.Authorize(provider))
	}

	r.HandleFunc("/auth/callback/{provider}", func(w http.ResponseWriter, request *http.Request) {
		vars := mux.Vars(request)
		provider := vars["provider"]

		user := b.Callback(provider, request)

		session, _ := store.Get(request, "_session")
		session.Values["user_id"] = user.Id

		session.Save(request, w)
	})
}
func (b *Builder) Authorize(provider string) func(w http.ResponseWriter, r *http.Request) {
	config := b.Providers[provider]

	return func(w http.ResponseWriter, r *http.Request) {
		url := config.Auth.AuthCodeURL("")
		http.Redirect(w, r, url, http.StatusFound)
	}
}

func (b *Builder) Callback(provider string, r *http.Request) User {
	config := b.Providers[provider]
	code := r.FormValue("code")
	t := &oauth.Transport{Config: config.Auth}
	t.Exchange(code)
	responseAuth, _ := t.Client().Get(config.UserInfoURL)
	defer responseAuth.Body.Close()

	var user User
	decoder := json.NewDecoder(responseAuth.Body)
	err := decoder.Decode(&user)
	if err != nil {
		panic(err)
	}
	return user
}
<|endoftext|>