<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/alecthomas/kingpin"
	"github.com/pkg/errors"

	"github.com/kopia/kopia/cli"
	_ "github.com/kopia/kopia/internal/logfile"
)

var baseDir = "content/docs/Reference/Command-Line"

const (
	advancedSection        = "Advanced"
	advancedCommandsWeight = 6

	commonSection        = "Common"
	commonCommandsWeight = 5

	dirMode = 0o750
)

var overrideDefault = map[string]string{
	"config-file": "repository.config",
	"log-dir":     "kopia",
}

func emitFlags(w io.Writer, flags []*kingpin.FlagModel) {
	if len(flags) == 0 {
		return
	}

	fmt.Fprintf(w, "| Flag | Short | Default | Help |\n")
	fmt.Fprintf(w, "| ---- | ----- | --- | --- |\n")

	for _, f := range sortFlags(flags) {
		maybeAdvanced := ""
		if f.Hidden {
			maybeAdvanced = "[ADV] "
		}

		shortFlag := ""
		if f.Short != 0 {
			shortFlag = "`-" + string([]byte{byte(f.Short)}) + "`"
		}

		defaultValue := ""
		if len(f.Default) > 0 {
			defaultValue = f.Default[0]
		}

		if def, ok := overrideDefault[f.Name]; ok {
			defaultValue = def
		}

		if defaultValue != "" {
			defaultValue = "`" + defaultValue + "`"
		}

		if f.IsBoolFlag() {
			if defaultValue == "" {
				defaultValue = "`false`"
			}

			fmt.Fprintf(w, "| `--[no-]%v` | %v | %v | %v%v |\n", f.Name, shortFlag, defaultValue, maybeAdvanced, f.Help)
		} else {
			fmt.Fprintf(w, "| `--%v` | %v | %v | %v%v |\n", f.Name, shortFlag, defaultValue, maybeAdvanced, f.Help)
		}
	}

	fmt.Fprintf(w, "\n")
}

func combineFlags(lists ...[]*kingpin.FlagModel) []*kingpin.FlagModel {
	var result []*kingpin.FlagModel

	for _, list := range lists {
		result = append(result, list...)
	}

	return result
}

func sortFlags(f []*kingpin.FlagModel) []*kingpin.FlagModel {
	sort.Slice(f, func(i, j int) bool {
		a, b := f[i], f[j]

		if l, r := a.Hidden, b.Hidden; l != r {
			return !l
		}

		return a.Name < b.Name
	})

	return f
}

func emitArgs(w io.Writer, args []*kingpin.ArgModel) {
	if len(args) == 0 {
		return
	}

	fmt.Fprintf(w, "| Argument | Help |\n")
	fmt.Fprintf(w, "| -------- | ---  |\n")

	args2 := append([]*kingpin.ArgModel(nil), args...)
	sort.Slice(args2, func(i, j int) bool {
		return args2[i].Name < args2[j].Name
	})

	for _, f := range args2 {
		fmt.Fprintf(w, "| `%v` | %v |\n", f.Name, f.Help)
	}

	fmt.Fprintf(w, "\n")
}

func generateAppFlags(app *kingpin.ApplicationModel) error {
	f, err := os.Create(filepath.Join(baseDir, "flags.md"))
	if err != nil {
		return errors.Wrap(err, "unable to create common flags file")
	}
	defer f.Close() //nolint:errcheck,gosec

	title := "Flags"
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: 3
---
`, title, title)
	emitFlags(f, app.Flags)

	return nil
}

func generateCommands(app *kingpin.ApplicationModel, section string, weight int, advanced bool) error {
	dir := filepath.Join(baseDir, section)

	if err := os.MkdirAll(dir, dirMode); err != nil {
		return errors.Wrapf(err, "error creating section directory for %v", section)
	}

	f, err := os.Create(filepath.Join(dir, "_index.md"))
	if err != nil {
		return errors.Wrap(err, "unable to create common flags file")
	}
	defer f.Close() //nolint:errcheck,gosec

	title := section + " Commands"
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: %v
---
`, title, title, weight)

	flat := flattenCommands(app.Commands)
	for _, c := range flat {
		generateSubcommands(f, dir, c.Help, c.Commands, advanced)
	}

	return nil
}

func flattenCommands(cmds []*kingpin.CmdModel) []*kingpin.CmdModel {
	var result []*kingpin.CmdModel

	commonRoot := &kingpin.CmdModel{
		Name:          "Common Commands",
		Help:          "Common Commands",
		CmdGroupModel: &kingpin.CmdGroupModel{},
	}
	result = append(result, commonRoot)

	for _, c := range cmds {
		if len(c.Commands) == 0 {
			commonRoot.Commands = append(commonRoot.Commands, c)
			continue
		}

		root := &kingpin.CmdModel{
			Name:          c.Name,
			FullCommand:   c.FullCommand,
			Help:          c.Help,
			Hidden:        c.Hidden,
			CmdGroupModel: &kingpin.CmdGroupModel{},
		}
		result = append(result, root)
		root.Commands = flattenChildren(c, nil, c.Hidden)
	}

	return result
}

func flattenChildren(cmd *kingpin.CmdModel, parentFlags []*kingpin.FlagModel, forceHidden bool) []*kingpin.CmdModel {
	var result []*kingpin.CmdModel

	cmdFlags := combineFlags(parentFlags, cmd.Flags)

	if len(cmd.Commands) == 0 {
		cmdClone := *cmd
		if forceHidden {
			cmdClone.Hidden = true
		}

		cmdClone.Flags = cmdFlags

		result = append(result, &cmdClone)
	} else {
		for _, c := range cmd.Commands {
			result = append(result, flattenChildren(c, cmdFlags, c.Hidden || forceHidden)...)
		}
	}

	return result
}

func generateSubcommands(w io.Writer, dir, sectionTitle string, cmds []*kingpin.CmdModel, advanced bool) {
	cmds = append([]*kingpin.CmdModel(nil), cmds...)

	first := true

	for _, c := range cmds {
		if c.Hidden != advanced {
			continue
		}

		if first {
			fmt.Fprintf(w, "\n### %v\n\n", sectionTitle)

			first = false
		}

		subcommandSlug := strings.Replace(c.FullCommand, " ", "-", -1)
		fmt.Fprintf(w, "* [`%v`](%v) - %v\n", c.FullCommand, subcommandSlug+"/", c.Help)
		generateSubcommandPage(filepath.Join(dir, subcommandSlug+".md"), c)
	}
}

func generateSubcommandPage(fname string, cmd *kingpin.CmdModel) {
	f, err := os.Create(fname)
	if err != nil {
		log.Fatalf("unable to create page: %v", err)
	}
	defer f.Close() //nolint:errcheck,gosec

	title := cmd.FullCommand
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: 10
---

`, title, title)

	flagSummary := ""
	argSummary := ""

	for _, a := range cmd.Args {
		if a.Required {
			argSummary += " <" + a.Name + ">"
		} else {
			argSummary += " [" + a.Name + "]"
		}
	}

	for _, fl := range cmd.Flags {
		if fl.Required {
			flagSummary += " \\\n        --" + fl.Name + "=..."
		}
	}

	fmt.Fprintf(f, "```shell\n$ kopia %v%v%v\n```\n\n", cmd.FullCommand, flagSummary, argSummary)
	fmt.Fprintf(f, "%v\n\n", cmd.Help)

	emitFlags(f, cmd.Flags)
	emitArgs(f, cmd.Args)
}

func main() {
	flag.Parse()

	kingpinApp := kingpin.New("kopia", "Kopia - Fast And Secure Open-Source Backup").Author("http://kopia.github.io/")
	cli.NewApp().Attach(kingpinApp)

	app := kingpinApp.Model()

	if err := generateAppFlags(app); err != nil {
		log.Fatalf("unable to generate common flags: %v", err)
	}

	if err := generateCommands(app, commonSection, commonCommandsWeight, false); err != nil {
		log.Fatalf("unable to generate common commands: %v", err)
	}

	if err := generateCommands(app, advancedSection, advancedCommandsWeight, true); err != nil {
		log.Fatalf("unable to generate advanced commands: %v", err)
	}
}
<commit_msg>Cleanup cli2md to fix issue #1440 (#1525)<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/alecthomas/kingpin"
	"github.com/pkg/errors"

	"github.com/kopia/kopia/cli"
	_ "github.com/kopia/kopia/internal/logfile"
)

var baseDir = "content/docs/Reference/Command-Line"

const (
	advancedSection        = "Advanced"
	advancedCommandsWeight = 6

	commonSection        = "Common"
	commonCommandsWeight = 5

	dirMode = 0o750
)

var overrideDefault = map[string]string{
	"config-file": "repository.config",
	"log-dir":     "kopia",
}

func emitFlags(w io.Writer, flags []*kingpin.FlagModel) {
	if len(flags) == 0 {
		return
	}

	fmt.Fprintf(w, "| Flag | Short | Default | Help |\n")
	fmt.Fprintf(w, "| ---- | ----- | --- | --- |\n")

	for _, f := range sortFlags(flags) {
		maybeAdvanced := ""
		if f.Hidden {
			maybeAdvanced = "[ADV] "
		}

		shortFlag := ""
		if f.Short != 0 {
			shortFlag = "`-" + string([]byte{byte(f.Short)}) + "`"
		}

		defaultValue := ""
		if len(f.Default) > 0 {
			defaultValue = f.Default[0]
		}

		if def, ok := overrideDefault[f.Name]; ok {
			defaultValue = def
		}

		if defaultValue != "" {
			defaultValue = "`" + defaultValue + "`"
		}

		if f.IsBoolFlag() {
			if defaultValue == "" {
				defaultValue = "`false`"
			}

			fmt.Fprintf(w, "| `--[no-]%v` | %v | %v | %v%v |\n", f.Name, shortFlag, defaultValue, maybeAdvanced, f.Help)
		} else {
			fmt.Fprintf(w, "| `--%v` | %v | %v | %v%v |\n", f.Name, shortFlag, defaultValue, maybeAdvanced, f.Help)
		}
	}

	fmt.Fprintf(w, "\n")
}

func combineFlags(lists ...[]*kingpin.FlagModel) []*kingpin.FlagModel {
	var result []*kingpin.FlagModel

	for _, list := range lists {
		result = append(result, list...)
	}

	return result
}

func sortFlags(f []*kingpin.FlagModel) []*kingpin.FlagModel {
	sort.Slice(f, func(i, j int) bool {
		a, b := f[i], f[j]

		if l, r := a.Hidden, b.Hidden; l != r {
			return !l
		}

		return a.Name < b.Name
	})

	return f
}

func emitArgs(w io.Writer, args []*kingpin.ArgModel) {
	if len(args) == 0 {
		return
	}

	fmt.Fprintf(w, "| Argument | Help |\n")
	fmt.Fprintf(w, "| -------- | ---  |\n")

	args2 := append([]*kingpin.ArgModel(nil), args...)
	sort.Slice(args2, func(i, j int) bool {
		return args2[i].Name < args2[j].Name
	})

	for _, f := range args2 {
		fmt.Fprintf(w, "| `%v` | %v |\n", f.Name, f.Help)
	}

	fmt.Fprintf(w, "\n")
}

func generateAppFlags(app *kingpin.ApplicationModel) error {
	f, err := os.Create(filepath.Join(baseDir, "flags.md"))
	if err != nil {
		return errors.Wrap(err, "unable to create common flags file")
	}
	defer f.Close() //nolint:errcheck,gosec

	title := "Flags"
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: 3
---
`, title, title)
	emitFlags(f, app.Flags)

	return nil
}

func generateCommands(app *kingpin.ApplicationModel, section string, weight int, advanced bool) error {
	dir := filepath.Join(baseDir, section)

	if err := os.MkdirAll(dir, dirMode); err != nil {
		return errors.Wrapf(err, "error creating section directory for %v", section)
	}

	f, err := os.Create(filepath.Join(dir, "_index.md"))
	if err != nil {
		return errors.Wrap(err, "unable to create common flags file")
	}
	defer f.Close() //nolint:errcheck,gosec

	title := section + " Commands"
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: %v
---
`, title, title, weight)

	flat := flattenCommands(app.Commands)
	for _, c := range flat {
		generateSubcommands(f, dir, c.Help, c.Commands, advanced)
	}

	return nil
}

func flattenCommands(cmds []*kingpin.CmdModel) []*kingpin.CmdModel {
	var result []*kingpin.CmdModel

	commonRoot := &kingpin.CmdModel{
		Name:          "Common Commands",
		Help:          "Common Commands",
		CmdGroupModel: &kingpin.CmdGroupModel{},
	}
	result = append(result, commonRoot)

	for _, c := range cmds {
		if len(c.Commands) == 0 {
			commonRoot.Commands = append(commonRoot.Commands, c)
			continue
		}

		root := &kingpin.CmdModel{
			Name:          c.Name,
			FullCommand:   c.FullCommand,
			Help:          c.Help,
			Hidden:        c.Hidden,
			CmdGroupModel: &kingpin.CmdGroupModel{},
		}
		result = append(result, root)
		root.Commands = flattenChildren(c, nil, c.Hidden)
	}

	return result
}

func flattenChildren(cmd *kingpin.CmdModel, parentFlags []*kingpin.FlagModel, forceHidden bool) []*kingpin.CmdModel {
	var result []*kingpin.CmdModel

	cmdFlags := combineFlags(parentFlags, cmd.Flags)

	if len(cmd.Commands) == 0 {
		cmdClone := *cmd
		if forceHidden {
			cmdClone.Hidden = true
		}

		cmdClone.Flags = cmdFlags

		result = append(result, &cmdClone)
	} else {
		for _, c := range cmd.Commands {
			result = append(result, flattenChildren(c, cmdFlags, c.Hidden || forceHidden)...)
		}
	}

	return result
}

func generateSubcommands(w io.Writer, dir, sectionTitle string, cmds []*kingpin.CmdModel, advanced bool) {
	cmds = append([]*kingpin.CmdModel(nil), cmds...)

	first := true

	for _, c := range cmds {
		if c.Hidden != advanced {
			continue
		}

		if first {
			fmt.Fprintf(w, "\n### %v\n\n", strings.TrimSuffix(sectionTitle, "."))

			first = false
		}

		subcommandSlug := strings.Replace(c.FullCommand, " ", "-", -1)
		helpSummary := strings.SplitN(c.Help, "\n", 2)[0] // nolint:gomnd
		helpSummary = strings.TrimSuffix(helpSummary, ".")
		fmt.Fprintf(w, "* [`%v`](%v) - %v\n", c.FullCommand, subcommandSlug+"/", helpSummary)
		generateSubcommandPage(filepath.Join(dir, subcommandSlug+".md"), c)
	}
}

func generateSubcommandPage(fname string, cmd *kingpin.CmdModel) {
	f, err := os.Create(fname)
	if err != nil {
		log.Fatalf("unable to create page: %v", err)
	}
	defer f.Close() //nolint:errcheck,gosec

	title := cmd.FullCommand
	fmt.Fprintf(f, `---
title: %q
linkTitle: %q
weight: 10
toc_hide: true
---

`, title, title)

	flagSummary := ""
	argSummary := ""

	for _, a := range cmd.Args {
		if a.Required {
			argSummary += " <" + a.Name + ">"
		} else {
			argSummary += " [" + a.Name + "]"
		}
	}

	for _, fl := range cmd.Flags {
		if fl.Required {
			flagSummary += " \\\n        --" + fl.Name + "=..."
		}
	}

	fmt.Fprintf(f, "```shell\n$ kopia %v%v%v\n```\n\n", cmd.FullCommand, flagSummary, argSummary)
	fmt.Fprintf(f, "%v\n\n", cmd.Help)

	emitFlags(f, cmd.Flags)
	emitArgs(f, cmd.Args)
}

func main() {
	flag.Parse()

	kingpinApp := kingpin.New("kopia", "Kopia - Fast And Secure Open-Source Backup").Author("http://kopia.github.io/")
	cli.NewApp().Attach(kingpinApp)

	app := kingpinApp.Model()

	if err := generateAppFlags(app); err != nil {
		log.Fatalf("unable to generate common flags: %v", err)
	}

	if err := generateCommands(app, commonSection, commonCommandsWeight, false); err != nil {
		log.Fatalf("unable to generate common commands: %v", err)
	}

	if err := generateCommands(app, advancedSection, advancedCommandsWeight, true); err != nil {
		log.Fatalf("unable to generate advanced commands: %v", err)
	}
}
<|endoftext|>


<commit_before>package controller

import (
	"context"
	"net/http"
	"time"

	"log"

	"strconv"

	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/go-chi/render"
	"github.com/sotoz/Ferrytale/entities"
)

type ErrResponse struct {
	Err            error `json:"-"` // low-level runtime error
	HTTPStatusCode int   `json:"-"` // http response status code

	StatusText string `json:"status"`          // user-level status message
	AppCode    int64  `json:"code,omitempty"`  // application-specific error code
	ErrorText  string `json:"error,omitempty"` // application-level error message, for debugging
}

var pageCtxKey string

type pageOpts struct {
	Page  int
	Limit int
}

func paginate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var page, limit int
		var err error
		pageParam := r.URL.Query().Get("page")
		limitParam := r.URL.Query().Get("limit")
		if pageParam == "" {
			page = 1
		} else {
			page, err = strconv.Atoi(pageParam)
			if err != nil {
				render.Status(r, http.StatusBadRequest)
				log.Print(err)
			}
		}
		if limitParam == "" {
			limit = 1
		} else {
			limit, err = strconv.Atoi(limitParam)
			if err != nil {
				render.Status(r, http.StatusBadRequest)
			}
		}
		ctx := context.WithValue(r.Context(), pageCtxKey, &pageOpts{
			Page:  page,
			Limit: limit,
		})
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func listDocks(w http.ResponseWriter, r *http.Request) {
	if err := render.RenderList(w, r, NewDocksListResponse(entities.Docks)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}
func listFerries(w http.ResponseWriter, r *http.Request) {
	if err := render.RenderList(w, r, NewFerriesListResponse(entities.Ferries)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}
func ListLines(w http.ResponseWriter, r *http.Request) {
	pgOpts := r.Context().Value(pageCtxKey).(*pageOpts)
	log.Print("Fetching Lines")

	lines, err := entities.GetLines(pgOpts.Page, pgOpts.Limit)
	if err != nil {
		log.Printf("error: %s", err)
	}
	if err := render.RenderList(w, r, NewLinesListResponse(lines)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}
func Router() http.Handler {
	r := chi.NewRouter()
	log.Print("asdfasdfaffafafa3333")

	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	// Set a timeout value on the request context (ctx), that will signal
	// through ctx.Done() that the request has timed out and further
	// processing should be stopped.
	r.Use(middleware.Timeout(60 * time.Second))

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Welcome to Amsterdam's Ferries webservice."))
	})

	r.Route("/docks", func(r chi.Router) {
		r.With(paginate).Get("/", listDocks)
	})

	r.Route("/ferries", func(r chi.Router) {
		r.With(paginate).Get("/", listFerries)
	})
	r.Route("/lines", func(r chi.Router) {
		r.With(paginate).Get("/", ListLines)
	})
	return r

}
<commit_msg>Make ListLines unexported<commit_after>package controller

import (
	"context"
	"net/http"
	"time"

	"log"

	"strconv"

	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/go-chi/render"
	"github.com/sotoz/Ferrytale/entities"
)

type ErrResponse struct {
	Err            error `json:"-"` // low-level runtime error
	HTTPStatusCode int   `json:"-"` // http response status code

	StatusText string `json:"status"`          // user-level status message
	AppCode    int64  `json:"code,omitempty"`  // application-specific error code
	ErrorText  string `json:"error,omitempty"` // application-level error message, for debugging
}

var pageCtxKey string

type pageOpts struct {
	Page  int
	Limit int
}

func paginate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var page, limit int
		var err error
		pageParam := r.URL.Query().Get("page")
		limitParam := r.URL.Query().Get("limit")
		if pageParam == "" {
			page = 1
		} else {
			page, err = strconv.Atoi(pageParam)
			if err != nil {
				render.Status(r, http.StatusBadRequest)
				log.Print(err)
			}
		}
		if limitParam == "" {
			limit = 1
		} else {
			limit, err = strconv.Atoi(limitParam)
			if err != nil {
				render.Status(r, http.StatusBadRequest)
			}
		}
		ctx := context.WithValue(r.Context(), pageCtxKey, &pageOpts{
			Page:  page,
			Limit: limit,
		})
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func listDocks(w http.ResponseWriter, r *http.Request) {
	if err := render.RenderList(w, r, NewDocksListResponse(entities.Docks)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}

func listFerries(w http.ResponseWriter, r *http.Request) {
	if err := render.RenderList(w, r, NewFerriesListResponse(entities.Ferries)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}

func listLines(w http.ResponseWriter, r *http.Request) {
	pgOpts := r.Context().Value(pageCtxKey).(*pageOpts)
	log.Print("Fetching Lines")

	lines, err := entities.GetLines(pgOpts.Page, pgOpts.Limit)
	if err != nil {
		log.Printf("error: %s", err)
	}
	if err := render.RenderList(w, r, NewLinesListResponse(lines)); err != nil {
		render.Render(w, r, ErrRender(err))
		return
	}
}

// Router is the default controller that has the routes for the application.
func Router() http.Handler {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	// Set a timeout value on the request context (ctx), that will signal
	// through ctx.Done() that the request has timed out and further
	// processing should be stopped.
	r.Use(middleware.Timeout(60 * time.Second))

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Welcome to Amsterdam's Ferries webservice."))
	})

	r.Route("/docks", func(r chi.Router) {
		r.With(paginate).Get("/", listDocks)
	})

	r.Route("/ferries", func(r chi.Router) {
		r.With(paginate).Get("/", listFerries)
	})
	r.Route("/lines", func(r chi.Router) {
		r.With(paginate).Get("/", listLines)
	})

	return r
}
<|endoftext|>


<commit_before>package farmer

import (
	"github.com/fsouza/go-dockerclient"
	"os"
)

var dockerClient *docker.Client

func init() {
	dockerClient, _ = docker.NewClient(os.Getenv("FARMER_DOCKER_API"))
}

func dockerCreateContainer(box *Box) error {
	container, err := dockerClient.CreateContainer(
		dockerCreateContainerOptions(box),
	)

	if err != nil {
		return err
	}

	box.ContainerID = container.ID
	dockerInspectContainer(box)

	return err
}

func dockerInspectContainer(box *Box) error {
	container, err := dockerClient.InspectContainer(box.ContainerID)

	if err != nil {
		return err
	}

	box.Hostname = container.Config.Hostname
	box.CgroupParent = container.HostConfig.CgroupParent
	box.Image = container.Config.Image
	box.IP = container.NetworkSettings.IPAddress

	box.Ports = dockerExtractPortBindings(container.NetworkSettings.Ports)
	box.Status = dockerTranslateContainerState(container.State)

	return nil
}

func dockerStartContainer(box *Box) error {
	err := dockerClient.StartContainer(box.ContainerID, dockerCreateContainerOptions(box).HostConfig)

	if err != nil {
		return err
	}

	return dockerInspectContainer(box)
}

func dockerRunContainer(box *Box) error {
	if err := dockerCreateContainer(box); err != nil {
		return err
	}

	return dockerStartContainer(box)
}

func dockerExecOnContainer(box *Box, commands []string) error {
	exec, err := dockerClient.CreateExec(docker.CreateExecOptions{
		Container:    box.ContainerID,
		AttachStdin:  false,
		AttachStdout: true,
		AttachStderr: true,
		Tty:          false,
		Cmd:          commands,
	})

	if err != nil {
		return err
	}

	return dockerClient.StartExec(exec.ID, docker.StartExecOptions{
		Detach:       false,
		Tty:          false,
		OutputStream: box.OutputStream,
		ErrorStream:  box.ErrorStream,
	})
}

func dockerDeleteContainer(box *Box) error {
	return dockerClient.RemoveContainer(docker.RemoveContainerOptions{
		ID:            box.ContainerID,
		RemoveVolumes: false,
		Force:         true,
	})
}

func dockerRestartContainer(box *Box) error {
	return dockerClient.RestartContainer(box.ContainerID, 1)
}

func dockerCreateContainerOptions(box *Box) docker.CreateContainerOptions {
	dockerConfig := &docker.Config{
		Hostname:     box.Name,
		Image:        box.Image,
		ExposedPorts: dockerReversePortBindings(box.Ports),
	}

	dockerHostConfig := &docker.HostConfig{
		Binds:           []string{box.CodeDirectory + ":/app"},
		CgroupParent:    box.CgroupParent,
		PublishAllPorts: true,
	}

	return docker.CreateContainerOptions{
		Name:       box.Name,
		Config:     dockerConfig,
		HostConfig: dockerHostConfig,
	}
}

func dockerReversePortBindings(ports []string) map[docker.Port]struct{} {
	portBindings := make(map[docker.Port]struct{})

	for _, portAndProtocol := range ports {
		var pp docker.Port
		pp = docker.Port(portAndProtocol)
		portBindings[pp] = struct{}{}
	}

	return portBindings
}

func dockerExtractPortBindings(ports map[docker.Port][]docker.PortBinding) []string {
	var portBindings []string
	for port, _ := range ports {
		portBindings = append(portBindings, string(port))
	}

	return portBindings
}

func dockerTranslateContainerState(state docker.State) string {
	switch {
	case state.Running:
		return "running"

	case state.Paused:
		return "paused"

	case state.Restarting:
		return "restarting"

	default:
		return "created"
	}
}
<commit_msg>fix(docker): Pass box environments to container creation<commit_after>package farmer

import (
	"github.com/fsouza/go-dockerclient"
	"os"
)

var dockerClient *docker.Client

func init() {
	dockerClient, _ = docker.NewClient(os.Getenv("FARMER_DOCKER_API"))
}

func dockerCreateContainer(box *Box) error {
	container, err := dockerClient.CreateContainer(
		dockerCreateContainerOptions(box),
	)

	if err != nil {
		return err
	}

	box.ContainerID = container.ID
	dockerInspectContainer(box)

	return err
}

func dockerInspectContainer(box *Box) error {
	container, err := dockerClient.InspectContainer(box.ContainerID)

	if err != nil {
		return err
	}

	box.Hostname = container.Config.Hostname
	box.CgroupParent = container.HostConfig.CgroupParent
	box.Image = container.Config.Image
	box.IP = container.NetworkSettings.IPAddress

	box.Ports = dockerExtractPortBindings(container.NetworkSettings.Ports)
	box.Status = dockerTranslateContainerState(container.State)

	return nil
}

func dockerStartContainer(box *Box) error {
	err := dockerClient.StartContainer(box.ContainerID, dockerCreateContainerOptions(box).HostConfig)

	if err != nil {
		return err
	}

	return dockerInspectContainer(box)
}

func dockerRunContainer(box *Box) error {
	if err := dockerCreateContainer(box); err != nil {
		return err
	}

	return dockerStartContainer(box)
}

func dockerExecOnContainer(box *Box, commands []string) error {
	exec, err := dockerClient.CreateExec(docker.CreateExecOptions{
		Container:    box.ContainerID,
		AttachStdin:  false,
		AttachStdout: true,
		AttachStderr: true,
		Tty:          false,
		Cmd:          commands,
	})

	if err != nil {
		return err
	}

	return dockerClient.StartExec(exec.ID, docker.StartExecOptions{
		Detach:       false,
		Tty:          false,
		OutputStream: box.OutputStream,
		ErrorStream:  box.ErrorStream,
	})
}

func dockerDeleteContainer(box *Box) error {
	return dockerClient.RemoveContainer(docker.RemoveContainerOptions{
		ID:            box.ContainerID,
		RemoveVolumes: false,
		Force:         true,
	})
}

func dockerRestartContainer(box *Box) error {
	return dockerClient.RestartContainer(box.ContainerID, 1)
}

func dockerCreateContainerOptions(box *Box) docker.CreateContainerOptions {
	dockerConfig := &docker.Config{
		Hostname:     box.Name,
		Image:        box.Image,
		ExposedPorts: dockerReversePortBindings(box.Ports),
		Env: 		  box.Env,
	}

	dockerHostConfig := &docker.HostConfig{
		Binds:           []string{box.CodeDirectory + ":/app"},
		CgroupParent:    box.CgroupParent,
		PublishAllPorts: true,
	}

	return docker.CreateContainerOptions{
		Name:       box.Name,
		Config:     dockerConfig,
		HostConfig: dockerHostConfig,
	}
}

func dockerReversePortBindings(ports []string) map[docker.Port]struct{} {
	portBindings := make(map[docker.Port]struct{})

	for _, portAndProtocol := range ports {
		var pp docker.Port
		pp = docker.Port(portAndProtocol)
		portBindings[pp] = struct{}{}
	}

	return portBindings
}

func dockerExtractPortBindings(ports map[docker.Port][]docker.PortBinding) []string {
	var portBindings []string
	for port, _ := range ports {
		portBindings = append(portBindings, string(port))
	}

	return portBindings
}

func dockerTranslateContainerState(state docker.State) string {
	switch {
	case state.Running:
		return "running"

	case state.Paused:
		return "paused"

	case state.Restarting:
		return "restarting"

	default:
		return "created"
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Space Monkey, Inc.
// +build cgo

package openssl

// #include <openssl/ssl.h>
// #include <openssl/conf.h>
// #include <openssl/err.h>
import "C"

import (
	"errors"
	"io"
	"net"
	"runtime"
	"sync"
	"time"
	"unsafe"

	"code.spacemonkey.com/go/openssl/utils"
)

var (
	zeroReturn = errors.New("zero return")
	wantRead   = errors.New("want read")
	wantWrite  = errors.New("want write")
	tryAgain   = errors.New("try again")
)

type Conn struct {
	conn             net.Conn
	ssl              *C.SSL
	into_ssl         *readBio
	from_ssl         *writeBio
	is_shutdown      bool
	mtx              sync.Mutex
	want_read_future *utils.Future
}

func newSSL(ctx *C.SSL_CTX) (*C.SSL, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	ssl := C.SSL_new(ctx)
	if ssl == nil {
		return nil, errorFromErrorQueue()
	}
	return ssl, nil
}

func newConn(conn net.Conn, ctx *Ctx) (*Conn, error) {
	ssl, err := newSSL(ctx.ctx)
	if err != nil {
		return nil, err
	}

	into_ssl := &readBio{}
	from_ssl := &writeBio{}

	into_ssl_cbio := into_ssl.MakeCBIO()
	from_ssl_cbio := from_ssl.MakeCBIO()
	if into_ssl_cbio == nil || from_ssl_cbio == nil {
		// these frees are null safe
		C.BIO_free(into_ssl_cbio)
		C.BIO_free(from_ssl_cbio)
		C.SSL_free(ssl)
		return nil, errors.New("failed to allocate memory BIO")
	}

	// the ssl object takes ownership of these objects now
	C.SSL_set_bio(ssl, into_ssl_cbio, from_ssl_cbio)

	c := &Conn{
		conn:     conn,
		ssl:      ssl,
		into_ssl: into_ssl,
		from_ssl: from_ssl}
	runtime.SetFinalizer(c, func(c *Conn) {
		c.into_ssl.Disconnect(into_ssl_cbio)
		c.from_ssl.Disconnect(from_ssl_cbio)
		C.SSL_free(c.ssl)
	})
	return c, nil
}

// Client wraps an existing stream connection and puts it in the connect state
// for any subsequent handshakes.
//
// IMPORTANT NOTE: if you use this method instead of Dial to construct an SSL
// connection, you are responsible for verifying the peer's hostname.
// Otherwise, you are vulnerable to MITM attacks.
//
// Client connections probably won't work for you unless you set a verify
// location or add some certs to the certificate store of the client context
// you're using. This library is not nice enough to use the system certificate
// store by default for you yet.
func Client(conn net.Conn, ctx *Ctx) (*Conn, error) {
	c, err := newConn(conn, ctx)
	if err != nil {
		return nil, err
	}
	C.SSL_set_connect_state(c.ssl)
	return c, nil
}

// Server wraps an existing stream connection and puts it in the accept state
// for any subsequent handshakes.
func Server(conn net.Conn, ctx *Ctx) (*Conn, error) {
	c, err := newConn(conn, ctx)
	if err != nil {
		return nil, err
	}
	C.SSL_set_accept_state(c.ssl)
	return c, nil
}

func (c *Conn) fillInputBuffer() error {
	for {
		n, err := c.into_ssl.ReadFromOnce(c.conn)
		if n == 0 && err == nil {
			continue
		}
		if err == io.EOF {
			c.into_ssl.MarkEOF()
			return c.Close()
		}
		return err
	}
}

func (c *Conn) flushOutputBuffer() error {
	_, err := c.from_ssl.WriteTo(c.conn)
	return err
}

func (c *Conn) getErrorHandler(rv C.int, errno error) func() error {
	errcode := C.SSL_get_error(c.ssl, rv)
	switch errcode {
	case C.SSL_ERROR_ZERO_RETURN:
		return func() error {
			c.Close()
			return io.ErrUnexpectedEOF
		}
	case C.SSL_ERROR_WANT_READ:
		go c.flushOutputBuffer()
		if c.want_read_future != nil {
			want_read_future := c.want_read_future
			return func() error {
				_, err := want_read_future.Get()
				return err
			}
		}
		c.want_read_future = utils.NewFuture()
		want_read_future := c.want_read_future
		return func() (err error) {
			defer func() {
				c.mtx.Lock()
				c.want_read_future = nil
				c.mtx.Unlock()
				want_read_future.Set(nil, err)
			}()
			err = c.fillInputBuffer()
			if err != nil {
				return err
			}
			return tryAgain
		}
	case C.SSL_ERROR_WANT_WRITE:
		return func() error {
			err := c.flushOutputBuffer()
			if err != nil {
				return err
			}
			return tryAgain
		}
	case C.SSL_ERROR_SYSCALL:
		var err error
		if C.ERR_peek_error() == 0 {
			switch rv {
			case 0:
				err = errors.New("protocol-violating EOF")
			case -1:
				err = errno
			default:
				err = errorFromErrorQueue()
			}
		} else {
			err = errorFromErrorQueue()
		}
		return func() error { return err }
	default:
		err := errorFromErrorQueue()
		return func() error { return err }
	}
}

func (c *Conn) handleError(errcb func() error) error {
	if errcb != nil {
		return errcb()
	}
	return nil
}

func (c *Conn) handshake() func() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		return func() error { return io.ErrUnexpectedEOF }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_do_handshake(c.ssl)
	if rv > 0 {
		return nil
	}
	return c.getErrorHandler(rv, errno)
}

// Handshake performs an SSL handshake. If a handshake is not manually
// triggered, it will run before the first I/O on the encrypted stream.
func (c *Conn) Handshake() error {
	err := tryAgain
	for err == tryAgain {
		err = c.handleError(c.handshake())
	}
	go c.flushOutputBuffer()
	return err
}

// PeerCertificate returns the Certificate of the peer with which you're
// communicating. Only valid after a handshake.
func (c *Conn) PeerCertificate() (*Certificate, error) {
	c.mtx.Lock()
	if c.is_shutdown {
		return nil, errors.New("connection closed")
	}
	x := C.SSL_get_peer_certificate(c.ssl)
	c.mtx.Unlock()
	if x == nil {
		return nil, errors.New("no peer certificate found")
	}
	cert := &Certificate{x: x}
	runtime.SetFinalizer(cert, func(cert *Certificate) {
		C.X509_free(cert.x)
	})
	return cert, nil
}

func (c *Conn) shutdown() func() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_shutdown(c.ssl)
	if rv > 0 {
		return nil
	}
	if rv == 0 {
		// The OpenSSL docs say that in this case, the shutdown is not
		// finished, and we should call SSL_shutdown() a second time, if a
		// bidirectional shutdown is going to be performed. Further, the
		// output of SSL_get_error may be misleading, as an erroneous
		// SSL_ERROR_SYSCALL may be flagged even though no error occurred.
		// So, TODO: revisit bidrectional shutdown, possibly trying again.
		// Note: some broken clients won't engage in bidirectional shutdown
		// without tickling them to close by sending a TCP_FIN packet, or
		// shutting down the write-side of the connection.
		return nil
	} else {
		return c.getErrorHandler(rv, errno)
	}
}

func (c *Conn) shutdownLoop() error {
	err := tryAgain
	shutdown_tries := 0
	for err == tryAgain {
		shutdown_tries = shutdown_tries + 1
		err = c.handleError(c.shutdown())
		if err == nil {
			return c.flushOutputBuffer()
		}
		if err == tryAgain && shutdown_tries >= 2 {
			return errors.New("shutdown requested a third time?")
		}
	}
	if err == io.ErrUnexpectedEOF {
		err = nil
	}
	return err
}

// Close shuts down the SSL connection and closes the underlying wrapped
// connection.
func (c *Conn) Close() error {
	c.mtx.Lock()
	if c.is_shutdown {
		c.mtx.Unlock()
		return nil
	}
	c.is_shutdown = true
	c.mtx.Unlock()
	var errs utils.ErrorGroup
	errs.Add(c.shutdownLoop())
	errs.Add(c.conn.Close())
	return errs.Finalize()
}

func (c *Conn) read(b []byte) (int, func() error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		return 0, func() error { return io.EOF }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_read(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
	if rv > 0 {
		return int(rv), nil
	}
	return 0, c.getErrorHandler(rv, errno)
}

// Read reads up to len(b) bytes into b. It returns the number of bytes read
// and an error if applicable. io.EOF is returned when the caller can expect
// to see no more data.
func (c *Conn) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	err = tryAgain
	for err == tryAgain {
		n, errcb := c.read(b)
		err = c.handleError(errcb)
		if err == nil {
			go c.flushOutputBuffer()
			return n, nil
		}
		if err == io.ErrUnexpectedEOF {
			err = io.EOF
		}
	}
	return 0, err
}

func (c *Conn) write(b []byte) (int, func() error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		err := errors.New("connection closed")
		return 0, func() error { return err }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_write(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
	if rv > 0 {
		return int(rv), nil
	}
	return 0, c.getErrorHandler(rv, errno)
}

// Write will encrypt the contents of b and write it to the underlying stream.
// Performance will be vastly improved if the size of b is a multiple of
// SSLRecordSize.
func (c *Conn) Write(b []byte) (written int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	err = tryAgain
	for err == tryAgain {
		n, errcb := c.write(b)
		err = c.handleError(errcb)
		if err == nil {
			return n, c.flushOutputBuffer()
		}
	}
	return 0, err
}

// VerifyHostname pulls the PeerCertificate and calls VerifyHostname on the
// certificate.
func (c *Conn) VerifyHostname(host string) error {
	cert, err := c.PeerCertificate()
	if err != nil {
		return err
	}
	return cert.VerifyHostname(host)
}

// LocalAddr returns the underlying connection's local address
func (c *Conn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

// RemoteAddr returns the underlying connection's remote address
func (c *Conn) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

// SetDeadline calls SetDeadline on the underlying connection.
func (c *Conn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

// SetReadDeadline calls SetReadDeadline on the underlying connection.
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

// SetWriteDeadline calls SetWriteDeadline on the underlying connection.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}
<commit_msg>space monkey internal commit export<commit_after>// Copyright (C) 2014 Space Monkey, Inc.
// +build cgo

package openssl

// #include <openssl/ssl.h>
// #include <openssl/conf.h>
// #include <openssl/err.h>
import "C"

import (
	"errors"
	"io"
	"net"
	"runtime"
	"sync"
	"time"
	"unsafe"

	"code.spacemonkey.com/go/openssl/utils"
)

var (
	zeroReturn = errors.New("zero return")
	wantRead   = errors.New("want read")
	wantWrite  = errors.New("want write")
	tryAgain   = errors.New("try again")
)

type Conn struct {
	conn             net.Conn
	ssl              *C.SSL
	into_ssl         *readBio
	from_ssl         *writeBio
	is_shutdown      bool
	mtx              sync.Mutex
	want_read_future *utils.Future
}

func newSSL(ctx *C.SSL_CTX) (*C.SSL, error) {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	ssl := C.SSL_new(ctx)
	if ssl == nil {
		return nil, errorFromErrorQueue()
	}
	return ssl, nil
}

func newConn(conn net.Conn, ctx *Ctx) (*Conn, error) {
	ssl, err := newSSL(ctx.ctx)
	if err != nil {
		return nil, err
	}

	into_ssl := &readBio{}
	from_ssl := &writeBio{}

	into_ssl_cbio := into_ssl.MakeCBIO()
	from_ssl_cbio := from_ssl.MakeCBIO()
	if into_ssl_cbio == nil || from_ssl_cbio == nil {
		// these frees are null safe
		C.BIO_free(into_ssl_cbio)
		C.BIO_free(from_ssl_cbio)
		C.SSL_free(ssl)
		return nil, errors.New("failed to allocate memory BIO")
	}

	// the ssl object takes ownership of these objects now
	C.SSL_set_bio(ssl, into_ssl_cbio, from_ssl_cbio)

	c := &Conn{
		conn:     conn,
		ssl:      ssl,
		into_ssl: into_ssl,
		from_ssl: from_ssl}
	runtime.SetFinalizer(c, func(c *Conn) {
		c.into_ssl.Disconnect(into_ssl_cbio)
		c.from_ssl.Disconnect(from_ssl_cbio)
		C.SSL_free(c.ssl)
	})
	return c, nil
}

// Client wraps an existing stream connection and puts it in the connect state
// for any subsequent handshakes.
//
// IMPORTANT NOTE: if you use this method instead of Dial to construct an SSL
// connection, you are responsible for verifying the peer's hostname.
// Otherwise, you are vulnerable to MITM attacks.
//
// Client connections probably won't work for you unless you set a verify
// location or add some certs to the certificate store of the client context
// you're using. This library is not nice enough to use the system certificate
// store by default for you yet.
func Client(conn net.Conn, ctx *Ctx) (*Conn, error) {
	c, err := newConn(conn, ctx)
	if err != nil {
		return nil, err
	}
	C.SSL_set_connect_state(c.ssl)
	return c, nil
}

// Server wraps an existing stream connection and puts it in the accept state
// for any subsequent handshakes.
func Server(conn net.Conn, ctx *Ctx) (*Conn, error) {
	c, err := newConn(conn, ctx)
	if err != nil {
		return nil, err
	}
	C.SSL_set_accept_state(c.ssl)
	return c, nil
}

func (c *Conn) fillInputBuffer() error {
	for {
		n, err := c.into_ssl.ReadFromOnce(c.conn)
		if n == 0 && err == nil {
			continue
		}
		if err == io.EOF {
			c.into_ssl.MarkEOF()
			return c.Close()
		}
		return err
	}
}

func (c *Conn) flushOutputBuffer() error {
	_, err := c.from_ssl.WriteTo(c.conn)
	return err
}

func (c *Conn) getErrorHandler(rv C.int, errno error) func() error {
	errcode := C.SSL_get_error(c.ssl, rv)
	switch errcode {
	case C.SSL_ERROR_ZERO_RETURN:
		return func() error {
			c.Close()
			return io.ErrUnexpectedEOF
		}
	case C.SSL_ERROR_WANT_READ:
		go c.flushOutputBuffer()
		if c.want_read_future != nil {
			want_read_future := c.want_read_future
			return func() error {
				_, err := want_read_future.Get()
				return err
			}
		}
		c.want_read_future = utils.NewFuture()
		want_read_future := c.want_read_future
		return func() (err error) {
			defer func() {
				c.mtx.Lock()
				c.want_read_future = nil
				c.mtx.Unlock()
				want_read_future.Set(nil, err)
			}()
			err = c.fillInputBuffer()
			if err != nil {
				return err
			}
			return tryAgain
		}
	case C.SSL_ERROR_WANT_WRITE:
		return func() error {
			err := c.flushOutputBuffer()
			if err != nil {
				return err
			}
			return tryAgain
		}
	case C.SSL_ERROR_SYSCALL:
		var err error
		if C.ERR_peek_error() == 0 {
			switch rv {
			case 0:
				err = errors.New("protocol-violating EOF")
			case -1:
				err = errno
			default:
				err = errorFromErrorQueue()
			}
		} else {
			err = errorFromErrorQueue()
		}
		return func() error { return err }
	default:
		err := errorFromErrorQueue()
		return func() error { return err }
	}
}

func (c *Conn) handleError(errcb func() error) error {
	if errcb != nil {
		return errcb()
	}
	return nil
}

func (c *Conn) handshake() func() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		return func() error { return io.ErrUnexpectedEOF }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_do_handshake(c.ssl)
	if rv > 0 {
		return nil
	}
	return c.getErrorHandler(rv, errno)
}

// Handshake performs an SSL handshake. If a handshake is not manually
// triggered, it will run before the first I/O on the encrypted stream.
func (c *Conn) Handshake() error {
	err := tryAgain
	for err == tryAgain {
		err = c.handleError(c.handshake())
	}
	go c.flushOutputBuffer()
	return err
}

// PeerCertificate returns the Certificate of the peer with which you're
// communicating. Only valid after a handshake.
func (c *Conn) PeerCertificate() (*Certificate, error) {
	c.mtx.Lock()
	if c.is_shutdown {
		return nil, errors.New("connection closed")
	}
	x := C.SSL_get_peer_certificate(c.ssl)
	c.mtx.Unlock()
	if x == nil {
		return nil, errors.New("no peer certificate found")
	}
	cert := &Certificate{x: x}
	runtime.SetFinalizer(cert, func(cert *Certificate) {
		C.X509_free(cert.x)
	})
	return cert, nil
}

type ConnectionState struct {
    Certificate *Certificate
    CertificateError error
}

func (c *Conn) ConnectionState() (rv ConnectionState) {
    rv.Certificate, rv.CertificateError = c.PeerCertificate()
    return
}

func (c *Conn) shutdown() func() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_shutdown(c.ssl)
	if rv > 0 {
		return nil
	}
	if rv == 0 {
		// The OpenSSL docs say that in this case, the shutdown is not
		// finished, and we should call SSL_shutdown() a second time, if a
		// bidirectional shutdown is going to be performed. Further, the
		// output of SSL_get_error may be misleading, as an erroneous
		// SSL_ERROR_SYSCALL may be flagged even though no error occurred.
		// So, TODO: revisit bidrectional shutdown, possibly trying again.
		// Note: some broken clients won't engage in bidirectional shutdown
		// without tickling them to close by sending a TCP_FIN packet, or
		// shutting down the write-side of the connection.
		return nil
	} else {
		return c.getErrorHandler(rv, errno)
	}
}

func (c *Conn) shutdownLoop() error {
	err := tryAgain
	shutdown_tries := 0
	for err == tryAgain {
		shutdown_tries = shutdown_tries + 1
		err = c.handleError(c.shutdown())
		if err == nil {
			return c.flushOutputBuffer()
		}
		if err == tryAgain && shutdown_tries >= 2 {
			return errors.New("shutdown requested a third time?")
		}
	}
	if err == io.ErrUnexpectedEOF {
		err = nil
	}
	return err
}

// Close shuts down the SSL connection and closes the underlying wrapped
// connection.
func (c *Conn) Close() error {
	c.mtx.Lock()
	if c.is_shutdown {
		c.mtx.Unlock()
		return nil
	}
	c.is_shutdown = true
	c.mtx.Unlock()
	var errs utils.ErrorGroup
	errs.Add(c.shutdownLoop())
	errs.Add(c.conn.Close())
	return errs.Finalize()
}

func (c *Conn) read(b []byte) (int, func() error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		return 0, func() error { return io.EOF }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_read(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
	if rv > 0 {
		return int(rv), nil
	}
	return 0, c.getErrorHandler(rv, errno)
}

// Read reads up to len(b) bytes into b. It returns the number of bytes read
// and an error if applicable. io.EOF is returned when the caller can expect
// to see no more data.
func (c *Conn) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	err = tryAgain
	for err == tryAgain {
		n, errcb := c.read(b)
		err = c.handleError(errcb)
		if err == nil {
			go c.flushOutputBuffer()
			return n, nil
		}
		if err == io.ErrUnexpectedEOF {
			err = io.EOF
		}
	}
	return 0, err
}

func (c *Conn) write(b []byte) (int, func() error) {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.is_shutdown {
		err := errors.New("connection closed")
		return 0, func() error { return err }
	}
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	rv, errno := C.SSL_write(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
	if rv > 0 {
		return int(rv), nil
	}
	return 0, c.getErrorHandler(rv, errno)
}

// Write will encrypt the contents of b and write it to the underlying stream.
// Performance will be vastly improved if the size of b is a multiple of
// SSLRecordSize.
func (c *Conn) Write(b []byte) (written int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	err = tryAgain
	for err == tryAgain {
		n, errcb := c.write(b)
		err = c.handleError(errcb)
		if err == nil {
			return n, c.flushOutputBuffer()
		}
	}
	return 0, err
}

// VerifyHostname pulls the PeerCertificate and calls VerifyHostname on the
// certificate.
func (c *Conn) VerifyHostname(host string) error {
	cert, err := c.PeerCertificate()
	if err != nil {
		return err
	}
	return cert.VerifyHostname(host)
}

// LocalAddr returns the underlying connection's local address
func (c *Conn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

// RemoteAddr returns the underlying connection's remote address
func (c *Conn) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

// SetDeadline calls SetDeadline on the underlying connection.
func (c *Conn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

// SetReadDeadline calls SetReadDeadline on the underlying connection.
func (c *Conn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

// SetWriteDeadline calls SetWriteDeadline on the underlying connection.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}
<|endoftext|>


<commit_before>package rhynock

import (
	"github.com/gorilla/websocket"
	"net/http"
	"time"
	"log"
)

// Some defaults for pinging
// Needs to be settable from outside
const (
	writeWait = 10 * time.Second
	pongWait = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10
	maxMessageSize = 512
)

// Conn encapsulates our websocket
type Conn struct {
	// Exported so everything can be messed with from outside
	Ws      *websocket.Conn
	Send    chan []byte
	Dst     BottleDst
	Quit chan []byte
}

//
// Convenience function so you dont have to use the Send channel
//
func (c *Conn) Send(message string) {
	// Basically just typecasting for convenience
	c.Send <- []byte(message)
}

//
// Convenience function to call the quit channel with a message
//
func (c *Conn) CloseMsg(message string) {
	c.Quit <- []byte(message)
}

//
// Used to write a single message to the client and report any errors
//
func (c *Conn) write(t int, payload []byte) error {
	c.Ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.Ws.WriteMessage(t, payload)
}

//
// Maintains both a reader and a writer, cleans up both if one fails
//
func (c *Conn) read_write() {
	// Ping timer
	ticker := time.NewTicker(pingPeriod)

	// Clean up Connection and Connection resources
	defer func() {
		ticker.Stop()
		c.Ws.Close()
	}()

	// Config websocket settings
	c.Ws.SetReadLimit(maxMessageSize)
	c.Ws.SetReadDeadline(time.Now().Add(pongWait))
	c.Ws.SetPongHandler(func(string) error {
		// Give each client pongWait seconds after the ping to respond
		c.Ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// Start a reading goroutine
	// The reader will stop when the c.Ws.Close is called at
	// in the defered cleanup function, so we do not manually
	// have to close the reader
	go func() {
		for {
			// This blcoks until it reads EOF or an error
			// occurs trying to read, the error can be
			// used to detect when the client closes the Connection
			_, message, err := c.Ws.ReadMessage()
			if err != nil {
				break // If we get an error escape the loop
			}

			// Bottle the message with its sender
			bottle := &Bottle{
				Sender: c,
				Message: message,
			}

			// Send to the destination for processing
			c.Dst.GetBottleChan() <- bottle
		}
		// The reader has been terminated

	}()

	// Main handling loop
	for {
		select {
		case message, ok := <- c.Send:
			// Our send channel has something in it or the channel closed
			if !ok {
				// Our channel was closed, gracefully close socket Conn
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			// Attempt to write the message to the websocket
			if err := c.write(websocket.TextMessage, message); err != nil {
				// If we get an error we can no longer communcate with client
				// return, no need to send CloseMessage since that would
				// just yield another error
				return
			}

		case <- ticker.C:
			// Ping ticker went off. We need to ping to check for connectivity.
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				// We got an error pinging, return and call defer
				// defer will close the socket which will kill the reader
				return
			}

		case bytes := <- c.Quit:
			// Close connection and send a final message
			c.write(websocket.TextMessage, bytes)
			c.write(websocket.CloseMessage, []byte{})
			return
		}
	}

}

//
// This function chews through the power cables
//
func (c *Conn) Close() {
	// Send ourself the quit signal with no message
	c.Quit <- []byte("")
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r* http.Request) bool { return true }}

//
// Hanlder function to start a websocket connection
//
func ConnectionHandler(w http.ResponseWriter, r *http.Request, dst BottleDst) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// Create new connection object
	c := &Conn{
		Send: make(chan []byte, 256),
		Ws: ws,
		Dst: dst,
		Quit: make(chan []byte),
	}

	// Alert the destination that a new connection has opened
	dst.ConnectionOpened(c)

	// Start infinite read/write loop
	c.read_write()
}
<commit_msg>Change name<commit_after>package rhynock

import (
	"github.com/gorilla/websocket"
	"net/http"
	"time"
	"log"
)

// Some defaults for pinging
// Needs to be settable from outside
const (
	writeWait = 10 * time.Second
	pongWait = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10
	maxMessageSize = 512
)

// Conn encapsulates our websocket
type Conn struct {
	// Exported so everything can be messed with from outside
	Ws      *websocket.Conn
	Send    chan []byte
	Dst     BottleDst
	Quit chan []byte
}

//
// Convenience function so you dont have to use the Send channel
//
func (c *Conn) SendMsg(message string) {
	// Basically just typecasting for convenience
	c.Send <- []byte(message)
}

//
// Convenience function to call the quit channel with a message
//
func (c *Conn) CloseMsg(message string) {
	c.Quit <- []byte(message)
}

//
// Used to write a single message to the client and report any errors
//
func (c *Conn) write(t int, payload []byte) error {
	c.Ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.Ws.WriteMessage(t, payload)
}

//
// Maintains both a reader and a writer, cleans up both if one fails
//
func (c *Conn) read_write() {
	// Ping timer
	ticker := time.NewTicker(pingPeriod)

	// Clean up Connection and Connection resources
	defer func() {
		ticker.Stop()
		c.Ws.Close()
	}()

	// Config websocket settings
	c.Ws.SetReadLimit(maxMessageSize)
	c.Ws.SetReadDeadline(time.Now().Add(pongWait))
	c.Ws.SetPongHandler(func(string) error {
		// Give each client pongWait seconds after the ping to respond
		c.Ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// Start a reading goroutine
	// The reader will stop when the c.Ws.Close is called at
	// in the defered cleanup function, so we do not manually
	// have to close the reader
	go func() {
		for {
			// This blcoks until it reads EOF or an error
			// occurs trying to read, the error can be
			// used to detect when the client closes the Connection
			_, message, err := c.Ws.ReadMessage()
			if err != nil {
				break // If we get an error escape the loop
			}

			// Bottle the message with its sender
			bottle := &Bottle{
				Sender: c,
				Message: message,
			}

			// Send to the destination for processing
			c.Dst.GetBottleChan() <- bottle
		}
		// The reader has been terminated

	}()

	// Main handling loop
	for {
		select {
		case message, ok := <- c.Send:
			// Our send channel has something in it or the channel closed
			if !ok {
				// Our channel was closed, gracefully close socket Conn
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			// Attempt to write the message to the websocket
			if err := c.write(websocket.TextMessage, message); err != nil {
				// If we get an error we can no longer communcate with client
				// return, no need to send CloseMessage since that would
				// just yield another error
				return
			}

		case <- ticker.C:
			// Ping ticker went off. We need to ping to check for connectivity.
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				// We got an error pinging, return and call defer
				// defer will close the socket which will kill the reader
				return
			}

		case bytes := <- c.Quit:
			// Close connection and send a final message
			c.write(websocket.TextMessage, bytes)
			c.write(websocket.CloseMessage, []byte{})
			return
		}
	}

}

//
// This function chews through the power cables
//
func (c *Conn) Close() {
	// Send ourself the quit signal with no message
	c.Quit <- []byte("")
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r* http.Request) bool { return true }}

//
// Hanlder function to start a websocket connection
//
func ConnectionHandler(w http.ResponseWriter, r *http.Request, dst BottleDst) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// Create new connection object
	c := &Conn{
		Send: make(chan []byte, 256),
		Ws: ws,
		Dst: dst,
		Quit: make(chan []byte),
	}

	// Alert the destination that a new connection has opened
	dst.ConnectionOpened(c)

	// Start infinite read/write loop
	c.read_write()
}
<|endoftext|>


<commit_before>package osc

import (
	"errors"
	"net"
	"strings"
)

// Common errors.
var (
	ErrNilDispatcher  = errors.New("nil dispatcher")
	ErrPrematureClose = errors.New("server cannot be closed before calling Listen")
)

// Conn defines the methods
type Conn interface {
	net.Conn
	Serve(Dispatcher) error
	Send(Packet) (int64, error)
}

var invalidAddressRunes = []rune{'*', '?', ',', '[', ']', '{', '}', '#', ' '}

func validateAddress(addr string) error {
	for _, chr := range invalidAddressRunes {
		if strings.ContainsRune(addr, chr) {
			return ErrInvalidAddress
		}
	}
	return nil
}
<commit_msg>Revert "update conn interface"<commit_after>package osc

import (
	"errors"
	"net"
	"strings"
)

// Common errors.
var (
	ErrNilDispatcher  = errors.New("nil dispatcher")
	ErrPrematureClose = errors.New("server cannot be closed before calling Listen")
)

// Conn defines the methods
type Conn interface {
	net.Conn
	Serve(Dispatcher) error
	Send(Packet) error
}

var invalidAddressRunes = []rune{'*', '?', ',', '[', ']', '{', '}', '#', ' '}

func validateAddress(addr string) error {
	for _, chr := range invalidAddressRunes {
		if strings.ContainsRune(addr, chr) {
			return ErrInvalidAddress
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Supports Windows, Linux, Mac, and Raspberry Pi

package main

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/arduino/arduino-create-agent/programmer"
	"github.com/arduino/arduino-create-agent/utilities"
	"github.com/gin-gonic/gin"
	"github.com/googollee/go-socket.io"
)

type connection struct {
	// The websocket connection.
	ws socketio.Socket

	// Buffered channel of outbound messages.
	send     chan []byte
	incoming chan []byte
}

func (c *connection) writer() {
	for message := range c.send {
		err := c.ws.Emit("message", string(message))
		if err != nil {
			break
		}
	}
}

// WsServer overrides socket.io server to set the CORS
type WsServer struct {
	Server *socketio.Server
}

func (s *WsServer) ServeHTTP(c *gin.Context) {
	s.Server.ServeHTTP(c.Writer, c.Request)
}

type AdditionalFile struct {
	Hex      []byte `json:"hex"`
	Filename string `json:"filename"`
}

// Upload contains the data to upload a sketch onto a board
type Upload struct {
	Port        string           `json:"port"`
	Board       string           `json:"board"`
	Rewrite     string           `json:"rewrite"`
	Commandline string           `json:"commandline"`
	Signature   string           `json:"signature"`
	Extra       programmer.Extra `json:"extra"`
	Hex         []byte           `json:"hex"`
	Filename    string           `json:"filename"`
	ExtraFiles  []AdditionalFile `json:"extrafiles"`
}

func uploadHandler(c *gin.Context) {
	data := new(Upload)
	c.BindJSON(data)

	log.Printf("%+v", data)

	if data.Port == "" {
		c.String(http.StatusBadRequest, "port is required")
		return
	}

	if data.Board == "" {
		c.String(http.StatusBadRequest, "board is required")
		log.Error("board is required")
		return
	}

	if data.Extra.Network == false {
		if data.Signature == "" {
			c.String(http.StatusBadRequest, "signature is required")
			return
		}

		if data.Commandline == "" {
			c.String(http.StatusBadRequest, "commandline is required for local board")
			return
		}

		err := verifyCommandLine(data.Commandline, data.Signature)

		if err != nil {
			c.String(http.StatusBadRequest, "signature is invalid")
			return
		}
	}

	buffer := bytes.NewBuffer(data.Hex)

	filePath, err := utilities.SaveFileonTempDir(data.Filename, buffer)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}

	for _, extraFile := range data.ExtraFiles {
		path := filepath.Join(filepath.Dir(filePath), extraFile.Filename)
		log.Printf("Saving %s on %s", extraFile.Filename, path)
		err := ioutil.WriteFile(path, extraFile.Hex, 0644)
		if err != nil {
			log.Printf(err.Error())
		}
	}

	if data.Rewrite != "" {
		data.Board = data.Rewrite
	}

	go func() {
		// Resolve commandline
		commandline, err := programmer.Resolve(data.Port, data.Board, filePath, data.Commandline, data.Extra, &Tools)
		if err != nil {

			return
		}

		// Upload
		if data.Extra.Network {
			send(map[string]string{"ProgrammerStatus": "Starting", "Cmd": "Network"})
			err = programmer.Network(data.Port, data.Board, filePath, commandline, data.Extra.Auth, nil)
		} else {
			send(map[string]string{"ProgrammerStatus": "Starting", "Cmd": "Serial"})
			err = programmer.Serial(data.Port, commandline, data.Extra, nil)
		}

		// Handle result
		if err != nil {
			send(map[string]string{"ProgrammerStatus": "Error", "Msg": err.Error()})
			return
		}
		send(map[string]string{"ProgrammerStatus": "Done", "Flash": "Ok"})
	}()

	c.String(http.StatusAccepted, "")
}

func send(args map[string]string) {
	mapB, _ := json.Marshal(args)
	h.broadcastSys <- mapB
}

func verifyCommandLine(input string, signature string) error {
	sign, _ := hex.DecodeString(signature)
	block, _ := pem.Decode([]byte(*signatureKey))
	if block == nil {
		return errors.New("invalid key")
	}
	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	rsaKey := key.(*rsa.PublicKey)
	h := sha256.New()
	h.Write([]byte(input))
	d := h.Sum(nil)
	return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, d, sign)
}

func wsHandler() *WsServer {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		c := &connection{send: make(chan []byte, 256*10), ws: so}
		h.register <- c
		so.On("command", func(message string) {
			h.broadcast <- []byte(message)
		})

		so.On("disconnection", func() {
			h.unregister <- c
		})
		go c.writer()
	})
	server.On("error", func(so socketio.Socket, err error) {
		log.Println("error:", err)
	})

	wrapper := WsServer{
		Server: server,
	}

	return &wrapper
}
<commit_msg>Add logger<commit_after>// Supports Windows, Linux, Mac, and Raspberry Pi

package main

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/arduino/arduino-create-agent/programmer"
	"github.com/arduino/arduino-create-agent/utilities"
	"github.com/gin-gonic/gin"
	"github.com/googollee/go-socket.io"
)

type connection struct {
	// The websocket connection.
	ws socketio.Socket

	// Buffered channel of outbound messages.
	send     chan []byte
	incoming chan []byte
}

func (c *connection) writer() {
	for message := range c.send {
		err := c.ws.Emit("message", string(message))
		if err != nil {
			break
		}
	}
}

// WsServer overrides socket.io server to set the CORS
type WsServer struct {
	Server *socketio.Server
}

func (s *WsServer) ServeHTTP(c *gin.Context) {
	s.Server.ServeHTTP(c.Writer, c.Request)
}

type AdditionalFile struct {
	Hex      []byte `json:"hex"`
	Filename string `json:"filename"`
}

// Upload contains the data to upload a sketch onto a board
type Upload struct {
	Port        string           `json:"port"`
	Board       string           `json:"board"`
	Rewrite     string           `json:"rewrite"`
	Commandline string           `json:"commandline"`
	Signature   string           `json:"signature"`
	Extra       programmer.Extra `json:"extra"`
	Hex         []byte           `json:"hex"`
	Filename    string           `json:"filename"`
	ExtraFiles  []AdditionalFile `json:"extrafiles"`
}

func uploadHandler(c *gin.Context) {
	data := new(Upload)
	c.BindJSON(data)

	log.Printf("%+v", data)

	if data.Port == "" {
		c.String(http.StatusBadRequest, "port is required")
		return
	}

	if data.Board == "" {
		c.String(http.StatusBadRequest, "board is required")
		log.Error("board is required")
		return
	}

	if data.Extra.Network == false {
		if data.Signature == "" {
			c.String(http.StatusBadRequest, "signature is required")
			return
		}

		if data.Commandline == "" {
			c.String(http.StatusBadRequest, "commandline is required for local board")
			return
		}

		err := verifyCommandLine(data.Commandline, data.Signature)

		if err != nil {
			c.String(http.StatusBadRequest, "signature is invalid")
			return
		}
	}

	buffer := bytes.NewBuffer(data.Hex)

	filePath, err := utilities.SaveFileonTempDir(data.Filename, buffer)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		return
	}

	for _, extraFile := range data.ExtraFiles {
		path := filepath.Join(filepath.Dir(filePath), extraFile.Filename)
		log.Printf("Saving %s on %s", extraFile.Filename, path)
		err := ioutil.WriteFile(path, extraFile.Hex, 0644)
		if err != nil {
			log.Printf(err.Error())
		}
	}

	if data.Rewrite != "" {
		data.Board = data.Rewrite
	}

	go func() {
		// Resolve commandline
		commandline, err := programmer.Resolve(data.Port, data.Board, filePath, data.Commandline, data.Extra, &Tools)
		if err != nil {
			send(map[string]string{"ProgrammerStatus": "Error", "Msg": err.Error()})
			return
		}

		l := PLogger{Verbose: data.Extra.Verbose}

		// Upload
		if data.Extra.Network {
			send(map[string]string{"ProgrammerStatus": "Starting", "Cmd": "Network"})
			err = programmer.Network(data.Port, data.Board, filePath, commandline, data.Extra.Auth, l)
		} else {
			send(map[string]string{"ProgrammerStatus": "Starting", "Cmd": "Serial"})
			err = programmer.Serial(data.Port, commandline, data.Extra, l)
		}

		// Handle result
		if err != nil {
			send(map[string]string{"ProgrammerStatus": "Error", "Msg": err.Error()})
			return
		}
		send(map[string]string{"ProgrammerStatus": "Done", "Flash": "Ok"})
	}()

	c.String(http.StatusAccepted, "")
}

// PLogger sends the info from the programmer to the websocket
type PLogger struct {
	Verbose bool
}

// Debug only sends messages if verbose is true
func (l PLogger) Debug(args ...interface{}) {
	if l.Verbose {
		l.Info(args...)
	}
}

// Info always send messages
func (l PLogger) Info(args ...interface{}) {
	output := fmt.Sprint(args...)
	send(map[string]string{"ProgrammerStatus": "Busy", "Msg": output})
}

func send(args map[string]string) {
	mapB, _ := json.Marshal(args)
	h.broadcastSys <- mapB
}

func verifyCommandLine(input string, signature string) error {
	sign, _ := hex.DecodeString(signature)
	block, _ := pem.Decode([]byte(*signatureKey))
	if block == nil {
		return errors.New("invalid key")
	}
	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	rsaKey := key.(*rsa.PublicKey)
	h := sha256.New()
	h.Write([]byte(input))
	d := h.Sum(nil)
	return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, d, sign)
}

func wsHandler() *WsServer {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		c := &connection{send: make(chan []byte, 256*10), ws: so}
		h.register <- c
		so.On("command", func(message string) {
			h.broadcast <- []byte(message)
		})

		so.On("disconnection", func() {
			h.unregister <- c
		})
		go c.writer()
	})
	server.On("error", func(so socketio.Socket, err error) {
		log.Println("error:", err)
	})

	wrapper := WsServer{
		Server: server,
	}

	return &wrapper
}
<|endoftext|>


<commit_before>/*
  core 提供全局可用变量, 方法.
  全局可用的类型定义请
	import "github.com/typepress/core/types"
*/
package core

import (
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"sort"
	"strings"

	. "github.com/typepress/core/types"

	"github.com/achun/tom-toml"
	"github.com/codegangsta/martini"
	"github.com/typepress/accessflags"
	"github.com/typepress/db"
	"github.com/typepress/log"
)

var (
	// global
	Conf       toml.Toml
	Log        log.Loggers
	Db         db.Database
	PWD        string
	AutoRouter = autoRouter
	safeRouter martini.Router // All method, Router.NotFound(NotFound(), SubAny.Handle) already.
	SubGet     martini.Router // GET method only
	SubPut     martini.Router // PUT method only
	SubHead    martini.Router // HEAD method only
	SubPost    martini.Router // POST method only
	SubAjax    martini.Router // POST method only, with head: X-Requested-With "XMLHttpRequest"
	SubPatch   martini.Router // PATCH method only
	SubDelete  martini.Router // DELETE method only
	SubOptions martini.Router // OPTIONS method only
	SubAny     martini.Router // Any method
)

const (
	SessionName    = "TypePression"
	ServerShutDown = "server shutdown"
)

// 默认的 Martini 对象
var safeMartini = martini.New()

// 临时保存 safeMartini 的 handlers
var cacheHandlers = []martini.Handler{}

var started bool

func appStart() bool {
	return started
}

// +dl en
// Handler add handler to builtin *Martini
// +dl

// 给内建 *Martini 对象添加 handler
func Handler(handler ...martini.Handler) {
	if !appStart() {
		cacheHandlers = append(cacheHandlers, handler...)
	}
}

// +dl en
// Martini returns builtin *Martini and master Router.
// call once, returns nil to again.
// +dl

/*
  返回内建 *Martini 和主 Router, 只能调用一次, 再次调用返回 nil.
  参数 handler 会优先于通过 Handler 添加的 handler 执行.
  已经执行过 .Action(Router.Handle)
*/
func Martini(handler ...martini.Handler) (*martini.Martini, martini.Router) {
	if appStart() {
		return nil, nil
	}
	started = true
	safeMartini.Handlers(append(handler, cacheHandlers...)...)
	safeMartini.Action(safeRouter.Handle)
	callInit()
	return safeMartini, safeRouter
}

var notifyMaps map[string][]int
var notifyFn []func(os.Signal) bool

/*
  ListenSignal 为监听 sigs 信号增加执行函数.
  参数:
 	fn 执行函数, 返回值如果是 true, 表示触发后剔除此函数.
 	sigs 为一组要监听的信号, 支持系统信号和自定义信号.
*/
func ListenSignal(fn func(os.Signal) bool, sigs ...os.Signal) {
	if appStart() {
		return
	}
	waitSigs := []os.Signal{}
	for _, sig := range sigs {
		key := sig.String()
		_, ok := notifyMaps[key]
		if !ok {
			notifyMaps[key] = []int{}
			_, ok := sig.(*StringSignal)
			if !ok {
				waitSigs = append(waitSigs, sig)
			}
		}

		i := len(notifyFn)
		notifyMaps[key] = append(notifyMaps[key], i)
		notifyFn = append(notifyFn, fn)
	}
	if len(waitSigs) != 0 {
		go signalNotify(waitSigs)
	}
}

/*
  FireSignal 按照 LIFO 的次序调用 Listen 增加的监听函数.
  如果捕获到 panic 中断调用, 并且监听函数会被剔除.
  参数:
	sig 指示触发信号
	remove 指示触发后是否剔除掉所有的触发函数
*/
func FireSignal(sig os.Signal, remove bool) {
	idx := notifyMaps[sig.String()]
	for i := len(idx); i > 0; {
		i--
		if i >= len(notifyFn) {
			continue
		}
		fn := notifyFn[i]
		if fn == nil {
			continue
		}
		var clear bool
		err := Recover(func() { clear = fn(sig) })
		if remove || clear || err != nil {
			notifyFn[i] = nil
		}
		if err != nil {
			break
		}
	}
}

func signalNotify(sigs []os.Signal) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, sigs...)
	for {
		FireSignal(<-ch, false)
	}
}

// Recover 执行函数 fn, 返回 recover() 结果
func Recover(fn func()) (err interface{}) {
	defer func() {
		err = recover()
	}()
	fn()
	return
}

func init() {
	var err error
	PWD, err = os.Getwd()
	if err != nil {
		panic(err)
	}
	Log = log.Multi().(log.Loggers)
	notifyMaps = map[string][]int{}

	safeRouter = martini.NewRouter()
	SubGet = martini.NewRouter()
	SubPut = martini.NewRouter()
	SubHead = martini.NewRouter()
	SubPost = martini.NewRouter()
	SubAjax = martini.NewRouter()
	SubPatch = martini.NewRouter()
	SubDelete = martini.NewRouter()
	SubOptions = martini.NewRouter()
	SubAny = martini.NewRouter()
	safeRouter.NotFound(subDispatch, SubAny.Handle)
}

// +dl en
// SubDispatch for master Router, auto dispatch SubXxxx router.
// +dl

// SubDispatch 仅用于主 Router, 根据 req.Method 分派子路由.
func SubDispatch() martini.Handler {
	return subDispatch
}

func subDispatch(res http.ResponseWriter, req *http.Request, c martini.Context) {
	switch req.Method {
	case "GET":
		SubGet.Handle(res, req, c)
	case "PUT":
		SubPut.Handle(res, req, c)
	case "HEAD":
		SubHead.Handle(res, req, c)
	case "POST":
		if req.Header.Get("X-Requested-With") == "XMLHttpRequest" {
			SubAjax.Handle(res, req, c)
		} else {
			SubPost.Handle(res, req, c)
		}

	case "PATCH":
		SubPatch.Handle(res, req, c)
	case "DELETE":
		SubDelete.Handle(res, req, c)
	case "OPTIONS":
		SubOptions.Handle(res, req, c)
	}
}

var initfn []func()

func callInit() {
	for _, f := range initfn {
		f()
	}
}

// 注册初始化函数,fn 会在 Martini() 被调用的时候执行.
func RegisterInit(fn ...func()) {
	if appStart() {
		return
	}
	initfn = append(initfn, fn...)
}

var routerMap map[string]martini.Router

func init() {
	routerMap = map[string]martini.Router{
		"GET":     SubGet,
		"PUT":     SubPut,
		"HEAD":    SubHead,
		"POST":    SubPost,
		"AJAX":    SubAjax,
		"PATCH":   SubPatch,
		"DELETE":  SubDelete,
		"DEL":     SubDelete,
		"OPTIONS": SubOptions,
		"OPT":     SubOptions,
		"ANY":     SubAny,
	}
}

// github.com/achun/testing-want_test.ExamplePanic
// github.com/achun/testing-want/GET%2eUd%2edd.ExamplePanic

// 自动注册路由, 不支持本地包, main 包.
// 目前支持来自 github.com 的 package
func autoRouter(pattern string, h ...martini.Handler) {
	const GITHUB = "github.com"
	if appStart() {
		return
	}
	pc, _, _, ok := runtime.Caller(2)
	if !ok {
		return
	}
	name := runtime.FuncForPC(pc).Name()
	names := strings.Split(name, "/")
	if len(names) < 4 || names[0] != GITHUB {
		println("AutoRouter not support:", name)
		os.Exit(1)
		return
	}
	names = names[3:]
	l := len(names) - 1
	pos := strings.LastIndex(names[l], ".")
	if pos != -1 {
		names[l] = names[l][:pos]
	}
	names[l] = strings.Replace(names[l], `%2e`, `.`, -1)
	names = append(names[:l], strings.Split(names[l], `.`)...)
	// fetch role,method
	var roles, methods []string
	for l >= 0 {
		name = names[l]
		if name == strings.ToUpper(name) {
			methods = append(methods, name)
		} else if name != strings.ToLower(name) {
			roles = append(roles, strings.ToLower(name))
		} else {
			l--
			continue
		}
		names = append(names[:l], names[l+1:]...)
		l--
	}

	pattern = "/" + strings.Join(names, "/") + pattern
	if len(roles) != 0 {
		h = append([]martini.Handler{RBAC(roles)}, h...)
	}

	if len(methods) == 0 {
		SubAny.Any(pattern, h...)
		return
	}

	for _, method := range methods {
		r := routerMap[method]
		if r == nil {
			SubAny.Any(pattern, h...)
		} else {
			r.Any(pattern, h...)
		}
	}
}

var rolesAll = []string{}

/*
  RolesSet 设置字符串角色名称集合, 用于角色控制.
  如果要启用角色控制, 必须在注册路由之前进行设置.
  字符串值会被转化为小写, 排序, 剔重.
  为 accessflags 传递 types.Role 值做准备.
*/
func RolesSet(rs ...string) {
	if appStart() {
		return
	}
	rolesAll = filpSlice(append(rolesAll, rs...))
}

func filpSlice(a []string) []string {
	l := len(a)
	if l <= 1 {
		return a
	}

	sort.Sort(sort.StringSlice(a))
	s := 0
	i := 1
	for i < l {
		if a[i] != a[s] {
			s++
			a[s] = a[i]
		}
		i++
	}
	if s > 63 {
		s = 63
	}
	return a[:s+1]
}

// 依据 RolesSet 设置的字符串角色集合对参数 rs 进行计算, 返回 types.Role 值.
func RolesToRole(rs []string) (x Role) {
	rs = filpSlice(rs)
	l := len(rolesAll)
	for _, s := range rs {
		i := sort.SearchStrings(rolesAll, s)
		if i < l && s == rolesAll[i] {
			x = x | 1<<uint(i)
		}
	}
	return x
}

// +dl en
// role-based access control
// +dl

/*
  RBAC 返回用于角色控制的 Handler
  依据 RolesSet 设置的字符串角色集合对参数 rs 进行计算,
  得到 types.Role 值并使用 accessflags 生成 Handler
*/
func RBAC(rs []string) martini.Handler {
	return accessflags.Forbidden(RolesToRole(rs))
}
<commit_msg>fix AutoRouter<commit_after>/*
  core 提供全局可用变量, 方法.
  全局可用的类型定义请
	import "github.com/typepress/core/types"
*/
package core

import (
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"sort"
	"strings"

	. "github.com/typepress/core/types"

	"github.com/achun/tom-toml"
	"github.com/codegangsta/martini"
	"github.com/typepress/accessflags"
	"github.com/typepress/db"
	"github.com/typepress/log"
)

var (
	// global
	Conf       toml.Toml
	Log        log.Loggers
	Db         db.Database
	PWD        string
	safeRouter martini.Router // All method, Router.NotFound(NotFound(), SubAny.Handle) already.
	SubGet     martini.Router // GET method only
	SubPut     martini.Router // PUT method only
	SubHead    martini.Router // HEAD method only
	SubPost    martini.Router // POST method only
	SubAjax    martini.Router // POST method only, with head: X-Requested-With "XMLHttpRequest"
	SubPatch   martini.Router // PATCH method only
	SubDelete  martini.Router // DELETE method only
	SubOptions martini.Router // OPTIONS method only
	SubAny     martini.Router // Any method
)

var (
	AutoRouter       = Autorouter
	PrefixImportPath = FixImportPath
)

const (
	SessionName    = "TypePression"
	ServerShutDown = "server shutdown"
)

// 默认的 Martini 对象
var safeMartini = martini.New()

// 临时保存 safeMartini 的 handlers
var cacheHandlers = []martini.Handler{}

var started bool

func appStart() bool {
	return started
}

// +dl en
// Handler add handler to builtin *Martini
// +dl

// 给内建 *Martini 对象添加 handler
func Handler(handler ...martini.Handler) {
	if !appStart() {
		cacheHandlers = append(cacheHandlers, handler...)
	}
}

// +dl en
// Martini returns builtin *Martini and master Router.
// call once, returns nil to again.
// +dl

/*
  返回内建 *Martini 和主 Router, 只能调用一次, 再次调用返回 nil.
  参数 handler 会优先于通过 Handler 添加的 handler 执行.
  已经执行过 .Action(Router.Handle)
*/
func Martini(handler ...martini.Handler) (*martini.Martini, martini.Router) {
	if appStart() {
		return nil, nil
	}
	started = true
	safeMartini.Handlers(append(handler, cacheHandlers...)...)
	safeMartini.Action(safeRouter.Handle)
	callInit()
	return safeMartini, safeRouter
}

var notifyMaps map[string][]int
var notifyFn []func(os.Signal) bool

/*
  ListenSignal 为监听 sigs 信号增加执行函数.
  参数:
 	fn 执行函数, 返回值如果是 true, 表示触发后剔除此函数.
 	sigs 为一组要监听的信号, 支持系统信号和自定义信号.
*/
func ListenSignal(fn func(os.Signal) bool, sigs ...os.Signal) {
	if appStart() {
		return
	}
	waitSigs := []os.Signal{}
	for _, sig := range sigs {
		key := sig.String()
		_, ok := notifyMaps[key]
		if !ok {
			notifyMaps[key] = []int{}
			_, ok := sig.(*StringSignal)
			if !ok {
				waitSigs = append(waitSigs, sig)
			}
		}

		i := len(notifyFn)
		notifyMaps[key] = append(notifyMaps[key], i)
		notifyFn = append(notifyFn, fn)
	}
	if len(waitSigs) != 0 {
		go signalNotify(waitSigs)
	}
}

/*
  FireSignal 按照 LIFO 的次序调用 Listen 增加的监听函数.
  如果捕获到 panic 中断调用, 并且监听函数会被剔除.
  参数:
	sig 指示触发信号
	remove 指示触发后是否剔除掉所有的触发函数
*/
func FireSignal(sig os.Signal, remove bool) {
	idx := notifyMaps[sig.String()]
	for i := len(idx); i > 0; {
		i--
		if i >= len(notifyFn) {
			continue
		}
		fn := notifyFn[i]
		if fn == nil {
			continue
		}
		var clear bool
		err := Recover(func() { clear = fn(sig) })
		if remove || clear || err != nil {
			notifyFn[i] = nil
		}
		if err != nil {
			break
		}
	}
}

func signalNotify(sigs []os.Signal) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, sigs...)
	for {
		FireSignal(<-ch, false)
	}
}

// Recover 执行函数 fn, 返回 recover() 结果
func Recover(fn func()) (err interface{}) {
	defer func() {
		err = recover()
	}()
	fn()
	return
}

func init() {
	var err error
	PWD, err = os.Getwd()
	if err != nil {
		panic(err)
	}
	Log = log.Multi().(log.Loggers)
	notifyMaps = map[string][]int{}

	safeRouter = martini.NewRouter()
	SubGet = martini.NewRouter()
	SubPut = martini.NewRouter()
	SubHead = martini.NewRouter()
	SubPost = martini.NewRouter()
	SubAjax = martini.NewRouter()
	SubPatch = martini.NewRouter()
	SubDelete = martini.NewRouter()
	SubOptions = martini.NewRouter()
	SubAny = martini.NewRouter()
	safeRouter.NotFound(subDispatch, SubAny.Handle)
}

// +dl en
// SubDispatch for master Router, auto dispatch SubXxxx router.
// +dl

// SubDispatch 仅用于主 Router, 根据 req.Method 分派子路由.
func SubDispatch() martini.Handler {
	return subDispatch
}

func subDispatch(res http.ResponseWriter, req *http.Request, c martini.Context) {
	switch req.Method {
	case "GET":
		SubGet.Handle(res, req, c)
	case "PUT":
		SubPut.Handle(res, req, c)
	case "HEAD":
		SubHead.Handle(res, req, c)
	case "POST":
		if req.Header.Get("X-Requested-With") == "XMLHttpRequest" {
			SubAjax.Handle(res, req, c)
		} else {
			SubPost.Handle(res, req, c)
		}

	case "PATCH":
		SubPatch.Handle(res, req, c)
	case "DELETE":
		SubDelete.Handle(res, req, c)
	case "OPTIONS":
		SubOptions.Handle(res, req, c)
	}
}

var initfn []func()

func callInit() {
	for _, f := range initfn {
		f()
	}
}

// 注册初始化函数,fn 会在 Martini() 被调用的时候执行.
func RegisterInit(fn ...func()) {
	if appStart() {
		return
	}
	initfn = append(initfn, fn...)
}

var routerMap map[string]martini.Router

func init() {
	routerMap = map[string]martini.Router{
		"GET":     SubGet,
		"PUT":     SubPut,
		"HEAD":    SubHead,
		"POST":    SubPost,
		"AJAX":    SubAjax,
		"PATCH":   SubPatch,
		"DELETE":  SubDelete,
		"DEL":     SubDelete,
		"OPTIONS": SubOptions,
		"OPT":     SubOptions,
		"ANY":     SubAny,
	}
}

// 自动注册路由, 不支持本地包, main 包.
// 目前支持来自 github.com 的 package
func Autorouter(pattern string, h ...martini.Handler) {
	if appStart() {
		return
	}
	pc, _, _, ok := runtime.Caller(2)
	if !ok {
		return
	}
	name := runtime.FuncForPC(pc).Name()
	name = strings.Replace(name, `%2e`, `.`, -1)

	names := PrefixImportPath(name)
	if len(names) == 0 {
		println("AutoRouter not support:", name)
		os.Exit(1)
	}

	l := len(names) - 1
	names = append(names[:l], strings.Split(names[l], `.`)...)

	// fetch role,method
	var roles, methods []string

	patterns := ""
	for i := 0; i <= l; i++ {
		name = names[i]
		if name == strings.ToUpper(name) {
			methods = append(methods, name)
			continue
		} else if name != strings.ToLower(name) {
			roles = append(roles, strings.ToLower(name))
			continue
		}
		patterns += "/" + name
	}
	pattern = patterns + pattern

	if len(roles) != 0 {
		h = append([]martini.Handler{RBAC(roles)}, h...)
	}

	if len(methods) == 0 {
		SubAny.Any(pattern, h...)
		return
	}

	for _, method := range methods {
		r := routerMap[method]
		if r == nil {
			SubAny.Any(pattern, h...)
		} else {
			r.Any(pattern, h...)
		}
	}
}

/*
  github.com/user/packagename/path/to/filename.FunctionName
*/

func FixImportPath(name string) []string {
	names := strings.Split(name, "/")
	l := len(names)
	s := names[0]
	switch {
	case "github.com" == s && l > 3:
		return names[3:]
	}
	return nil
}

var rolesAll = []string{}

/*
  RolesSet 设置字符串角色名称集合, 用于角色控制.
  如果要启用角色控制, 必须在注册路由之前进行设置.
  字符串值会被转化为小写, 排序, 剔重.
  为 accessflags 传递 types.Role 值做准备.
*/
func RolesSet(rs ...string) {
	if appStart() {
		return
	}
	rolesAll = filpSlice(append(rolesAll, rs...))
}

func filpSlice(a []string) []string {
	l := len(a)
	if l <= 1 {
		return a
	}

	sort.Sort(sort.StringSlice(a))
	s := 0
	i := 1
	for i < l {
		if a[i] != a[s] {
			s++
			a[s] = a[i]
		}
		i++
	}
	if s > 63 {
		s = 63
	}
	return a[:s+1]
}

// 依据 RolesSet 设置的字符串角色集合对参数 rs 进行计算, 返回 types.Role 值.
func RolesToRole(rs []string) (x Role) {
	rs = filpSlice(rs)
	l := len(rolesAll)
	for _, s := range rs {
		i := sort.SearchStrings(rolesAll, s)
		if i < l && s == rolesAll[i] {
			x = x | 1<<uint(i)
		}
	}
	return x
}

// +dl en
// role-based access control
// +dl

/*
  RBAC 返回用于角色控制的 Handler
  依据 RolesSet 设置的字符串角色集合对参数 rs 进行计算,
  得到 types.Role 值并使用 accessflags 生成 Handler
*/
func RBAC(rs []string) martini.Handler {
	return accessflags.Forbidden(RolesToRole(rs))
}
<|endoftext|>


<commit_before>package rc2

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func TestEncryptDecrypt(t *testing.T) {

	// TODO(dgryski): add the rest of the test vectors from the RFC
	var tests = []struct {
		key    string
		plain  string
		cipher string
		t1     int
	}{
		{
			"0000000000000000",
			"0000000000000000",
			"ebb773f993278eff",
			63,
		},
		{
			"ffffffffffffffff",
			"ffffffffffffffff",
			"278b27e42e2f0d49",
			64,
		},
		{
			"3000000000000000",
			"1000000000000001",
			"30649edf9be7d2c2",
			64,
		},
		{
			"88",
			"0000000000000000",
			"61a8a244adacccf0",
			64,
		},
		{
			"88bca90e90875a",
			"0000000000000000",
			"6ccf4308974c267f",
			64,
		},
		{
			"88bca90e90875a7f0f79c384627bafb2",
			"0000000000000000",
			"1a807d272bbe5db1",
			64,
		},
		{
			"88bca90e90875a7f0f79c384627bafb2",
			"0000000000000000",
			"2269552ab0f85ca6",
			128,
		},
		{
			"88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e",
			"0000000000000000",
			"5b78d3a43dfff1f1",
			129,
		},
	}

	for _, tt := range tests {
		k, _ := hex.DecodeString(tt.key)
		p, _ := hex.DecodeString(tt.plain)
		c, _ := hex.DecodeString(tt.cipher)

		b, _ := New(k, tt.t1)

		var dst [8]byte

		b.Encrypt(dst[:], p)

		if !bytes.Equal(dst[:], c) {
			t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c)
		}

		b.Decrypt(dst[:], c)

		if !bytes.Equal(dst[:], p) {
			t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p)
		}
	}
}
<commit_msg>todos--<commit_after>package rc2

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func TestEncryptDecrypt(t *testing.T) {

	var tests = []struct {
		key    string
		plain  string
		cipher string
		t1     int
	}{
		{
			"0000000000000000",
			"0000000000000000",
			"ebb773f993278eff",
			63,
		},
		{
			"ffffffffffffffff",
			"ffffffffffffffff",
			"278b27e42e2f0d49",
			64,
		},
		{
			"3000000000000000",
			"1000000000000001",
			"30649edf9be7d2c2",
			64,
		},
		{
			"88",
			"0000000000000000",
			"61a8a244adacccf0",
			64,
		},
		{
			"88bca90e90875a",
			"0000000000000000",
			"6ccf4308974c267f",
			64,
		},
		{
			"88bca90e90875a7f0f79c384627bafb2",
			"0000000000000000",
			"1a807d272bbe5db1",
			64,
		},
		{
			"88bca90e90875a7f0f79c384627bafb2",
			"0000000000000000",
			"2269552ab0f85ca6",
			128,
		},
		{
			"88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e",
			"0000000000000000",
			"5b78d3a43dfff1f1",
			129,
		},
	}

	for _, tt := range tests {
		k, _ := hex.DecodeString(tt.key)
		p, _ := hex.DecodeString(tt.plain)
		c, _ := hex.DecodeString(tt.cipher)

		b, _ := New(k, tt.t1)

		var dst [8]byte

		b.Encrypt(dst[:], p)

		if !bytes.Equal(dst[:], c) {
			t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c)
		}

		b.Decrypt(dst[:], c)

		if !bytes.Equal(dst[:], p) {
			t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p)
		}
	}
}
<|endoftext|>


<commit_before>package server

import (
	"sync"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/admin"
	"github.com/pachyderm/pachyderm/src/server/pkg/log"
)

type apiServer struct {
	log.Logger
	address        string
	pachClient     *client.APIClient
	pachClientOnce sync.Once
}

func (a *apiServer) Extract(request *admin.ExtractRequest, extractServer admin.API_ExtractServer) error {
	return nil
}

func (a *apiServer) Restore(restoreServer admin.API_RestoreServer) error {
	return nil
}

func (a *apiServer) getPachClient() (*client.APIClient, error) {
	if a.pachClient == nil {
		var onceErr error
		a.pachClientOnce.Do(func() {
			a.pachClient, onceErr = client.NewFromAddress(a.address)
		})
		if onceErr != nil {
			return nil, onceErr
		}
	}
	return a.pachClient, nil
}
<commit_msg>Adds extraction for repos.<commit_after>package server

import (
	"sync"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/admin"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/server/pkg/log"
)

type apiServer struct {
	log.Logger
	address        string
	pachClient     *client.APIClient
	pachClientOnce sync.Once
}

func (a *apiServer) Extract(request *admin.ExtractRequest, extractServer admin.API_ExtractServer) error {
	pachClient, err := a.getPachClient()
	if err != nil {
		return err
	}
	repos, err := pachClient.ListRepo(nil)
	for _, repoInfo := range repos {
		if err := extractServer.Send(&admin.Op{
			Repo: &pfs.CreateRepoRequest{
				Repo:        repoInfo.Repo,
				Provenance:  repoInfo.Provenance,
				Description: repoInfo.Description,
			},
		}); err != nil {
			return err
		}
	}
	return nil
}

func (a *apiServer) Restore(restoreServer admin.API_RestoreServer) error {
	return nil
}

func (a *apiServer) getPachClient() (*client.APIClient, error) {
	if a.pachClient == nil {
		var onceErr error
		a.pachClientOnce.Do(func() {
			a.pachClient, onceErr = client.NewFromAddress(a.address)
		})
		if onceErr != nil {
			return nil, onceErr
		}
	}
	return a.pachClient, nil
}
<|endoftext|>


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

// Package cfgmatcher efficiently matches a CL to 0+ ConfigGroupID for a single
// LUCI project.
package cfgmatcher

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	"google.golang.org/protobuf/proto"

	"go.chromium.org/luci/common/errors"

	cfgpb "go.chromium.org/luci/cv/api/config/v2"
	"go.chromium.org/luci/cv/internal/config"
)

// Matcher effieciently find matching ConfigGroupID for Gerrit CLs.
type Matcher struct {
	state                *MatcherState
	cachedConfigGroupIDs []config.ConfigGroupID
}

// LoadMatcher instantiates Matcher from config stored in Datastore.
func LoadMatcher(ctx context.Context, luciProject, configHash string) (*Matcher, error) {
	meta, err := config.GetHashMeta(ctx, luciProject, configHash)
	if err != nil {
		return nil, err
	}
	configGroups, err := meta.GetConfigGroups(ctx)
	if err != nil {
		return nil, err
	}
	m := &Matcher{
		state: &MatcherState{
			// 1-2 Gerrit hosts is typical as of 2020.
			Hosts:            make(map[string]*MatcherState_Projects, 2),
			ConfigGroupNames: make([]string, len(configGroups)),
			ConfigHash:       configHash,
		},
		cachedConfigGroupIDs: meta.ConfigGroupIDs,
	}
	for i, cg := range configGroups {
		m.state.ConfigGroupNames[i] = cg.ID.Name()
		for _, gerrit := range cg.Content.GetGerrit() {
			host := config.GerritHost(gerrit)
			var projectsMap map[string]*Groups
			if ps, ok := m.state.GetHosts()[host]; ok {
				projectsMap = ps.GetProjects()
			} else {
				// Either 1 Gerrit project or lots of them is typical as 2020.
				projectsMap = make(map[string]*Groups, 1)
				m.state.GetHosts()[host] = &MatcherState_Projects{Projects: projectsMap}
			}

			for _, p := range gerrit.GetProjects() {
				g := MakeGroup(cg, p)
				// Don't store exact ID, it can be computed from the rest of matcher
				// state if index is known. This reduces RAM usage after
				// serialize/deserialize cycle.
				g.Id = ""
				g.Index = int32(i)
				if groups, ok := projectsMap[p.GetName()]; ok {
					groups.Groups = append(groups.GetGroups(), g)
				} else {
					projectsMap[p.GetName()] = &Groups{Groups: []*Group{g}}
				}
			}
		}
	}
	return m, nil
}

func (m *Matcher) Serialize() ([]byte, error) {
	return proto.Marshal(m.state)
}

func Deserialize(buf []byte) (*Matcher, error) {
	m := &Matcher{state: &MatcherState{}}
	if err := proto.Unmarshal(buf, m.state); err != nil {
		return nil, errors.Annotate(err, "failed to Deserialize Matcher").Err()
	}
	m.cachedConfigGroupIDs = make([]config.ConfigGroupID, len(m.state.ConfigGroupNames))
	hash := m.state.GetConfigHash()
	for i, name := range m.state.ConfigGroupNames {
		m.cachedConfigGroupIDs[i] = config.MakeConfigGroupID(hash, name)
	}
	return m, nil
}

// Match returns ConfigGroupIDs matched for a given triple.
func (m *Matcher) Match(host, project, ref string) []config.ConfigGroupID {
	ps, ok := m.state.GetHosts()[host]
	if !ok {
		return nil
	}
	gs, ok := ps.GetProjects()[project]
	if !ok {
		return nil
	}
	matched := gs.Match(ref)
	if len(matched) == 0 {
		return nil
	}
	ret := make([]config.ConfigGroupID, len(matched))
	for i, g := range matched {
		ret[i] = m.cachedConfigGroupIDs[g.GetIndex()]
	}
	return ret
}

// TODO(tandrii): add "main" branch too to ease migration once either:
//   * CQDaemon is no longer involved,
//   * CQDaemon does the same at the same time.
var defaultRefRegexpInclude = []string{"refs/heads/master"}
var defaultRefRegexpExclude = []string{"^$" /* matches nothing */}

// MakeGroup returns a new Group based on the Gerrit Project section of a
// ConfigGroup.
func MakeGroup(g *config.ConfigGroup, p *cfgpb.ConfigGroup_Gerrit_Project) *Group {
	var inc, exc []string
	if inc = p.GetRefRegexp(); len(inc) == 0 {
		inc = defaultRefRegexpInclude
	}
	if exc = p.GetRefRegexpExclude(); len(exc) == 0 {
		exc = defaultRefRegexpExclude
	}
	return &Group{
		Id:       string(g.ID),
		Include:  disjunctiveOfRegexps(inc),
		Exclude:  disjunctiveOfRegexps(exc),
		Fallback: g.Content.Fallback == cfgpb.Toggle_YES,
	}
}

// Match returns matching groups, obeying fallback config.
//
// If there are two groups that match, one fallback and one non-fallback, the
// non-fallback group is the one to use. The fallback group will be used if it's
// the only group that matches.
func (gs *Groups) Match(ref string) []*Group {
	var ret []*Group
	var fallback *Group
	for _, g := range gs.GetGroups() {
		switch {
		case !g.Match(ref):
			continue
		case g.GetFallback() && fallback != nil:
			// Valid config require at most 1 fallback group in a LUCI project.
			panic(fmt.Errorf("invalid Groups: %s and %s are both fallback", fallback, g))
		case g.GetFallback():
			fallback = g
		default:
			ret = append(ret, g)
		}
	}
	if len(ret) == 0 && fallback != nil {
		ret = []*Group{fallback}
	}
	return ret
}

// Match returns true iff ref matches given Group.
func (g *Group) Match(ref string) bool {
	if !regexp.MustCompile(g.GetInclude()).MatchString(ref) {
		return false
	}
	return !regexp.MustCompile(g.GetExclude()).MatchString(ref)
}

// matchesAny returns true iff s matches any of the patterns.
//
// It is assumed that all patterns have been pre-validated and
// are valid regexps.
func matchesAny(patterns []string, s string) bool {
	for _, pattern := range patterns {
		if regexp.MustCompile(pattern).MatchString(s) {
			return true
		}
	}
	return false
}

func disjunctiveOfRegexps(rs []string) string {
	sb := strings.Builder{}
	sb.WriteString("^(")
	for i, r := range rs {
		if i > 0 {
			sb.WriteRune('|')
		}
		sb.WriteRune('(')
		sb.WriteString(r)
		sb.WriteRune(')')
	}
	sb.WriteString(")$")
	return sb.String()
}
<commit_msg>cv: add Matcher.ConfigHash() method.<commit_after>// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package cfgmatcher efficiently matches a CL to 0+ ConfigGroupID for a single
// LUCI project.
package cfgmatcher

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	"google.golang.org/protobuf/proto"

	"go.chromium.org/luci/common/errors"

	cfgpb "go.chromium.org/luci/cv/api/config/v2"
	"go.chromium.org/luci/cv/internal/config"
)

// Matcher effieciently find matching ConfigGroupID for Gerrit CLs.
type Matcher struct {
	state                *MatcherState
	cachedConfigGroupIDs []config.ConfigGroupID
}

// LoadMatcher instantiates Matcher from config stored in Datastore.
func LoadMatcher(ctx context.Context, luciProject, configHash string) (*Matcher, error) {
	meta, err := config.GetHashMeta(ctx, luciProject, configHash)
	if err != nil {
		return nil, err
	}
	configGroups, err := meta.GetConfigGroups(ctx)
	if err != nil {
		return nil, err
	}
	m := &Matcher{
		state: &MatcherState{
			// 1-2 Gerrit hosts is typical as of 2020.
			Hosts:            make(map[string]*MatcherState_Projects, 2),
			ConfigGroupNames: make([]string, len(configGroups)),
			ConfigHash:       configHash,
		},
		cachedConfigGroupIDs: meta.ConfigGroupIDs,
	}
	for i, cg := range configGroups {
		m.state.ConfigGroupNames[i] = cg.ID.Name()
		for _, gerrit := range cg.Content.GetGerrit() {
			host := config.GerritHost(gerrit)
			var projectsMap map[string]*Groups
			if ps, ok := m.state.GetHosts()[host]; ok {
				projectsMap = ps.GetProjects()
			} else {
				// Either 1 Gerrit project or lots of them is typical as 2020.
				projectsMap = make(map[string]*Groups, 1)
				m.state.GetHosts()[host] = &MatcherState_Projects{Projects: projectsMap}
			}

			for _, p := range gerrit.GetProjects() {
				g := MakeGroup(cg, p)
				// Don't store exact ID, it can be computed from the rest of matcher
				// state if index is known. This reduces RAM usage after
				// serialize/deserialize cycle.
				g.Id = ""
				g.Index = int32(i)
				if groups, ok := projectsMap[p.GetName()]; ok {
					groups.Groups = append(groups.GetGroups(), g)
				} else {
					projectsMap[p.GetName()] = &Groups{Groups: []*Group{g}}
				}
			}
		}
	}
	return m, nil
}

func (m *Matcher) Serialize() ([]byte, error) {
	return proto.Marshal(m.state)
}

func Deserialize(buf []byte) (*Matcher, error) {
	m := &Matcher{state: &MatcherState{}}
	if err := proto.Unmarshal(buf, m.state); err != nil {
		return nil, errors.Annotate(err, "failed to Deserialize Matcher").Err()
	}
	m.cachedConfigGroupIDs = make([]config.ConfigGroupID, len(m.state.ConfigGroupNames))
	hash := m.state.GetConfigHash()
	for i, name := range m.state.ConfigGroupNames {
		m.cachedConfigGroupIDs[i] = config.MakeConfigGroupID(hash, name)
	}
	return m, nil
}

// Match returns ConfigGroupIDs matched for a given triple.
func (m *Matcher) Match(host, project, ref string) []config.ConfigGroupID {
	ps, ok := m.state.GetHosts()[host]
	if !ok {
		return nil
	}
	gs, ok := ps.GetProjects()[project]
	if !ok {
		return nil
	}
	matched := gs.Match(ref)
	if len(matched) == 0 {
		return nil
	}
	ret := make([]config.ConfigGroupID, len(matched))
	for i, g := range matched {
		ret[i] = m.cachedConfigGroupIDs[g.GetIndex()]
	}
	return ret
}

// ConfigHash returns ConfigHash for which Matcher does matching.
func (m *Matcher) ConfigHash() string {
	return m.state.GetConfigHash()
}

// TODO(tandrii): add "main" branch too to ease migration once either:
//   * CQDaemon is no longer involved,
//   * CQDaemon does the same at the same time.
var defaultRefRegexpInclude = []string{"refs/heads/master"}
var defaultRefRegexpExclude = []string{"^$" /* matches nothing */}

// MakeGroup returns a new Group based on the Gerrit Project section of a
// ConfigGroup.
func MakeGroup(g *config.ConfigGroup, p *cfgpb.ConfigGroup_Gerrit_Project) *Group {
	var inc, exc []string
	if inc = p.GetRefRegexp(); len(inc) == 0 {
		inc = defaultRefRegexpInclude
	}
	if exc = p.GetRefRegexpExclude(); len(exc) == 0 {
		exc = defaultRefRegexpExclude
	}
	return &Group{
		Id:       string(g.ID),
		Include:  disjunctiveOfRegexps(inc),
		Exclude:  disjunctiveOfRegexps(exc),
		Fallback: g.Content.Fallback == cfgpb.Toggle_YES,
	}
}

// Match returns matching groups, obeying fallback config.
//
// If there are two groups that match, one fallback and one non-fallback, the
// non-fallback group is the one to use. The fallback group will be used if it's
// the only group that matches.
func (gs *Groups) Match(ref string) []*Group {
	var ret []*Group
	var fallback *Group
	for _, g := range gs.GetGroups() {
		switch {
		case !g.Match(ref):
			continue
		case g.GetFallback() && fallback != nil:
			// Valid config require at most 1 fallback group in a LUCI project.
			panic(fmt.Errorf("invalid Groups: %s and %s are both fallback", fallback, g))
		case g.GetFallback():
			fallback = g
		default:
			ret = append(ret, g)
		}
	}
	if len(ret) == 0 && fallback != nil {
		ret = []*Group{fallback}
	}
	return ret
}

// Match returns true iff ref matches given Group.
func (g *Group) Match(ref string) bool {
	if !regexp.MustCompile(g.GetInclude()).MatchString(ref) {
		return false
	}
	return !regexp.MustCompile(g.GetExclude()).MatchString(ref)
}

// matchesAny returns true iff s matches any of the patterns.
//
// It is assumed that all patterns have been pre-validated and
// are valid regexps.
func matchesAny(patterns []string, s string) bool {
	for _, pattern := range patterns {
		if regexp.MustCompile(pattern).MatchString(s) {
			return true
		}
	}
	return false
}

func disjunctiveOfRegexps(rs []string) string {
	sb := strings.Builder{}
	sb.WriteString("^(")
	for i, r := range rs {
		if i > 0 {
			sb.WriteRune('|')
		}
		sb.WriteRune('(')
		sb.WriteString(r)
		sb.WriteRune(')')
	}
	sb.WriteString(")$")
	return sb.String()
}
<|endoftext|>