<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// e2e.go runs the e2e test suite. No non-standard package dependencies; call with "go run".
package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
)

var (
	isup    = flag.Bool("isup", false, "Check to see if the e2e cluster is up, then exit.")
	build   = flag.Bool("build", false, "If true, build a new release. Otherwise, use whatever is there.")
	up      = flag.Bool("up", false, "If true, start the the e2e cluster. If cluster is already up, recreate it.")
	push    = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
	down    = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
	test    = flag.Bool("test", false, "Run all tests in hack/e2e-suite.")
	tests   = flag.String("tests", "", "Run only tests in hack/e2e-suite matching this glob. Ignored if -test is set.")
	root    = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
	verbose = flag.Bool("v", false, "If true, print all command output.")

	cfgCmd = flag.String("cfg", "", "If nonempty, pass this as an argument, and call kubecfg. Implies -v.")
	ctlCmd = flag.String("ctl", "", "If nonempty, pass this as an argument, and call kubectl. Implies -v. (-test, -cfg, -ctl are mutually exclusive)")
)

var signals = make(chan os.Signal, 100)

func absOrDie(path string) string {
	out, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}
	return out
}

func main() {
	flag.Parse()
	signal.Notify(signals, os.Interrupt)

	if *test {
		*tests = "*"
	}

	if *isup {
		status := 1
		if runBash("get status", `$KUBECFG -server_version`) {
			status = 0
			log.Printf("Cluster is UP")
		} else {
			log.Printf("Cluster is DOWN")
		}
		os.Exit(status)
	}

	if *build {
		if !runBash("build-release", `test-build-release`) {
			log.Fatal("Error building. Aborting.")
		}
	}

	if *up {
		if !Up() {
			log.Fatal("Error starting e2e cluster. Aborting.")
		}
	} else if *push {
		if !runBash("push", path.Join(*root, "/cluster/kube-push.sh")) {
			log.Fatal("Error pushing e2e cluster. Aborting.")
		}
	}

	failure := false
	switch {
	case *cfgCmd != "":
		failure = !runBash("'kubecfg "+*cfgCmd+"'", "$KUBECFG "+*cfgCmd)
	case *ctlCmd != "":
		failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECFG "+*ctlCmd)
	case *tests != "":
		failed, passed := Test()
		log.Printf("Passed tests: %v", passed)
		log.Printf("Failed tests: %v", failed)
		failure = len(failed) > 0
	}

	if *down {
		TearDown()
	}

	if failure {
		os.Exit(1)
	}
}

func TearDown() {
	runBash("teardown", "test-teardown")
}

func Up() bool {
	if !tryUp() {
		log.Printf("kube-up failed; will tear down and retry. (Possibly your cluster was in some partially created state?)")
		TearDown()
		return tryUp()
	}
	return true
}

func tryUp() bool {
	return runBash("up", path.Join(*root, "/cluster/kube-up.sh; test-setup;"))
}

func Test() (failed, passed []string) {
	// run tests!
	dir, err := os.Open(filepath.Join(*root, "hack", "e2e-suite"))
	if err != nil {
		log.Fatal("Couldn't open e2e-suite dir")
	}
	defer dir.Close()
	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatal("Couldn't read names in e2e-suite dir")
	}

	for i := range names {
		name := names[i]
		if name == "." || name == ".." {
			continue
		}
		if match, err := path.Match(*tests, name); !match && err == nil {
			continue
		}
		absName := filepath.Join(*root, "hack", "e2e-suite", name)
		log.Printf("%v matches %v. Starting test.", name, *tests)
		if runBash(name, absName) {
			log.Printf("%v passed", name)
			passed = append(passed, name)
		} else {
			log.Printf("%v failed", name)
			failed = append(failed, name)
		}
	}

	return
}

// All nonsense below is temporary until we have go versions of these things.

func runBash(stepName, bashFragment string) bool {
	cmd := exec.Command("bash", "-s")
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	return finishRunning(stepName, cmd)
}

func run(stepName, cmdPath string) bool {
	return finishRunning(stepName, exec.Command(filepath.Join(*root, cmdPath)))
}

func finishRunning(stepName string, cmd *exec.Cmd) bool {
	log.Printf("Running: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	if *verbose {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = stdout
		cmd.Stderr = stderr
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		for {
			select {
			case <-done:
				return
			case s := <-signals:
				cmd.Process.Signal(s)
			}
		}
	}()

	if err := cmd.Run(); err != nil {
		log.Printf("Error running %v: %v", stepName, err)
		if !*verbose {
			fmt.Printf("stdout:\n------\n%v\n------\n", string(stdout.Bytes()))
			fmt.Printf("stderr:\n------\n%v\n------\n", string(stderr.Bytes()))
		}
		return false
	}
	return true
}

var bashCommandPrefix = `
set -o errexit
set -o nounset
set -o pipefail

export KUBE_CONFIG_FILE="config-test.sh"

# TODO(jbeda): This will break on usage if there is a space in
# ${KUBE_ROOT}.  Covert to an array?  Or an exported function?
export KUBECFG="` + *root + `/cluster/kubecfg.sh -expect_version_match"

source "` + *root + `/cluster/kube-env.sh"
source "` + *root + `/cluster/${KUBERNETES_PROVIDER}/util.sh"

if [[ ${KUBERNETES_PROVIDER} == "gce" ]]; then
  detect-project
fi

`

var bashCommandSuffix = `

`

func bashWrap(cmd string) string {
	return bashCommandPrefix + cmd + bashCommandSuffix
}
<commit_msg>Actually let hack/e2e.go run kubectl<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// e2e.go runs the e2e test suite. No non-standard package dependencies; call with "go run".
package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
)

var (
	isup             = flag.Bool("isup", false, "Check to see if the e2e cluster is up, then exit.")
	build            = flag.Bool("build", false, "If true, build a new release. Otherwise, use whatever is there.")
	up               = flag.Bool("up", false, "If true, start the the e2e cluster. If cluster is already up, recreate it.")
	push             = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
	down             = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
	test             = flag.Bool("test", false, "Run all tests in hack/e2e-suite.")
	tests            = flag.String("tests", "", "Run only tests in hack/e2e-suite matching this glob. Ignored if -test is set.")
	root             = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
	verbose          = flag.Bool("v", false, "If true, print all command output.")
	checkVersionSkew = flag.Bool("check_version_skew", true, ""+
		"By default, verify that client and server have exact version match. "+
		"You can explicitly set to false if you're, e.g., testing client changes "+
		"for which the server version doesn't make a difference.")

	cfgCmd = flag.String("cfg", "", "If nonempty, pass this as an argument, and call kubecfg. Implies -v.")
	ctlCmd = flag.String("ctl", "", "If nonempty, pass this as an argument, and call kubectl. Implies -v. (-test, -cfg, -ctl are mutually exclusive)")
)

var signals = make(chan os.Signal, 100)

func absOrDie(path string) string {
	out, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}
	return out
}

func main() {
	flag.Parse()
	signal.Notify(signals, os.Interrupt)

	if *test {
		*tests = "*"
	}

	if *isup {
		status := 1
		if runBash("get status", `$KUBECFG -server_version`) {
			status = 0
			log.Printf("Cluster is UP")
		} else {
			log.Printf("Cluster is DOWN")
		}
		os.Exit(status)
	}

	if *build {
		if !runBash("build-release", `test-build-release`) {
			log.Fatal("Error building. Aborting.")
		}
	}

	if *up {
		if !Up() {
			log.Fatal("Error starting e2e cluster. Aborting.")
		}
	} else if *push {
		if !runBash("push", path.Join(*root, "/cluster/kube-push.sh")) {
			log.Fatal("Error pushing e2e cluster. Aborting.")
		}
	}

	failure := false
	switch {
	case *cfgCmd != "":
		failure = !runBash("'kubecfg "+*cfgCmd+"'", "$KUBECFG "+*cfgCmd)
	case *ctlCmd != "":
		failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECTL "+*ctlCmd)
	case *tests != "":
		failed, passed := Test()
		log.Printf("Passed tests: %v", passed)
		log.Printf("Failed tests: %v", failed)
		failure = len(failed) > 0
	}

	if *down {
		TearDown()
	}

	if failure {
		os.Exit(1)
	}
}

func TearDown() {
	runBash("teardown", "test-teardown")
}

func Up() bool {
	if !tryUp() {
		log.Printf("kube-up failed; will tear down and retry. (Possibly your cluster was in some partially created state?)")
		TearDown()
		return tryUp()
	}
	return true
}

func tryUp() bool {
	return runBash("up", path.Join(*root, "/cluster/kube-up.sh; test-setup;"))
}

func Test() (failed, passed []string) {
	// run tests!
	dir, err := os.Open(filepath.Join(*root, "hack", "e2e-suite"))
	if err != nil {
		log.Fatal("Couldn't open e2e-suite dir")
	}
	defer dir.Close()
	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatal("Couldn't read names in e2e-suite dir")
	}

	for i := range names {
		name := names[i]
		if name == "." || name == ".." {
			continue
		}
		if match, err := path.Match(*tests, name); !match && err == nil {
			continue
		}
		absName := filepath.Join(*root, "hack", "e2e-suite", name)
		log.Printf("%v matches %v. Starting test.", name, *tests)
		if runBash(name, absName) {
			log.Printf("%v passed", name)
			passed = append(passed, name)
		} else {
			log.Printf("%v failed", name)
			failed = append(failed, name)
		}
	}

	return
}

// All nonsense below is temporary until we have go versions of these things.

func runBash(stepName, bashFragment string) bool {
	cmd := exec.Command("bash", "-s")
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	return finishRunning(stepName, cmd)
}

func run(stepName, cmdPath string) bool {
	return finishRunning(stepName, exec.Command(filepath.Join(*root, cmdPath)))
}

func finishRunning(stepName string, cmd *exec.Cmd) bool {
	log.Printf("Running: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	if *verbose {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = stdout
		cmd.Stderr = stderr
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		for {
			select {
			case <-done:
				return
			case s := <-signals:
				cmd.Process.Signal(s)
			}
		}
	}()

	if err := cmd.Run(); err != nil {
		log.Printf("Error running %v: %v", stepName, err)
		if !*verbose {
			fmt.Printf("stdout:\n------\n%v\n------\n", string(stdout.Bytes()))
			fmt.Printf("stderr:\n------\n%v\n------\n", string(stderr.Bytes()))
		}
		return false
	}
	return true
}

// returns either "", or a list of args intended for appending with the
// kubecfg or kubectl commands (begining with a space).
func kubeClientArgs() string {
	if *checkVersionSkew {
		return " -expect_version_match"
	}
	return ""
}

func bashWrap(cmd string) string {
	return `
set -o errexit
set -o nounset
set -o pipefail

export KUBE_CONFIG_FILE="config-test.sh"

# TODO(jbeda): This will break on usage if there is a space in
# ${KUBE_ROOT}.  Covert to an array?  Or an exported function?
export KUBECFG="` + *root + `/cluster/kubecfg.sh` + kubeClientArgs() + `"
export KUBECTL="` + *root + `/cluster/kubectl.sh` + kubeClientArgs() + `"

source "` + *root + `/cluster/kube-env.sh"
source "` + *root + `/cluster/${KUBERNETES_PROVIDER}/util.sh"

if [[ ${KUBERNETES_PROVIDER} == "gce" ]]; then
  detect-project
fi

` + cmd + `
`
}
<|endoftext|>


<commit_before>/*
Package handlers is a small library of utility http handlers that are useful
for building web applications. It includes a NotFoundHandler, an ErrorHandler,
and a FileHandler.

The NotFoundHandler and ErrorHandler provide a simple way to respond to the
client with custom 404 and 500 status pages: create your own application
specific error page templates and call each of the handler's Serve methods
with the appropriate arguments.

These two handlers are intended to be used indirectly, from inside other
handlers where server errors or page not found errors occur and you need
to report them to the browser. However, both of these types implement the
http.Handler interface with a ServeHTTP method, which shows their default
behaviour when bound to a specific route.

The FileHandler provides similar functionality to the FileServer in the
net/http package, but with two differences: it will not show directory
listings for directories under its path, and it will respond to any request
for a non-existent file with the given NotFoundHandler.
*/
package handlers

import (
	"bytes"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// ErrorMessage holds the message passed to the error template. The template
// can access the message field with the {{.ErrorMessage}} tag.
type ErrorMessage struct {
	ErrorMessage string
}

// ErrorHandler serves error messages with the given template. The template
// can access the message served by the handler with the {{.ErrorMessage}} tag.
type ErrorHandler struct {
	template       *template.Template
	defaultMessage string
	displayErrors  bool
}

// NewErrorHandler returns a new ErrorHandler with the handler values initialised.
// The handler uses the given template to print an error message. The template
// must display {{.ErrorMessage}}. The default error message is set to message.
// The display argument controls whether error messages passed to the handler's
// ServeError function are shown to the user on the error page, or whether the
// default error message is shown instead. This allows detailed error messages
// to be printed to the screen during development, but turned off in production.
// The handler's AlwaysServeError method forces the display of a particular
// error message even if displayErrors is set to false.
func NewErrorHandler(template *template.Template, defaultMessage string, displayErrors bool) *ErrorHandler {

	return &ErrorHandler{
		template:       template,
		defaultMessage: defaultMessage,
		displayErrors:  displayErrors,
	}
}

// LoadErrorHandler is a convenience function that returns a new ErrorHandler
// using the template file specified by templatePath. The function first loads
// the template and then creates the ErrorHandler using NewErrorHandler.
func LoadErrorHandler(templatePath string, defaultMessage string, displayErrors bool) *ErrorHandler {

	template, err := template.ParseFiles(templatePath)

	if err != nil {
		log.Fatal(err)
	}

	return NewErrorHandler(template, defaultMessage, displayErrors)
}

// ServeError serves the appropriate error message in the error template
// depending on the value of displayErrors. If displayErrors is true then
// the given message is shown, otherwise the default error message is shown.
func (h *ErrorHandler) ServeError(w http.ResponseWriter, message string) {

	var (
		templateData *ErrorMessage
		buffer       bytes.Buffer
	)

	if h.displayErrors {

		templateData = &ErrorMessage{message}

	} else {

		templateData = &ErrorMessage{h.defaultMessage}
	}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fall back to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// AlwaysServeError serves the given error message in the error template.
// This method overrides the default error message, irrespective of whether
// displayErrors is false, and ensures that the given message is always shown.
func (h *ErrorHandler) AlwaysServeError(w http.ResponseWriter, message string) {

	var buffer bytes.Buffer
	templateData := &ErrorMessage{message}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fall back to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// ServeHTTP serves the default error message in the error template.
func (h *ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var buffer bytes.Buffer
	templateData := &ErrorMessage{h.defaultMessage}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fallback to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// NotFoundData holds the path passed to the handler's template. The template
// can access the message field with the {{.Path}} tag.
type NotFoundData struct {
	Path string
}

// NotFoundHandler serves a 404 with the given template. The template
// can access the path to the file not found with {{.Path}} tag.
type NotFoundHandler struct {
	template *template.Template
}

// NewNotFoundHandler returns a new NotFoundHandler with the handler values
// initialised. The handler uses the given template to print the path to the
// file not found with a 404. The template must display {{.Path}}.
func NewNotFoundHandler(template *template.Template) *NotFoundHandler {

	return &NotFoundHandler{
		template: template,
	}
}

// LoadNotFoundHandler is a convenience function that returns a new NotFoundHandler
// using the template file specified by templatePath. The function first loads the
// template and then creates the NotFoundHandler using NewNotFoundHandler.
func LoadNotFoundHandler(templatePath string) *NotFoundHandler {

	template, err := template.ParseFiles(templatePath)

	if err != nil {
		log.Fatal(err)
	}

	return NewNotFoundHandler(template)
}

// ServeHTTP serves the path in the handler's template.
func (h *NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var buffer bytes.Buffer
	templateData := &NotFoundData{r.URL.Path}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, report it with the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the 404 in the not found template
	w.WriteHeader(http.StatusNotFound)
	buffer.WriteTo(w)
	return
}

// FileHandler serves files requested under the given url path from the given
// directory. The url path should be the same as the path to which the handler
// is bound with http.Handle. If the file is not found the handler serves a 404
// using the given notFoundHandler. The notFoundHandler can be any Handler, but
// its ServeHTTP method should return a 404. Unlike Go's built-in FileServer,
// FileHandler will not return directory listings for directories without an
// index.html and will instead respond with a 404.
type FileHandler struct {
	urlPath         string
	directory       string
	notFoundHandler http.Handler
}

// NewFileHandler returns a new FileHandler with the handler values initialised.
func NewFileHandler(urlPath string, directory string, notFoundHandler http.Handler) *FileHandler {

	return &FileHandler{
		urlPath:         urlPath,
		directory:       directory,
		notFoundHandler: notFoundHandler,
	}
}

// ServeHTTP is a wrapper around http.ServeFile, with paths and response
// values modified to provide the appropriate behaviour for the FileHandler.
func (h *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	const indexPage string = "index.html"

	var (
		requestPath string = r.URL.Path[len(h.urlPath)-1:]
		filePath    string
	)

	// If the request path ends in "/" ...
	if strings.HasSuffix(r.URL.Path, "/") {

		// Set the target filepath to index.html
		filePath = h.directory + filepath.FromSlash(requestPath+indexPage)

	} else {

		// Otherwise set the target filepath to the named file
		filePath = h.directory + filepath.FromSlash(requestPath)
	}

	// Try to get file info
	finfo, err := os.Stat(filePath)

	// If Stat fails return a 404
	if err != nil {

		h.notFoundHandler.ServeHTTP(w, r)
		return
	}

	// Check the mode to ensure the target filepath is a file
	switch mode := finfo.Mode(); {

	// If the target file is a directory redirect to the path with a slash
	case mode.IsDir():

		http.Redirect(w, r, r.URL.Path+"/", http.StatusFound)

	// Otherwise serve the file
	case mode.IsRegular():

		http.ServeFile(w, r, filePath)
	}

	return
}
<commit_msg>1.0.2<commit_after>/*
Package handlers is a small library of utility http handlers that are useful
for building web applications. It includes a NotFoundHandler, an ErrorHandler,
and a FileHandler.

The NotFoundHandler and ErrorHandler provide a simple way to respond to the
client with custom 404 and 500 status pages: create your own application
specific error page templates and call each of the handler's Serve methods
with the appropriate arguments.

These two handlers are intended to be used indirectly, from inside other
handlers where server errors or page not found errors occur and you need
to report them to the browser. However, both of these types implement the
http.Handler interface with a ServeHTTP method, which shows their default
behaviour when bound to a specific route.

The FileHandler provides similar functionality to the FileServer in the
net/http package, but with two differences: it will not show directory
listings for directories under its path, and it will respond to any request
for a non-existent file with the given NotFoundHandler.
*/
package handlers

import (
	"bytes"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// ErrorMessage holds the message passed to the error template. The template
// can access the message field with the {{.ErrorMessage}} tag.
type ErrorMessage struct {
	ErrorMessage string
}

// ErrorHandler serves error messages with the given template. The template
// can access the message served by the handler with the {{.ErrorMessage}} tag.
type ErrorHandler struct {
	template       *template.Template
	defaultMessage string
	displayErrors  bool
}

// NewErrorHandler returns a new ErrorHandler with the handler values initialised.
// The handler uses the given template to print an error message. The template
// must display {{.ErrorMessage}}. The default error message is set to message.
// The display argument controls whether error messages passed to the handler's
// ServeError function are shown to the user on the error page, or whether the
// default error message is shown instead. This allows detailed error messages
// to be printed to the screen during development, but turned off in production.
// The handler's AlwaysServeError method forces the display of a particular
// error message even if displayErrors is set to false.
func NewErrorHandler(template *template.Template, defaultMessage string, displayErrors bool) *ErrorHandler {

	return &ErrorHandler{
		template:       template,
		defaultMessage: defaultMessage,
		displayErrors:  displayErrors,
	}
}

// LoadErrorHandler is a convenience function that returns a new ErrorHandler
// using the template file specified by templatePath. The function first loads
// the template and then creates the ErrorHandler using NewErrorHandler.
func LoadErrorHandler(templatePath string, defaultMessage string, displayErrors bool) *ErrorHandler {

	template, err := template.ParseFiles(templatePath)

	if err != nil {
		log.Fatal(err)
	}

	return NewErrorHandler(template, defaultMessage, displayErrors)
}

// ServeError serves the appropriate error message in the error template
// depending on the value of displayErrors. If displayErrors is true then
// the given message is shown, otherwise the default error message is shown.
func (h *ErrorHandler) ServeError(w http.ResponseWriter, message string) {

	var (
		templateData *ErrorMessage
		buffer       bytes.Buffer
	)

	if h.displayErrors {

		templateData = &ErrorMessage{message}

	} else {

		templateData = &ErrorMessage{h.defaultMessage}
	}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fall back to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// AlwaysServeError serves the given error message in the error template.
// This method overrides the default error message, irrespective of whether
// displayErrors is false, and ensures that the given message is always shown.
func (h *ErrorHandler) AlwaysServeError(w http.ResponseWriter, message string) {

	var buffer bytes.Buffer
	templateData := &ErrorMessage{message}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fall back to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// ServeHTTP serves the default error message in the error template.
func (h *ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var buffer bytes.Buffer
	templateData := &ErrorMessage{h.defaultMessage}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, fall back to the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the error in the error template
	w.WriteHeader(http.StatusInternalServerError)
	buffer.WriteTo(w)
	return
}

// NotFoundData holds the path passed to the handler's template. The template
// can access the message field with the {{.Path}} tag.
type NotFoundData struct {
	Path string
}

// NotFoundHandler serves a 404 with the given template. The template
// can access the path to the file not found with {{.Path}} tag.
type NotFoundHandler struct {
	template *template.Template
}

// NewNotFoundHandler returns a new NotFoundHandler with the handler values
// initialised. The handler uses the given template to print the path to the
// file not found with a 404. The template must display {{.Path}}.
func NewNotFoundHandler(template *template.Template) *NotFoundHandler {

	return &NotFoundHandler{
		template: template,
	}
}

// LoadNotFoundHandler is a convenience function that returns a new NotFoundHandler
// using the template file specified by templatePath. The function first loads the
// template and then creates the NotFoundHandler using NewNotFoundHandler.
func LoadNotFoundHandler(templatePath string) *NotFoundHandler {

	template, err := template.ParseFiles(templatePath)

	if err != nil {
		log.Fatal(err)
	}

	return NewNotFoundHandler(template)
}

// ServeHTTP serves the path in the handler's template.
func (h *NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	var buffer bytes.Buffer
	templateData := &NotFoundData{r.URL.Path}

	// Execute template into buffer
	err := h.template.Execute(&buffer, templateData)

	// If template execution fails, report it with the built-in http error
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Otherwise serve the 404 in the not found template
	w.WriteHeader(http.StatusNotFound)
	buffer.WriteTo(w)
	return
}

// FileHandler serves files requested under the given url path from the given
// directory. The url path should be the same as the path to which the handler
// is bound with http.Handle. If the file is not found the handler serves a 404
// using the given notFoundHandler. The notFoundHandler can be any Handler, but
// its ServeHTTP method should return a 404. Unlike Go's built-in FileServer,
// FileHandler will not return directory listings for directories without an
// index.html and will instead respond with a 404.
type FileHandler struct {
	urlPath         string
	directory       string
	notFoundHandler http.Handler
}

// NewFileHandler returns a new FileHandler with the handler values initialised.
func NewFileHandler(urlPath string, directory string, notFoundHandler http.Handler) *FileHandler {

	return &FileHandler{
		urlPath:         urlPath,
		directory:       directory,
		notFoundHandler: notFoundHandler,
	}
}

// ServeHTTP is a wrapper around http.ServeFile, with paths and response
// values modified to provide the appropriate behaviour for the FileHandler.
func (h *FileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	const indexPage string = "index.html"

	var (
		requestPath string = r.URL.Path[len(h.urlPath)-1:]
		filePath    string
	)

	// If the request path ends in "/" ...
	if strings.HasSuffix(r.URL.Path, "/") {

		// Set the target filepath to index.html
		filePath = h.directory + filepath.FromSlash(requestPath+indexPage)

	} else {

		// Otherwise set the target filepath to the named file
		filePath = h.directory + filepath.FromSlash(requestPath)
	}

	// Try to get file info
	finfo, err := os.Stat(filePath)

	// If Stat fails return a 404
	if err != nil {

		h.notFoundHandler.ServeHTTP(w, r)
		return
	}

	// Check the mode to ensure the target filepath is a file
	switch mode := finfo.Mode(); {

	// If the target file is a directory redirect to the path with a slash
	case mode.IsDir():

		http.Redirect(w, r, r.URL.Path+"/", http.StatusFound)

	// Otherwise serve the file
	case mode.IsRegular():

		http.ServeFile(w, r, filePath)
	}

	return
}
<|endoftext|>


<commit_before>package restservice

//TODO: Better use of errchan
import (
	"encoding/json"
	"errors"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/howbazaar/loggo"
	"github.com/nu7hatch/gouuid"
	"github.com/straumur/straumur"
	"io"
	"net/http"
	"strconv"
	"time"
)

var (
	ErrSaveExisting      = errors.New("Save existing resource")
	ErrUpdateNonExisting = errors.New("Update non-existing resource")
	ErrMissingType       = errors.New("Missing type param")
	ErrInvalidEntity     = errors.New("Invalid entity")
	logger               = loggo.GetLogger("straumur.rest")
	sessionName          = "straumur"
	clientVarName        = "client-id"
)

type RESTService struct {
	Headers     map[string]string
	Store       sessions.Store
	databackend straumur.DataBackend
	events      chan *straumur.Event
	WsServer    *WebSocketServer
	errchan     chan error
}

// Returns the entity prefix
func getEntity(req *http.Request) (string, error) {
	vars := mux.Vars(req)
	entity := vars["entity"]
	id := vars["id"]
	if id == "" || entity == "" {
		return "", ErrInvalidEntity
	}
	return entity + "/" + id, nil
}

// Parses a Query from the request
func getQuery(req *http.Request) (*straumur.Query, error) {
	req.ParseForm()
	return straumur.QueryFromValues(req.Form)
}

// Parses an event from the post body
func (r *RESTService) parseEvent(body io.ReadCloser) (straumur.Event, error) {
	decoder := json.NewDecoder(body)
	defer body.Close()
	var e straumur.Event
	err := decoder.Decode(&e)
	return e, err
}

// Appends a unique session id to the request headers
func (r *RESTService) AddSessionIdHeader(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {

	return func(w http.ResponseWriter, req *http.Request) {

		session, err := r.Store.Get(req, sessionName)
		if err != nil {
			logger.Errorf("%v", err)
		}

		cidi, ok := session.Values[clientVarName]
		cid := ""

		if !ok {
			logger.Infof("New session")
			u4, err := uuid.NewV4()
			if err != nil {
				logger.Errorf("%v", err)
			}
			cid = u4.String()
			session.Values[clientVarName] = cid
			session.Save(req, w)
		} else {
			cid = cidi.(string)
		}

		req.Header.Add("X-User-Id", cid)
		f(w, req)
	}

}

// Wraps http.HandlerFunc, adds error response and frequently used headers
func (r *RESTService) Middleware(f func(http.ResponseWriter, *http.Request) (error, int)) http.HandlerFunc {

	v := func(w http.ResponseWriter, req *http.Request) {

		for k, v := range r.Headers {
			w.Header().Set(k, v)
		}

		t := time.Now()
		err, status := f(w, req)

		logger.Infof("Processed request: %s:%s in %f seconds", req.Method, req.URL, time.Now().Sub(t).Seconds())

		if err != nil {
			logger.Warningf("Error - [%s]%s, status: %d", req.Method, req.URL, status)
			http.Error(w, err.Error(), status)
		}
	}

	return r.AddSessionIdHeader(v)
}

// GET: /api/entity/id/
func (r *RESTService) entityHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	e, err := getEntity(req)
	if err != nil {
		return err, http.StatusBadRequest
	}
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	q.Entities = append(q.Entities, e)
	events, err := r.databackend.Query(*q)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)
	go r.updateListener(req.Header.Get("X-User-Id"), q)
	return nil, http.StatusOK
}

// GET: /api/id/
func (r *RESTService) retrieveHandler(w http.ResponseWriter, req *http.Request) (error, int) {

	vars := mux.Vars(req)
	id := vars["id"]
	idAsInt, err := strconv.Atoi(id)
	if err != nil {
		return err, http.StatusBadRequest
	}
	event, err := r.databackend.GetById(idAsInt)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(event)
	return nil, http.StatusOK
}

// POST: /
// PUT: /id/
// Save or update
func (r *RESTService) saveHandler(w http.ResponseWriter, req *http.Request) (error, int) {

	vars := mux.Vars(req)
	id := vars["id"]
	e, err := r.parseEvent(req.Body)
	if err != nil {
		return err, http.StatusBadRequest
	}
	if id == "" && e.ID != 0 {
		return ErrSaveExisting, http.StatusBadRequest
	}
	if id != "" && e.ID == 0 {
		return ErrUpdateNonExisting, http.StatusBadRequest
	}
	if e.ID == 0 {
		w.WriteHeader(http.StatusCreated)
	} else {
		w.WriteHeader(http.StatusAccepted)
	}

	logger.Infof("Saved event for key %s", e.Key)
	//fix block on error
	go func() { r.events <- &e }()
	return nil, 0
}

// GET: /api/search
func (r *RESTService) searchHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusBadRequest
	}
	events, err := r.databackend.Query(*q)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)
	go r.updateListener(req.Header.Get("X-User-Id"), q)
	return nil, http.StatusOK
}

func (r *RESTService) aggregateHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	vars := mux.Vars(req)
	agtype := vars["type"]
	if agtype == "" {
		return ErrMissingType, http.StatusBadRequest
	}
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	m, err := r.databackend.AggregateType(*q, agtype)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	enc := json.NewEncoder(w)
	enc.Encode(m)
	go r.updateListener(req.Header.Get("X-User-Id"), q)
	return nil, http.StatusOK
}

func (r *RESTService) updateListener(clientId string, q *straumur.Query) {
	c := r.WsServer.FindClientById(clientId)
	if c != nil {
		c.query = *q
	}
	logger.Infof("Updating WS Client: %s, %+v", clientId, c)
	return
}

func (r *RESTService) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	router := r.getRouter()
	router.ServeHTTP(w, req)
}

func (r *RESTService) getRouter() *mux.Router {
	router := mux.NewRouter()
	router.HandleFunc("/{entity}/{id}/", r.Middleware(r.entityHandler)).Methods("GET")
	router.HandleFunc("/", r.Middleware(r.saveHandler)).Methods("POST")
	router.HandleFunc("/{id}/", r.Middleware(r.retrieveHandler)).Methods("GET")
	router.HandleFunc("/{id}/", r.Middleware(r.saveHandler)).Methods("PUT")
	router.HandleFunc("/search", r.Middleware(r.searchHandler)).Methods("GET")
	router.HandleFunc("/aggregate/{type}", r.Middleware(r.aggregateHandler)).Methods("GET")
	router.Handle("/ws", r.WsServer.GetHandler())
	return router
}

// Creates a new REST dataservice
func NewRESTService(d straumur.DataBackend, errorChan chan error) *RESTService {

	defaultHeaders := make(map[string]string)
	defaultHeaders["Content-Type"] = "application/json; charset=utf-8"
	defaultHeaders["Access-Control-Allow-Origin"] = "*"
	defaultHeaders["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"

	rs := RESTService{
		Headers:     defaultHeaders,
		WsServer:    NewWebSocketServer(),
		events:      make(chan *straumur.Event),
		databackend: d,
		errchan:     errorChan,
	}
	go rs.WsServer.Run(errorChan)
	return &rs
}

//EventFeed interface
func (r *RESTService) Updates() <-chan *straumur.Event {
	return r.events
}

func (r *RESTService) Close() error {
	close(r.events)
	//Investigate way to perform graceful shutdown of http
	return nil
}
<commit_msg>After a REST query is performed, future updates matching the query are sent over websockets<commit_after>package restservice

//TODO: Better use of errchan
import (
	"encoding/json"
	"errors"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/howbazaar/loggo"
	"github.com/nu7hatch/gouuid"
	"github.com/straumur/straumur"
	"io"
	"net/http"
	"strconv"
	"time"
)

var (
	ErrSaveExisting      = errors.New("Save existing resource")
	ErrUpdateNonExisting = errors.New("Update non-existing resource")
	ErrMissingType       = errors.New("Missing type param")
	ErrInvalidEntity     = errors.New("Invalid entity")
	logger               = loggo.GetLogger("straumur.rest")
	sessionName          = "straumur"
	clientVarName        = "client-id"
)

type RESTService struct {
	Headers     map[string]string
	Store       sessions.Store
	databackend straumur.DataBackend
	events      chan *straumur.Event
	WsServer    *WebSocketServer
	errchan     chan error
}

// Returns the entity prefix
func getEntity(req *http.Request) (string, error) {
	vars := mux.Vars(req)
	entity := vars["entity"]
	id := vars["id"]
	if id == "" || entity == "" {
		return "", ErrInvalidEntity
	}
	return entity + "/" + id, nil
}

// Parses a Query from the request
func getQuery(req *http.Request) (*straumur.Query, error) {
	req.ParseForm()
	return straumur.QueryFromValues(req.Form)
}

// Parses an event from the post body
func (r *RESTService) parseEvent(body io.ReadCloser) (straumur.Event, error) {
	decoder := json.NewDecoder(body)
	defer body.Close()
	var e straumur.Event
	err := decoder.Decode(&e)
	return e, err
}

// Appends a unique session id to the request headers
func (r *RESTService) AddSessionIdHeader(f func(http.ResponseWriter, *http.Request)) http.HandlerFunc {

	return func(w http.ResponseWriter, req *http.Request) {

		session, err := r.Store.Get(req, sessionName)
		if err != nil {
			logger.Errorf("%v", err)
		}

		cidi, ok := session.Values[clientVarName]
		cid := ""

		if !ok {
			logger.Infof("New session")
			u4, err := uuid.NewV4()
			if err != nil {
				logger.Errorf("%v", err)
			}
			cid = u4.String()
			session.Values[clientVarName] = cid
			session.Save(req, w)
		} else {
			cid = cidi.(string)
		}

		req.Header.Add("X-User-Id", cid)
		f(w, req)
	}

}

// Wraps http.HandlerFunc, adds error response and frequently used headers
func (r *RESTService) Middleware(f func(http.ResponseWriter, *http.Request) (error, int)) http.HandlerFunc {

	v := func(w http.ResponseWriter, req *http.Request) {

		for k, v := range r.Headers {
			w.Header().Set(k, v)
		}

		t := time.Now()
		err, status := f(w, req)

		logger.Infof("Processed request: %s:%s in %f seconds", req.Method, req.URL, time.Now().Sub(t).Seconds())

		if err != nil {
			logger.Warningf("Error - [%s]%s, status: %d", req.Method, req.URL, status)
			http.Error(w, err.Error(), status)
		}
	}

	return r.AddSessionIdHeader(v)
}

// GET: /api/entity/id/
func (r *RESTService) entityHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	e, err := getEntity(req)
	if err != nil {
		return err, http.StatusBadRequest
	}
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	q.Entities = append(q.Entities, e)
	events, err := r.databackend.Query(*q)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)
	r.WsServer.Filters <- FilterPair{req.Header.Get("X-User-Id"), *q, 1}
	return nil, http.StatusOK
}

// GET: /api/id/
func (r *RESTService) retrieveHandler(w http.ResponseWriter, req *http.Request) (error, int) {

	vars := mux.Vars(req)
	id := vars["id"]
	idAsInt, err := strconv.Atoi(id)
	if err != nil {
		return err, http.StatusBadRequest
	}
	event, err := r.databackend.GetById(idAsInt)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(event)
	return nil, http.StatusOK
}

// POST: /
// PUT: /id/
// Save or update
func (r *RESTService) saveHandler(w http.ResponseWriter, req *http.Request) (error, int) {

	vars := mux.Vars(req)
	id := vars["id"]
	e, err := r.parseEvent(req.Body)
	if err != nil {
		return err, http.StatusBadRequest
	}
	if id == "" && e.ID != 0 {
		return ErrSaveExisting, http.StatusBadRequest
	}
	if id != "" && e.ID == 0 {
		return ErrUpdateNonExisting, http.StatusBadRequest
	}
	if e.ID == 0 {
		w.WriteHeader(http.StatusCreated)
	} else {
		w.WriteHeader(http.StatusAccepted)
	}

	logger.Infof("Saved event for key %s", e.Key)
	//fix block on error
	go func() { r.events <- &e }()
	return nil, 0
}

// GET: /api/search
func (r *RESTService) searchHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusBadRequest
	}
	events, err := r.databackend.Query(*q)
	if err != nil {
		return err, http.StatusInternalServerError
	}
	enc := json.NewEncoder(w)
	enc.Encode(events)
	r.WsServer.Filters <- FilterPair{req.Header.Get("X-User-Id"), *q, 1}
	return nil, http.StatusOK
}

func (r *RESTService) aggregateHandler(w http.ResponseWriter, req *http.Request) (error, int) {
	vars := mux.Vars(req)
	agtype := vars["type"]
	if agtype == "" {
		return ErrMissingType, http.StatusBadRequest
	}
	q, err := getQuery(req)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	m, err := r.databackend.AggregateType(*q, agtype)
	if err != nil {
		return err, http.StatusInternalServerError
	}

	enc := json.NewEncoder(w)
	enc.Encode(m)
	return nil, http.StatusOK
}

func (r *RESTService) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	router := r.getRouter()
	router.ServeHTTP(w, req)
}

func (r *RESTService) getRouter() *mux.Router {
	router := mux.NewRouter()
	s := router.PathPrefix("/api").Subrouter()
	s.HandleFunc("/{entity}/{id}/", r.Middleware(r.entityHandler)).Methods("GET")
	s.HandleFunc("/", r.Middleware(r.saveHandler)).Methods("POST")
	s.HandleFunc("/{id}/", r.Middleware(r.retrieveHandler)).Methods("GET")
	s.HandleFunc("/{id}/", r.Middleware(r.saveHandler)).Methods("PUT")
	s.HandleFunc("/search", r.Middleware(r.searchHandler)).Methods("GET")
	s.HandleFunc("/aggregate/{type}", r.Middleware(r.aggregateHandler)).Methods("GET")
	s.HandleFunc("/ws", r.AddSessionIdHeader(r.WsServer.GetHandler().ServeHTTP))
	return router
}

// Creates a new REST dataservice
func NewRESTService(d straumur.DataBackend, errorChan chan error) *RESTService {

	defaultHeaders := make(map[string]string)
	defaultHeaders["Content-Type"] = "application/json; charset=utf-8"
	defaultHeaders["Access-Control-Allow-Origin"] = "*"
	defaultHeaders["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"

	rs := RESTService{
		Headers:     defaultHeaders,
		WsServer:    NewWebSocketServer(),
		events:      make(chan *straumur.Event),
		databackend: d,
		errchan:     errorChan,
	}
	go rs.WsServer.Run(errorChan)
	return &rs
}

//EventFeed interface
func (r *RESTService) Updates() <-chan *straumur.Event {
	return r.events
}

func (r *RESTService) Close() error {
	close(r.events)
	//Investigate way to perform graceful shutdown of http
	return nil
}
<|endoftext|>


<commit_before>package simplehstore

import (
	"context"
	"database/sql"
	"fmt"
	"strings"
)

// HashMap2 contains a KeyValue struct and a dbDatastructure.
// Each value is a JSON data blob and can contains sub-keys.
type HashMap2 struct {
	dbDatastructure        // KeyValue is .host *Host + .table string
	ownerTable      string // Set of owner keys
	propTable       string // Set of all possible property keys
}

// A string that is unlikely to appear in a key
const fieldSep = "¤"

// NewHashMap2 creates a new HashMap2 struct
func NewHashMap2(host *Host, name string) (*HashMap2, error) {
	var hm2 HashMap2
	kv, err := NewKeyValue(host, name+"_hm2_kv")
	if err != nil {
		return nil, err
	}
	ownerSet, err := NewSet(host, name+"_hm2_owners")
	if err != nil {
		return nil, err
	}
	propSet, err := NewSet(host, name+"_hm2_seen_keys")
	if err != nil {
		return nil, err
	}
	hm2.host = host
	hm2.table = kv.table
	hm2.ownerTable = ownerSet.table
	hm2.propTable = propSet.table
	return &hm2, nil
}

// KeyValue returns the *KeyValue of properties for this HashMap2
func (hm2 *HashMap2) KeyValue() *KeyValue {
	return &KeyValue{hm2.host, hm2.table}
}

// OwnerSet returns the owner *Set for this HashMap2
func (hm2 *HashMap2) OwnerSet() *Set {
	return &Set{hm2.host, hm2.ownerTable}
}

// PropSet returns the property *Set for this HashMap2
func (hm2 *HashMap2) PropSet() *Set {
	return &Set{hm2.host, hm2.propTable}
}

// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (hm2 *HashMap2) Set(owner, key, value string) error {
	if strings.Contains(owner, fieldSep) || strings.Contains(key, fieldSep) {
		return fmt.Errorf("owner or key can not contain %s", fieldSep)
	}
	// Use a context and a transaction to bundle queries
	ctx := context.Background()
	transaction, err := hm2.host.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	// Add the owner to the set
	if err := hm2.OwnerSet().addWithTransaction(ctx, transaction, owner); err != nil {
		transaction.Rollback()
		return err
	}
	// Add the key to the property set
	if err := hm2.PropSet().addWithTransaction(ctx, transaction, key); err != nil {
		transaction.Rollback()
		return err
	}
	// Set a key + value for this "owner¤key"
	if err := hm2.KeyValue().setWithTransaction(ctx, transaction, owner+fieldSep+key, value); err != nil {
		transaction.Rollback()
		return err
	}
	// Commit the transaction
	return transaction.Commit()
}

// setWithTransaction will set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (hm2 *HashMap2) setWithTransaction(ctx context.Context, transaction *sql.Tx, owner, key, value string) error {
	if strings.Contains(owner, fieldSep) || strings.Contains(key, fieldSep) {
		return fmt.Errorf("owner or key can not contain %s", fieldSep)
	}
	// Add the owner to the set
	if err := hm2.OwnerSet().addWithTransaction(ctx, transaction, owner); err != nil {
		return err
	}
	// Add the key to the property set
	if err := hm2.PropSet().addWithTransaction(ctx, transaction, key); err != nil {
		return err
	}
	// Set a key + value for this "owner¤key"
	return hm2.KeyValue().setWithTransaction(ctx, transaction, owner+fieldSep+key, value)
}

// SetMap will set many keys/values, in a single transaction
func (hm2 *HashMap2) SetMap(owner string, m map[string]string) error {
	// Use a context and a transaction to bundle queries
	ctx := context.Background()
	transaction, err := hm2.host.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	// Prepare the changes
	for k, v := range m {
		if err := hm2.setWithTransaction(ctx, transaction, owner, k, v); err != nil {
			transaction.Rollback()
			return err
		}
	}
	// Commit the transaction
	return transaction.Commit()
}

// Get a value
func (hm2 *HashMap2) Get(owner, key string) (string, error) {
	return hm2.KeyValue().Get(owner + fieldSep + key)
}

// Has checks if a given owner + key exists in the hash map
func (hm2 *HashMap2) Has(owner, key string) (bool, error) {
	s, err := hm2.KeyValue().Get(owner + fieldSep + key)
	return s != "", err
}

// Exists checks if a given owner exists as a hash map at all
func (hm2 *HashMap2) Exists(owner string) (bool, error) {
	return hm2.OwnerSet().Has(owner)
}

// AllWhere returns all owner ID's that has a property where key == value
func (hm2 *HashMap2) AllWhere(key, value string) ([]string, error) {
	allOwners, err := hm2.OwnerSet().All()
	if err != nil {
		return []string{}, err
	}
	// TODO: Improve the performance of this by using SQL instead of looping
	foundOwners := []string{}
	for _, owner := range allOwners {
		if found, err := hm2.Has(owner, key); err == nil && found {
			foundOwners = append(foundOwners, owner)
		}
	}
	return foundOwners, nil
}

// Keys loops through absolutely all owners and all properties in the database
// and returns all found keys.
func (hm2 *HashMap2) Keys(owner string) ([]string, error) {
	allProps, err := hm2.PropSet().All()
	if err != nil {
		return []string{}, err
	}
	// TODO: Improve the performance of this by using SQL instead of looping
	allKeys := []string{}
	for _, key := range allProps {
		if found, err := hm2.Has(owner, key); err == nil && found {
			allKeys = append(allKeys, key)
		}
	}
	return allKeys, nil
}

// All returns all owner ID's
func (hm2 *HashMap2) All() ([]string, error) {
	return hm2.OwnerSet().All()
}

// Count counts the number of owners for hash map elements
func (hm2 *HashMap2) Count() (int, error) {
	return hm2.OwnerSet().Count()
}

// CountInt64 counts the number of owners for hash map elements (int64)
func (hm2 *HashMap2) CountInt64() (int64, error) {
	return hm2.OwnerSet().CountInt64()
}

// DelKey removes a key of an owner in a hashmap (for instance the email field for a user)
func (hm2 *HashMap2) DelKey(owner, key string) error {
	return hm2.KeyValue().Del(owner + fieldSep + key)
}

// Del removes an element (for instance a user)
func (hm2 *HashMap2) Del(owner string) error {
	ownerSet := hm2.OwnerSet()
	items, err := ownerSet.All()
	if err != nil {
		return err
	}
	for _, v := range items {
		if v == owner {
			return ownerSet.Del(v)
		}
	}
	return fmt.Errorf("could not find %s", owner)
}

// Remove this hashmap
func (hm2 *HashMap2) Remove() error {
	hm2.PropSet().Remove()
	hm2.OwnerSet().Remove()
	if err := hm2.KeyValue().Remove(); err != nil {
		return fmt.Errorf("could not remove kv: %s", err)
	}
	return nil
}

// Clear the contents
func (hm2 *HashMap2) Clear() error {
	if err := hm2.KeyValue().Clear(); err != nil {
		return err
	}
	if err := hm2.OwnerSet().Clear(); err != nil {
		return err
	}
	if err := hm2.PropSet().Clear(); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix: If the table does not exist, the elements does not exist either<commit_after>package simplehstore

import (
	"context"
	"database/sql"
	"fmt"
	"strings"
)

// HashMap2 contains a KeyValue struct and a dbDatastructure.
// Each value is a JSON data blob and can contains sub-keys.
type HashMap2 struct {
	dbDatastructure        // KeyValue is .host *Host + .table string
	ownerTable      string // Set of owner keys
	propTable       string // Set of all possible property keys
}

// A string that is unlikely to appear in a key
const fieldSep = "¤"

// NewHashMap2 creates a new HashMap2 struct
func NewHashMap2(host *Host, name string) (*HashMap2, error) {
	var hm2 HashMap2
	kv, err := NewKeyValue(host, name+"_hm2_kv")
	if err != nil {
		return nil, err
	}
	ownerSet, err := NewSet(host, name+"_hm2_owners")
	if err != nil {
		return nil, err
	}
	propSet, err := NewSet(host, name+"_hm2_seen_keys")
	if err != nil {
		return nil, err
	}
	hm2.host = host
	hm2.table = kv.table
	hm2.ownerTable = ownerSet.table
	hm2.propTable = propSet.table
	return &hm2, nil
}

// KeyValue returns the *KeyValue of properties for this HashMap2
func (hm2 *HashMap2) KeyValue() *KeyValue {
	return &KeyValue{hm2.host, hm2.table}
}

// OwnerSet returns the owner *Set for this HashMap2
func (hm2 *HashMap2) OwnerSet() *Set {
	return &Set{hm2.host, hm2.ownerTable}
}

// PropSet returns the property *Set for this HashMap2
func (hm2 *HashMap2) PropSet() *Set {
	return &Set{hm2.host, hm2.propTable}
}

// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (hm2 *HashMap2) Set(owner, key, value string) error {
	if strings.Contains(owner, fieldSep) || strings.Contains(key, fieldSep) {
		return fmt.Errorf("owner or key can not contain %s", fieldSep)
	}
	// Use a context and a transaction to bundle queries
	ctx := context.Background()
	transaction, err := hm2.host.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	// Add the owner to the set
	if err := hm2.OwnerSet().addWithTransaction(ctx, transaction, owner); err != nil {
		transaction.Rollback()
		return err
	}
	// Add the key to the property set
	if err := hm2.PropSet().addWithTransaction(ctx, transaction, key); err != nil {
		transaction.Rollback()
		return err
	}
	// Set a key + value for this "owner¤key"
	if err := hm2.KeyValue().setWithTransaction(ctx, transaction, owner+fieldSep+key, value); err != nil {
		transaction.Rollback()
		return err
	}
	// Commit the transaction
	return transaction.Commit()
}

// setWithTransaction will set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (hm2 *HashMap2) setWithTransaction(ctx context.Context, transaction *sql.Tx, owner, key, value string) error {
	if strings.Contains(owner, fieldSep) || strings.Contains(key, fieldSep) {
		return fmt.Errorf("owner or key can not contain %s", fieldSep)
	}
	// Add the owner to the set
	if err := hm2.OwnerSet().addWithTransaction(ctx, transaction, owner); err != nil {
		return err
	}
	// Add the key to the property set
	if err := hm2.PropSet().addWithTransaction(ctx, transaction, key); err != nil {
		return err
	}
	// Set a key + value for this "owner¤key"
	return hm2.KeyValue().setWithTransaction(ctx, transaction, owner+fieldSep+key, value)
}

// SetMap will set many keys/values, in a single transaction
func (hm2 *HashMap2) SetMap(owner string, m map[string]string) error {
	// Use a context and a transaction to bundle queries
	ctx := context.Background()
	transaction, err := hm2.host.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	// Prepare the changes
	for k, v := range m {
		if err := hm2.setWithTransaction(ctx, transaction, owner, k, v); err != nil {
			transaction.Rollback()
			return err
		}
	}
	// Commit the transaction
	return transaction.Commit()
}

// Get a value
func (hm2 *HashMap2) Get(owner, key string) (string, error) {
	return hm2.KeyValue().Get(owner + fieldSep + key)
}

// Has checks if a given owner + key exists in the hash map
func (hm2 *HashMap2) Has(owner, key string) (bool, error) {
	s, err := hm2.KeyValue().Get(owner + fieldSep + key)
	return s != "", err
}

// Exists checks if a given owner exists as a hash map at all
func (hm2 *HashMap2) Exists(owner string) (bool, error) {
	found, err := hm2.OwnerSet().Has(owner)
	if err != nil && strings.HasSuffix(err.Error(), "does not exist") {
		return false, nil
	}
	return found, err
}

// AllWhere returns all owner ID's that has a property where key == value
func (hm2 *HashMap2) AllWhere(key, value string) ([]string, error) {
	allOwners, err := hm2.OwnerSet().All()
	if err != nil {
		return []string{}, err
	}
	// TODO: Improve the performance of this by using SQL instead of looping
	foundOwners := []string{}
	for _, owner := range allOwners {
		if found, err := hm2.Has(owner, key); err == nil && found {
			foundOwners = append(foundOwners, owner)
		}
	}
	return foundOwners, nil
}

// Keys loops through absolutely all owners and all properties in the database
// and returns all found keys.
func (hm2 *HashMap2) Keys(owner string) ([]string, error) {
	allProps, err := hm2.PropSet().All()
	if err != nil {
		return []string{}, err
	}
	// TODO: Improve the performance of this by using SQL instead of looping
	allKeys := []string{}
	for _, key := range allProps {
		if found, err := hm2.Has(owner, key); err == nil && found {
			allKeys = append(allKeys, key)
		}
	}
	return allKeys, nil
}

// All returns all owner ID's
func (hm2 *HashMap2) All() ([]string, error) {
	return hm2.OwnerSet().All()
}

// Count counts the number of owners for hash map elements
func (hm2 *HashMap2) Count() (int, error) {
	return hm2.OwnerSet().Count()
}

// CountInt64 counts the number of owners for hash map elements (int64)
func (hm2 *HashMap2) CountInt64() (int64, error) {
	return hm2.OwnerSet().CountInt64()
}

// DelKey removes a key of an owner in a hashmap (for instance the email field for a user)
func (hm2 *HashMap2) DelKey(owner, key string) error {
	return hm2.KeyValue().Del(owner + fieldSep + key)
}

// Del removes an element (for instance a user)
func (hm2 *HashMap2) Del(owner string) error {
	ownerSet := hm2.OwnerSet()
	items, err := ownerSet.All()
	if err != nil {
		return err
	}
	for _, v := range items {
		if v == owner {
			return ownerSet.Del(v)
		}
	}
	return fmt.Errorf("could not find %s", owner)
}

// Remove this hashmap
func (hm2 *HashMap2) Remove() error {
	hm2.PropSet().Remove()
	hm2.OwnerSet().Remove()
	if err := hm2.KeyValue().Remove(); err != nil {
		return fmt.Errorf("could not remove kv: %s", err)
	}
	return nil
}

// Clear the contents
func (hm2 *HashMap2) Clear() error {
	if err := hm2.KeyValue().Clear(); err != nil {
		return err
	}
	if err := hm2.OwnerSet().Clear(); err != nil {
		return err
	}
	if err := hm2.PropSet().Clear(); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

type Base struct {
	b int
}

type Container struct {
	Base
	c string
}

func main() {
	bb := Base{b: 10}

	// Note: using "Base" in this literal to initialize the field.
	cc := Container{Base: bb, c: "foo"}

	fmt.Printf("cc -> {b: %v, c: %v}\n", cc.b, cc.c)
}
<commit_msg>Flesh out example with methods, etc.<commit_after>package main

import "fmt"

type Base struct {
	b int
}

func (base Base) Describe() string {
	return fmt.Sprintf("base %d belongs to us", base.b)
}

type Container struct {
	Base
	c string
}

func main() {
	co := Container{}
	co.b = 1
	co.c = "string"
	fmt.Printf("co -> {b: %v, c: %v}\n", co.b, co.c)

	// Note: using "Base" in this literal to initialize the field.
	cc := Container{Base: Base{b: 10}, c: "foo"}
	fmt.Printf("cc -> {b: %v, c: %v}\n", cc.b, cc.c)

	// Fully qualified access.
	fmt.Println(cc.Base.b)

	fmt.Println(cc.Describe())
}
<|endoftext|>


<commit_before>// +build go1.3

// Copyright 2014 The Macaron 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 macaron is a high productive and modular web framework in Go.
package macaron

import (
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"
	"sync"

	"github.com/Unknwon/com"
	"gopkg.in/ini.v1"

	"github.com/go-macaron/inject"
)

const _VERSION = "1.2.0.0128"

func Version() string {
	return _VERSION
}

// Handler can be any callable function.
// Macaron attempts to inject services into the handler's argument list,
// and panics if an argument could not be fullfilled via dependency injection.
type Handler interface{}

// handlerFuncInvoker is an inject.FastInvoker wrapper of func(http.ResponseWriter, *http.Request).
type handlerFuncInvoker func(http.ResponseWriter, *http.Request)

func (invoke handlerFuncInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
	invoke(params[0].(http.ResponseWriter), params[1].(*http.Request))
	return nil, nil
}

// internalServerErrorInvoker is an inject.FastInvoker wrapper of func(rw http.ResponseWriter, err error).
type internalServerErrorInvoker func(rw http.ResponseWriter, err error)

func (invoke internalServerErrorInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
	invoke(params[0].(http.ResponseWriter), params[1].(error))
	return nil, nil
}

// validateAndWrapHandler makes sure a handler is a callable function, it panics if not.
// When the handler is also potential to be any built-in inject.FastInvoker,
// it wraps the handler automatically to have some performance gain.
func validateAndWrapHandler(h Handler) Handler {
	if reflect.TypeOf(h).Kind() != reflect.Func {
		panic("Macaron handler must be a callable function")
	}

	if !inject.IsFastInvoker(h) {
		switch v := h.(type) {
		case func(*Context):
			return ContextInvoker(v)
		case func(*Context, *log.Logger):
			return LoggerInvoker(v)
		case func(http.ResponseWriter, *http.Request):
			return handlerFuncInvoker(v)
		case func(http.ResponseWriter, error):
			return internalServerErrorInvoker(v)
		}
	}
	return h
}

// validateAndWrapHandlers preforms validation and wrapping for each input handler.
// It accepts an optional wrapper function to perform custom wrapping on handlers.
func validateAndWrapHandlers(handlers []Handler, wrappers ...func(Handler) Handler) []Handler {
	var wrapper func(Handler) Handler
	if len(wrappers) > 0 {
		wrapper = wrappers[0]
	}

	wrappedHandlers := make([]Handler, len(handlers))
	for i, h := range handlers {
		h = validateAndWrapHandler(h)
		if wrapper != nil && !inject.IsFastInvoker(h) {
			h = wrapper(h)
		}
		wrappedHandlers[i] = h
	}

	return wrappedHandlers
}

// Macaron represents the top level web application.
// inject.Injector methods can be invoked to map services on a global level.
type Macaron struct {
	inject.Injector
	befores  []BeforeHandler
	handlers []Handler
	action   Handler

	hasURLPrefix bool
	urlPrefix    string // For suburl support.
	*Router

	logger *log.Logger
}

// NewWithLogger creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
// You can specify logger output writer with this function.
func NewWithLogger(out io.Writer) *Macaron {
	m := &Macaron{
		Injector: inject.New(),
		action:   func() {},
		Router:   NewRouter(),
		logger:   log.New(out, "[Macaron] ", 0),
	}
	m.Router.m = m
	m.Map(m.logger)
	m.Map(defaultReturnHandler())
	m.NotFound(http.NotFound)
	m.InternalServerError(func(rw http.ResponseWriter, err error) {
		http.Error(rw, err.Error(), 500)
	})
	return m
}

// New creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
func New() *Macaron {
	return NewWithLogger(os.Stdout)
}

// Classic creates a classic Macaron with some basic default middleware:
// mocaron.Logger, mocaron.Recovery and mocaron.Static.
func Classic() *Macaron {
	m := New()
	m.Use(Logger())
	m.Use(Recovery())
	m.Use(Static("public"))
	return m
}

// Handlers sets the entire middleware stack with the given Handlers.
// This will clear any current middleware handlers,
// and panics if any of the handlers is not a callable function
func (m *Macaron) Handlers(handlers ...Handler) {
	m.handlers = make([]Handler, 0)
	for _, handler := range handlers {
		m.Use(handler)
	}
}

// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Macaron) Action(handler Handler) {
	handler = validateAndWrapHandler(handler)
	m.action = handler
}

// BeforeHandler represents a handler executes at beginning of every request.
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool

func (m *Macaron) Before(handler BeforeHandler) {
	m.befores = append(m.befores, handler)
}

// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
func (m *Macaron) Use(handler Handler) {
	handler = validateAndWrapHandler(handler)
	m.handlers = append(m.handlers, handler)
}

func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context {
	c := &Context{
		Injector: inject.New(),
		handlers: m.handlers,
		action:   m.action,
		index:    0,
		Router:   m.Router,
		Req:      Request{req},
		Resp:     NewResponseWriter(rw),
		Render:   &DummyRender{rw},
		Data:     make(map[string]interface{}),
	}
	c.SetParent(m)
	c.Map(c)
	c.MapTo(c.Resp, (*http.ResponseWriter)(nil))
	c.Map(req)
	return c
}

// ServeHTTP is the HTTP Entry point for a Macaron instance.
// Useful if you want to control your own HTTP server.
// Be aware that none of middleware will run without registering any router.
func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if m.hasURLPrefix {
		req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
	}
	for _, h := range m.befores {
		if h(rw, req) {
			return
		}
	}
	m.Router.ServeHTTP(rw, req)
}

func GetDefaultListenInfo() (string, int) {
	host := os.Getenv("HOST")
	if len(host) == 0 {
		host = "0.0.0.0"
	}
	port := com.StrTo(os.Getenv("PORT")).MustInt()
	if port == 0 {
		port = 4000
	}
	return host, port
}

// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
func (m *Macaron) Run(args ...interface{}) {
	host, port := GetDefaultListenInfo()
	if len(args) == 1 {
		switch arg := args[0].(type) {
		case string:
			host = arg
		case int:
			port = arg
		}
	} else if len(args) >= 2 {
		if arg, ok := args[0].(string); ok {
			host = arg
		}
		if arg, ok := args[1].(int); ok {
			port = arg
		}
	}

	addr := host + ":" + com.ToStr(port)
	logger := m.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
	logger.Printf("listening on %s (%s)\n", addr, safeEnv())
	logger.Fatalln(http.ListenAndServe(addr, m))
}

// SetURLPrefix sets URL prefix of router layer, so that it support suburl.
func (m *Macaron) SetURLPrefix(prefix string) {
	m.urlPrefix = prefix
	m.hasURLPrefix = len(m.urlPrefix) > 0
}

// ____   ____            .__      ___.   .__
// \   \ /   /____ _______|__|____ \_ |__ |  |   ____   ______
//  \   Y   /\__  \\_  __ \  \__  \ | __ \|  | _/ __ \ /  ___/
//   \     /  / __ \|  | \/  |/ __ \| \_\ \  |_\  ___/ \___ \
//    \___/  (____  /__|  |__(____  /___  /____/\___  >____  >
//                \/              \/    \/          \/     \/

const (
	DEV  = "development"
	PROD = "production"
	TEST = "test"
)

var (
	// Env is the environment that Macaron is executing in.
	// The MACARON_ENV is read on initialization to set this variable.
	Env     = DEV
	envLock sync.Mutex

	// Path of work directory.
	Root string

	// Flash applies to current request.
	FlashNow bool

	// Configuration convention object.
	cfg *ini.File
)

func setENV(e string) {
	envLock.Lock()
	defer envLock.Unlock()

	if len(e) > 0 {
		Env = e
	}
}

func safeEnv() string {
	envLock.Lock()
	defer envLock.Unlock()

	return Env
}

func init() {
	setENV(os.Getenv("MACARON_ENV"))

	var err error
	Root, err = os.Getwd()
	if err != nil {
		panic("error getting work directory: " + err.Error())
	}
}

// SetConfig sets data sources for configuration.
func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err error) {
	cfg, err = ini.Load(source, others...)
	return Config(), err
}

// Config returns configuration convention object.
// It returns an empty object if there is no one available.
func Config() *ini.File {
	if cfg == nil {
		return ini.Empty()
	}
	return cfg
}
<commit_msg>fix documentation string of Classic() (#117)<commit_after>// +build go1.3

// Copyright 2014 The Macaron 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 macaron is a high productive and modular web framework in Go.
package macaron

import (
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"
	"sync"

	"github.com/Unknwon/com"
	"gopkg.in/ini.v1"

	"github.com/go-macaron/inject"
)

const _VERSION = "1.2.0.0128"

func Version() string {
	return _VERSION
}

// Handler can be any callable function.
// Macaron attempts to inject services into the handler's argument list,
// and panics if an argument could not be fullfilled via dependency injection.
type Handler interface{}

// handlerFuncInvoker is an inject.FastInvoker wrapper of func(http.ResponseWriter, *http.Request).
type handlerFuncInvoker func(http.ResponseWriter, *http.Request)

func (invoke handlerFuncInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
	invoke(params[0].(http.ResponseWriter), params[1].(*http.Request))
	return nil, nil
}

// internalServerErrorInvoker is an inject.FastInvoker wrapper of func(rw http.ResponseWriter, err error).
type internalServerErrorInvoker func(rw http.ResponseWriter, err error)

func (invoke internalServerErrorInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
	invoke(params[0].(http.ResponseWriter), params[1].(error))
	return nil, nil
}

// validateAndWrapHandler makes sure a handler is a callable function, it panics if not.
// When the handler is also potential to be any built-in inject.FastInvoker,
// it wraps the handler automatically to have some performance gain.
func validateAndWrapHandler(h Handler) Handler {
	if reflect.TypeOf(h).Kind() != reflect.Func {
		panic("Macaron handler must be a callable function")
	}

	if !inject.IsFastInvoker(h) {
		switch v := h.(type) {
		case func(*Context):
			return ContextInvoker(v)
		case func(*Context, *log.Logger):
			return LoggerInvoker(v)
		case func(http.ResponseWriter, *http.Request):
			return handlerFuncInvoker(v)
		case func(http.ResponseWriter, error):
			return internalServerErrorInvoker(v)
		}
	}
	return h
}

// validateAndWrapHandlers preforms validation and wrapping for each input handler.
// It accepts an optional wrapper function to perform custom wrapping on handlers.
func validateAndWrapHandlers(handlers []Handler, wrappers ...func(Handler) Handler) []Handler {
	var wrapper func(Handler) Handler
	if len(wrappers) > 0 {
		wrapper = wrappers[0]
	}

	wrappedHandlers := make([]Handler, len(handlers))
	for i, h := range handlers {
		h = validateAndWrapHandler(h)
		if wrapper != nil && !inject.IsFastInvoker(h) {
			h = wrapper(h)
		}
		wrappedHandlers[i] = h
	}

	return wrappedHandlers
}

// Macaron represents the top level web application.
// inject.Injector methods can be invoked to map services on a global level.
type Macaron struct {
	inject.Injector
	befores  []BeforeHandler
	handlers []Handler
	action   Handler

	hasURLPrefix bool
	urlPrefix    string // For suburl support.
	*Router

	logger *log.Logger
}

// NewWithLogger creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
// You can specify logger output writer with this function.
func NewWithLogger(out io.Writer) *Macaron {
	m := &Macaron{
		Injector: inject.New(),
		action:   func() {},
		Router:   NewRouter(),
		logger:   log.New(out, "[Macaron] ", 0),
	}
	m.Router.m = m
	m.Map(m.logger)
	m.Map(defaultReturnHandler())
	m.NotFound(http.NotFound)
	m.InternalServerError(func(rw http.ResponseWriter, err error) {
		http.Error(rw, err.Error(), 500)
	})
	return m
}

// New creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
func New() *Macaron {
	return NewWithLogger(os.Stdout)
}

// Classic creates a classic Macaron with some basic default middleware:
// macaron.Logger, macaron.Recovery and macaron.Static.
func Classic() *Macaron {
	m := New()
	m.Use(Logger())
	m.Use(Recovery())
	m.Use(Static("public"))
	return m
}

// Handlers sets the entire middleware stack with the given Handlers.
// This will clear any current middleware handlers,
// and panics if any of the handlers is not a callable function
func (m *Macaron) Handlers(handlers ...Handler) {
	m.handlers = make([]Handler, 0)
	for _, handler := range handlers {
		m.Use(handler)
	}
}

// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Macaron) Action(handler Handler) {
	handler = validateAndWrapHandler(handler)
	m.action = handler
}

// BeforeHandler represents a handler executes at beginning of every request.
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool

func (m *Macaron) Before(handler BeforeHandler) {
	m.befores = append(m.befores, handler)
}

// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
func (m *Macaron) Use(handler Handler) {
	handler = validateAndWrapHandler(handler)
	m.handlers = append(m.handlers, handler)
}

func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context {
	c := &Context{
		Injector: inject.New(),
		handlers: m.handlers,
		action:   m.action,
		index:    0,
		Router:   m.Router,
		Req:      Request{req},
		Resp:     NewResponseWriter(rw),
		Render:   &DummyRender{rw},
		Data:     make(map[string]interface{}),
	}
	c.SetParent(m)
	c.Map(c)
	c.MapTo(c.Resp, (*http.ResponseWriter)(nil))
	c.Map(req)
	return c
}

// ServeHTTP is the HTTP Entry point for a Macaron instance.
// Useful if you want to control your own HTTP server.
// Be aware that none of middleware will run without registering any router.
func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if m.hasURLPrefix {
		req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
	}
	for _, h := range m.befores {
		if h(rw, req) {
			return
		}
	}
	m.Router.ServeHTTP(rw, req)
}

func GetDefaultListenInfo() (string, int) {
	host := os.Getenv("HOST")
	if len(host) == 0 {
		host = "0.0.0.0"
	}
	port := com.StrTo(os.Getenv("PORT")).MustInt()
	if port == 0 {
		port = 4000
	}
	return host, port
}

// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
func (m *Macaron) Run(args ...interface{}) {
	host, port := GetDefaultListenInfo()
	if len(args) == 1 {
		switch arg := args[0].(type) {
		case string:
			host = arg
		case int:
			port = arg
		}
	} else if len(args) >= 2 {
		if arg, ok := args[0].(string); ok {
			host = arg
		}
		if arg, ok := args[1].(int); ok {
			port = arg
		}
	}

	addr := host + ":" + com.ToStr(port)
	logger := m.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
	logger.Printf("listening on %s (%s)\n", addr, safeEnv())
	logger.Fatalln(http.ListenAndServe(addr, m))
}

// SetURLPrefix sets URL prefix of router layer, so that it support suburl.
func (m *Macaron) SetURLPrefix(prefix string) {
	m.urlPrefix = prefix
	m.hasURLPrefix = len(m.urlPrefix) > 0
}

// ____   ____            .__      ___.   .__
// \   \ /   /____ _______|__|____ \_ |__ |  |   ____   ______
//  \   Y   /\__  \\_  __ \  \__  \ | __ \|  | _/ __ \ /  ___/
//   \     /  / __ \|  | \/  |/ __ \| \_\ \  |_\  ___/ \___ \
//    \___/  (____  /__|  |__(____  /___  /____/\___  >____  >
//                \/              \/    \/          \/     \/

const (
	DEV  = "development"
	PROD = "production"
	TEST = "test"
)

var (
	// Env is the environment that Macaron is executing in.
	// The MACARON_ENV is read on initialization to set this variable.
	Env     = DEV
	envLock sync.Mutex

	// Path of work directory.
	Root string

	// Flash applies to current request.
	FlashNow bool

	// Configuration convention object.
	cfg *ini.File
)

func setENV(e string) {
	envLock.Lock()
	defer envLock.Unlock()

	if len(e) > 0 {
		Env = e
	}
}

func safeEnv() string {
	envLock.Lock()
	defer envLock.Unlock()

	return Env
}

func init() {
	setENV(os.Getenv("MACARON_ENV"))

	var err error
	Root, err = os.Getwd()
	if err != nil {
		panic("error getting work directory: " + err.Error())
	}
}

// SetConfig sets data sources for configuration.
func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err error) {
	cfg, err = ini.Load(source, others...)
	return Config(), err
}

// Config returns configuration convention object.
// It returns an empty object if there is no one available.
func Config() *ini.File {
	if cfg == nil {
		return ini.Empty()
	}
	return cfg
}
<|endoftext|>


<commit_before>package storage

import (
	"github.com/khlieng/dispatch/pkg/session"
)

var Path directory

func Initialize(dir string) {
	Path = directory(dir)
}

type Store interface {
	GetUsers() ([]*User, error)
	SaveUser(user *User) error
	DeleteUser(user *User) error

	GetServers(user *User) ([]*Server, error)
	AddServer(user *User, server *Server) error
	RemoveServer(user *User, host string) error
	SetNick(user *User, nick, host string) error
	SetServerName(user *User, name, host string) error

	GetChannels(user *User) ([]*Channel, error)
	AddChannel(user *User, channel *Channel) error
	RemoveChannel(user *User, server, channel string) error
}

type SessionStore interface {
	GetSessions() ([]*session.Session, error)
	SaveSession(session *session.Session) error
	DeleteSession(key string) error
}

type MessageStore interface {
	LogMessage(message *Message) error
	GetMessages(server, channel string, count int, fromID string) ([]Message, bool, error)
	GetMessagesByID(server, channel string, ids []string) ([]Message, error)
	Close()
}

type MessageSearchProvider interface {
	SearchMessages(server, channel, q string) ([]string, error)
	Index(id string, message *Message) error
	Close()
}
<commit_msg>Create root directory explicitly, closes #22<commit_after>package storage

import (
	"os"

	"github.com/khlieng/dispatch/pkg/session"
)

var Path directory

func Initialize(dir string) {
	Path = directory(dir)
	os.MkdirAll(Path.Root(), 0700)
}

type Store interface {
	GetUsers() ([]*User, error)
	SaveUser(user *User) error
	DeleteUser(user *User) error

	GetServers(user *User) ([]*Server, error)
	AddServer(user *User, server *Server) error
	RemoveServer(user *User, host string) error
	SetNick(user *User, nick, host string) error
	SetServerName(user *User, name, host string) error

	GetChannels(user *User) ([]*Channel, error)
	AddChannel(user *User, channel *Channel) error
	RemoveChannel(user *User, server, channel string) error
}

type SessionStore interface {
	GetSessions() ([]*session.Session, error)
	SaveSession(session *session.Session) error
	DeleteSession(key string) error
}

type MessageStore interface {
	LogMessage(message *Message) error
	GetMessages(server, channel string, count int, fromID string) ([]Message, bool, error)
	GetMessagesByID(server, channel string, ids []string) ([]Message, error)
	Close()
}

type MessageSearchProvider interface {
	SearchMessages(server, channel, q string) ([]string, error)
	Index(id string, message *Message) error
	Close()
}
<|endoftext|>


<commit_before>package controller

import (
	"github.com/mesos/mesos-go/api/v1/lib"
	"github.com/mesos/mesos-go/api/v1/lib/encoding"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler/calls"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler/events"
)

type (
	Context interface {
		// Done returns true when the controller should exit
		Done() bool

		// FrameworkID returns the current Mesos-assigned framework ID. Frameworks are expected to
		// track this ID (that comes from Mesos, in a SUBSCRIBED event).
		FrameworkID() string

		// Error is an error handler that is invoked at the end of every subscription cycle; the given
		// error may be nil (if no errors occurred).
		Error(error)
	}

	ContextAdapter struct {
		// FrameworkIDFunc is optional; nil tells the controller to always register as a new framework
		// for each subscription attempt.
		FrameworkIDFunc func() string

		// Done is optional; nil equates to a func that always returns false
		DoneFunc func() bool

		// ErrorFunc is optional; if nil then errors are swallowed
		ErrorFunc func(error)
	}

	Config struct {
		Context   Context              // Context is required
		Framework *mesos.FrameworkInfo // FrameworkInfo is required
		Caller    calls.Caller         // Caller  is required

		// Handler (optional) processes scheduler events. The controller's internal event processing
		// loop is aborted if a Handler returns a non-nil error, after which the controller may attempt
		// to re-register (subscribe) with Mesos.
		Handler events.Handler

		// RegistrationTokens (optional) limits the rate at which a framework (re)registers with Mesos.
		// The returned chan should either be non-blocking (nil/closed), or should yield a struct{} in
		// order to allow the framework registration process to continue. May be nil.
		RegistrationTokens <-chan struct{}
	}

	Controller interface {
		// Run executes the controller using the given Config
		Run(Config) error
	}

	// ControllerFunc is a functional adaptation of a Controller
	ControllerFunc func(Config) error

	controllerImpl int
)

// Run implements Controller for ControllerFunc
func (cf ControllerFunc) Run(config Config) error { return cf(config) }

func New() Controller {
	return new(controllerImpl)
}

// Run executes a control loop that registers a framework with Mesos and processes the scheduler events
// that flow through the subscription. Upon disconnection, if the given Context reports !Done() then the
// controller will attempt to re-register the framework and continue processing events.
func (_ *controllerImpl) Run(config Config) (lastErr error) {
	subscribe := calls.Subscribe(config.Framework)
	for !config.Context.Done() {
		frameworkID := config.Context.FrameworkID()
		if config.Framework.GetFailoverTimeout() > 0 && frameworkID != "" {
			subscribe.With(calls.SubscribeTo(frameworkID))
		}
		<-config.RegistrationTokens
		resp, err := config.Caller.Call(subscribe)
		lastErr = processSubscription(config, resp, err)
		config.Context.Error(lastErr)
	}
	return
}

func processSubscription(config Config, resp mesos.Response, err error) error {
	if resp != nil {
		defer resp.Close()
	}
	if err == nil {
		err = eventLoop(config, resp)
	}
	return err
}

// eventLoop returns the framework ID received by mesos (if any); callers should check for a
// framework ID regardless of whether error != nil.
func eventLoop(config Config, eventDecoder encoding.Decoder) (err error) {
	h := config.Handler
	if h == nil {
		h = events.HandlerFunc(DefaultHandler)
	}
	for err == nil && !config.Context.Done() {
		var e scheduler.Event
		if err = eventDecoder.Decode(&e); err == nil {
			err = h.HandleEvent(&e)
		}
	}
	return err
}

var _ = Context(&ContextAdapter{}) // ContextAdapter implements Context

func (ca *ContextAdapter) Done() bool {
	return ca.DoneFunc != nil && ca.DoneFunc()
}
func (ca *ContextAdapter) FrameworkID() (id string) {
	if ca.FrameworkIDFunc != nil {
		id = ca.FrameworkIDFunc()
	}
	return
}
func (ca *ContextAdapter) Error(err error) {
	if ca.ErrorFunc != nil {
		ca.ErrorFunc(err)
	}
}

// ErrEvent errors are generated by the DefaultHandler upon receiving an ERROR event from Mesos.
type ErrEvent string

func (e ErrEvent) Error() string {
	return string(e)
}

// DefaultHandler provides the minimum implementation required for correct controller behavior.
func DefaultHandler(e *scheduler.Event) (err error) {
	if e.GetType() == scheduler.Event_ERROR {
		// it's recommended that we abort and re-try subscribing; returning an
		// error here will cause the event loop to terminate and the connection
		// will be reset.
		err = ErrEvent(e.GetError().GetMessage())
	}
	return
}
<commit_msg>fix RegistrationTokens bug<commit_after>package controller

import (
	"github.com/mesos/mesos-go/api/v1/lib"
	"github.com/mesos/mesos-go/api/v1/lib/encoding"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler/calls"
	"github.com/mesos/mesos-go/api/v1/lib/scheduler/events"
)

type (
	Context interface {
		// Done returns true when the controller should exit
		Done() bool

		// FrameworkID returns the current Mesos-assigned framework ID. Frameworks are expected to
		// track this ID (that comes from Mesos, in a SUBSCRIBED event).
		FrameworkID() string

		// Error is an error handler that is invoked at the end of every subscription cycle; the given
		// error may be nil (if no errors occurred).
		Error(error)
	}

	ContextAdapter struct {
		// FrameworkIDFunc is optional; nil tells the controller to always register as a new framework
		// for each subscription attempt.
		FrameworkIDFunc func() string

		// Done is optional; nil equates to a func that always returns false
		DoneFunc func() bool

		// ErrorFunc is optional; if nil then errors are swallowed
		ErrorFunc func(error)
	}

	Config struct {
		Context   Context              // Context is required
		Framework *mesos.FrameworkInfo // FrameworkInfo is required
		Caller    calls.Caller         // Caller  is required

		// Handler (optional) processes scheduler events. The controller's internal event processing
		// loop is aborted if a Handler returns a non-nil error, after which the controller may attempt
		// to re-register (subscribe) with Mesos.
		Handler events.Handler

		// RegistrationTokens (optional) limits the rate at which a framework (re)registers with Mesos.
		// The chan should either be non-blocking, or should yield a struct{} in order to allow the
		// framework registration process to continue. May be nil.
		RegistrationTokens <-chan struct{}
	}

	Controller interface {
		// Run executes the controller using the given Config
		Run(Config) error
	}

	// ControllerFunc is a functional adaptation of a Controller
	ControllerFunc func(Config) error

	controllerImpl int
)

// Run implements Controller for ControllerFunc
func (cf ControllerFunc) Run(config Config) error { return cf(config) }

func New() Controller {
	return new(controllerImpl)
}

// Run executes a control loop that registers a framework with Mesos and processes the scheduler events
// that flow through the subscription. Upon disconnection, if the given Context reports !Done() then the
// controller will attempt to re-register the framework and continue processing events.
func (_ *controllerImpl) Run(config Config) (lastErr error) {
	subscribe := calls.Subscribe(config.Framework)
	for !config.Context.Done() {
		frameworkID := config.Context.FrameworkID()
		if config.Framework.GetFailoverTimeout() > 0 && frameworkID != "" {
			subscribe.With(calls.SubscribeTo(frameworkID))
		}
		if config.RegistrationTokens != nil {
			<-config.RegistrationTokens
		}
		resp, err := config.Caller.Call(subscribe)
		lastErr = processSubscription(config, resp, err)
		config.Context.Error(lastErr)
	}
	return
}

func processSubscription(config Config, resp mesos.Response, err error) error {
	if resp != nil {
		defer resp.Close()
	}
	if err == nil {
		err = eventLoop(config, resp)
	}
	return err
}

// eventLoop returns the framework ID received by mesos (if any); callers should check for a
// framework ID regardless of whether error != nil.
func eventLoop(config Config, eventDecoder encoding.Decoder) (err error) {
	h := config.Handler
	if h == nil {
		h = events.HandlerFunc(DefaultHandler)
	}
	for err == nil && !config.Context.Done() {
		var e scheduler.Event
		if err = eventDecoder.Decode(&e); err == nil {
			err = h.HandleEvent(&e)
		}
	}
	return err
}

var _ = Context(&ContextAdapter{}) // ContextAdapter implements Context

func (ca *ContextAdapter) Done() bool {
	return ca.DoneFunc != nil && ca.DoneFunc()
}
func (ca *ContextAdapter) FrameworkID() (id string) {
	if ca.FrameworkIDFunc != nil {
		id = ca.FrameworkIDFunc()
	}
	return
}
func (ca *ContextAdapter) Error(err error) {
	if ca.ErrorFunc != nil {
		ca.ErrorFunc(err)
	}
}

// ErrEvent errors are generated by the DefaultHandler upon receiving an ERROR event from Mesos.
type ErrEvent string

func (e ErrEvent) Error() string {
	return string(e)
}

// DefaultHandler provides the minimum implementation required for correct controller behavior.
func DefaultHandler(e *scheduler.Event) (err error) {
	if e.GetType() == scheduler.Event_ERROR {
		// it's recommended that we abort and re-try subscribing; returning an
		// error here will cause the event loop to terminate and the connection
		// will be reset.
		err = ErrEvent(e.GetError().GetMessage())
	}
	return
}
<|endoftext|>