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

package simplepush

import (
	"code.google.com/p/go.net/websocket"
	"mozilla.org/simplepush/sperrors"
	"mozilla.org/simplepush/storage"
	"mozilla.org/util"

	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
    "log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"runtime/debug"
	"strconv"
	"strings"
	"time"
)

func awsGetPublicHostname() (hostname string, err error) {
	req := &http.Request{Method: "GET",
		URL: &url.URL{
			Scheme: "http",
			Host:   "169.254.169.254",
			Path:   "/latest/meta-data/public-hostname"}}
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode >= 200 && resp.StatusCode < 300 {
		var hostBytes []byte
		hostBytes, err = ioutil.ReadAll(resp.Body)
		if err == nil {
			hostname = string(hostBytes)
		}
		return
	}
	return
}

func FixConfig(config util.JsMap) util.JsMap {
	if _, ok := config["shard.current_host"]; !ok {
		currentHost := "localhost"
		if val := os.Getenv("HOST"); len(val) > 0 {
			currentHost = val
		} else {
			if util.MzGetFlag(config, "shard.use_aws_host") {
				var awsHost string
				var err error
				awsHost, err = awsGetPublicHostname()
				if err == nil {
					currentHost = awsHost
				}
			}
		}
		config["shard.current_host"] = currentHost
	}
	// Convert the token_key from base64 (if present)
	if k, ok := config["token_key"]; ok {
		key, err := base64.URLEncoding.DecodeString(k.(string))
        if err != nil {
            log.Fatal(err)
        }

		config["token_key"] = key
	}

	config["heka.current_host"] = config["shard.current_host"]

	return config

}

type Handler struct {
    config util.JsMap
    logger *util.HekaLogger
}

func NewHandler(config util.JsMap, logger *util.HekaLogger) *Handler {
    return &Handler{config: config,
    logger: logger}
}

// VIP response
func (self *Handler) StatusHandler(resp http.ResponseWriter, req *http.Request) {
	// return "OK" only if all is well.
	// TODO: make sure all is well.
	resp.Write([]byte("OK"))
}

func proxyNotification(host, path string) (err error) {
	req := &http.Request{Method: "PUT",
		URL: &url.URL{
			Scheme: "http",
			Host:   host,
			Path:   path}}
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		return err
	}
	if resp.StatusCode >= 200 && resp.StatusCode <= 300 {
		return nil
	}
	body, err := ioutil.ReadAll(resp.Body)
	return errors.New(fmt.Sprintf("Proxy failed. Returned (%d)\n %s",
		resp.StatusCode, body))
}

// -- REST
func (self *Handler) UpdateHandler(resp http.ResponseWriter, req *http.Request) {
	// Handle the version updates.
	var err error
	var port string
	var vers int64

	timer := time.Now()
	filter := regexp.MustCompile("[^\\w-\\.\\=]")
    self.logger.Debug("main", "Config", self.config)

	self.logger.Debug("main",
        fmt.Sprintf("Handling Update %s", req.URL.Path), nil)
	if req.Method != "PUT" {
		http.Error(resp, "", http.StatusMethodNotAllowed)
		return
	}

	svers := req.FormValue("version")
	if svers != "" {
		vers, err = strconv.ParseInt(svers, 10, 64)
		if err != nil || vers < 0 {
			http.Error(resp, "\"Invalid Version\"", http.StatusBadRequest)
			return
		}
	} else {
		vers = time.Now().UTC().Unix()
	}

	elements := strings.Split(req.URL.Path, "/")
	pk := elements[len(elements)-1]
	if len(pk) == 0 {
		self.logger.Error("main", "No token, rejecting request",
			util.JsMap{"remoteAddr": req.RemoteAddr})
		http.Error(resp, "Token not found", http.StatusNotFound)
		return
	}

	store := storage.New(self.config, self.logger)
	if token, ok := self.config["token_key"]; ok && len(token.([]uint8)) > 0 {
        self.logger.Debug("main", "Decoding key", util.JsMap{"token": token})
		var err error
		bpk, err := Decode(token.([]byte),
			pk)
		if err != nil {
			self.logger.Error("main",
				"Could not decode token",
				util.JsMap{"primarykey": pk,
					"remoteAddr": req.RemoteAddr,
					"path":       req.RequestURI,
					"error":      err})
			http.Error(resp, "", http.StatusNotFound)
			return
		}

		pk = strings.TrimSpace(string(bpk))
	}

	if filter.Find([]byte(pk)) != nil {
		self.logger.Error("main",
			"Invalid token for update",
			nil)
		http.Error(resp, "Invalid Token", http.StatusNotFound)
		return
	}

	uaid, appid, err := storage.ResolvePK(pk)
	if err != nil {
	    self.logger.Error("main",
			fmt.Sprintf("Could not resolve PK %s, %s", pk, err), nil)
		return
	}

	if appid == "" {
		self.logger.Error("main",
			"Incomplete primary key",
			util.JsMap{"uaid": uaid,
				"channelID":  appid,
				"remoteAddr": req.RemoteAddr})
		return
	}

	if iport, ok := self.config["port"]; ok {
		port = iport.(string)
	}
	if port != "" && port != "80" {
		port = ":" + port
	}
	currentHost := util.MzGet(self.config, "shard.current_host", "localhost")
	host, err := store.GetUAIDHost(uaid)
	if err != nil {
		self.logger.Error("main",
			fmt.Sprintf("Could not discover host for %s, %s (using default)",
				uaid, err), nil)
		host = util.MzGet(self.config, "shard.defaultHost", "localhost")
	}
	if util.MzGetFlag(self.config, "shard.doProxy") {
		if host != currentHost && host != "localhost" {
			self.logger.Info("main",
				fmt.Sprintf("Proxying request to %s", host+port), nil)
			err = proxyNotification(host+port, req.URL.Path)
			if err != nil {
				self.logger.Error("main",
					fmt.Sprintf("Proxy to %s failed: %s", host+port, err),
					nil)
			}
			return
		}
	}

	defer func(uaid, appid, path string, timer time.Time) {
		self.logger.Info("timer", "Client Update complete",
			util.JsMap{
				"uaid":      uaid,
				"path":      req.URL.Path,
				"channelID": appid,
				"duration":  time.Now().Sub(timer).Nanoseconds()})
	}(uaid, appid, req.URL.Path, timer)

	self.logger.Info("main",
		fmt.Sprintf("setting version for %s.%s to %d", uaid, appid, vers),
		nil)
	err = store.UpdateChannel(pk, vers)

	if err != nil {
		errstr := fmt.Sprintf("Could not update channel %s.%s :: %s", uaid, appid, err)
		self.logger.Warn("main", errstr, nil)
		status, _ := sperrors.ErrToStatus(err)
		http.Error(resp, errstr, status)
		return
	}
	resp.Header().Set("Content-Type", "application/json")
	resp.Write([]byte("{}"))
	self.logger.Info("timer", "Client Update complete",
		util.JsMap{"uaid": uaid,
			"channelID": appid,
			"duration":  time.Now().Sub(timer).Nanoseconds()})
	// Ping the appropriate server
	if client, ok := Clients[uaid]; ok {
		Flush(client)
	}
	return
}

func (self *Handler) PushSocketHandler(ws *websocket.Conn) {
	timer := time.Now()
	store := storage.New(self.config, self.logger)
	sock := PushWS{Uaid: "",
		Socket: ws,
		Scmd:   make(chan PushCommand),
		Ccmd:   make(chan PushCommand),
		Store:  store,
		Logger: self.logger,
		Born:   timer}

	sock.Logger.Info("main", "New socket connection detected", nil)
	defer func(log *util.HekaLogger) {
		if r := recover(); r != nil {
			debug.PrintStack()
			log.Error("main", "Unknown error", util.JsMap{"error": r.(error).Error()})
		}
	}(sock.Logger)

	go NewWorker(self.config).Run(sock)
	for {
		select {
		case serv_cmd := <-sock.Scmd:
			result, args := HandleServerCommand(serv_cmd, &sock)
			sock.Logger.Debug("main",
				fmt.Sprintf("Returning Result %s", result),
				nil)
			sock.Scmd <- PushCommand{result, args}
		}
	}
}

// o4fs
// vim: set tabstab=4 softtabstop=4 shiftwidth=4 noexpandtab
<commit_msg>Heka message cleanup.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package simplepush

import (
	"code.google.com/p/go.net/websocket"
	"mozilla.org/simplepush/sperrors"
	"mozilla.org/simplepush/storage"
	"mozilla.org/util"

	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"runtime/debug"
	"strconv"
	"strings"
	"time"
)

func awsGetPublicHostname() (hostname string, err error) {
	req := &http.Request{Method: "GET",
		URL: &url.URL{
			Scheme: "http",
			Host:   "169.254.169.254",
			Path:   "/latest/meta-data/public-hostname"}}
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode >= 200 && resp.StatusCode < 300 {
		var hostBytes []byte
		hostBytes, err = ioutil.ReadAll(resp.Body)
		if err == nil {
			hostname = string(hostBytes)
		}
		return
	}
	return
}

func FixConfig(config util.JsMap) util.JsMap {
	if _, ok := config["shard.current_host"]; !ok {
		currentHost := "localhost"
		if val := os.Getenv("HOST"); len(val) > 0 {
			currentHost = val
		} else {
			if util.MzGetFlag(config, "shard.use_aws_host") {
				var awsHost string
				var err error
				awsHost, err = awsGetPublicHostname()
				if err == nil {
					currentHost = awsHost
				}
			}
		}
		config["shard.current_host"] = currentHost
	}
	// Convert the token_key from base64 (if present)
	if k, ok := config["token_key"]; ok {
		key, err := base64.URLEncoding.DecodeString(k.(string))
		if err != nil {
			log.Fatal(err)
		}

		config["token_key"] = key
	}

	config["heka.current_host"] = config["shard.current_host"]

	return config

}

type Handler struct {
	config util.JsMap
	logger *util.HekaLogger
}

func NewHandler(config util.JsMap, logger *util.HekaLogger) *Handler {
	return &Handler{config: config,
		logger: logger}
}

// VIP response
func (self *Handler) StatusHandler(resp http.ResponseWriter, req *http.Request) {
	// return "OK" only if all is well.
	// TODO: make sure all is well.
	resp.Write([]byte("OK"))
}

func proxyNotification(host, path string) (err error) {
	req := &http.Request{Method: "PUT",
		URL: &url.URL{
			Scheme: "http",
			Host:   host,
			Path:   path}}
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		return err
	}
	if resp.StatusCode >= 200 && resp.StatusCode <= 300 {
		return nil
	}
	body, err := ioutil.ReadAll(resp.Body)
	return errors.New(fmt.Sprintf("Proxy failed. Returned (%d)\n %s",
		resp.StatusCode, body))
}

// -- REST
func (self *Handler) UpdateHandler(resp http.ResponseWriter, req *http.Request) {
	// Handle the version updates.
	var err error
	var port string
	var vers int64

	timer := time.Now()
	filter := regexp.MustCompile("[^\\w-\\.\\=]")
	self.logger.Debug("main", "Config", self.config)

	self.logger.Debug("update", "Handling Update",
		util.JsMap{"path": req.URL.Path})
	if req.Method != "PUT" {
		http.Error(resp, "", http.StatusMethodNotAllowed)
		return
	}

	svers := req.FormValue("version")
	if svers != "" {
		vers, err = strconv.ParseInt(svers, 10, 64)
		if err != nil || vers < 0 {
			http.Error(resp, "\"Invalid Version\"", http.StatusBadRequest)
			return
		}
	} else {
		vers = time.Now().UTC().Unix()
	}

	elements := strings.Split(req.URL.Path, "/")
	pk := elements[len(elements)-1]
	if len(pk) == 0 {
		self.logger.Error("update", "No token, rejecting request",
			util.JsMap{"remoteAddr": req.RemoteAddr,
				"path": req.URL.Path})
		http.Error(resp, "Token not found", http.StatusNotFound)
		return
	}

	store := storage.New(self.config, self.logger)
	if token, ok := self.config["token_key"]; ok && len(token.([]uint8)) > 0 {
		self.logger.Debug("main", "Decoding key", util.JsMap{"token": token})
		var err error
		bpk, err := Decode(token.([]byte),
			pk)
		if err != nil {
			self.logger.Error("update",
				"Could not decode token",
				util.JsMap{"primarykey": pk,
					"remoteAddr": req.RemoteAddr,
					"path":       req.URL.Path,
					"error":      err})
			http.Error(resp, "", http.StatusNotFound)
			return
		}

		pk = strings.TrimSpace(string(bpk))
	}

	if filter.Find([]byte(pk)) != nil {
		self.logger.Error("update",
			"Invalid token for update",
			util.JsMap{"token": pk,
				"path": req.URL.Path})
		http.Error(resp, "Invalid Token", http.StatusNotFound)
		return
	}

	uaid, appid, err := storage.ResolvePK(pk)
	if err != nil {
		self.logger.Error("update",
			"Could not resolve PK",
			util.JsMap{"primaryKey": pk,
				"path":  req.URL.Path,
				"error": err})
		return
	}

	if appid == "" {
		self.logger.Error("update",
			"Incomplete primary key",
			util.JsMap{"uaid": uaid,
				"channelID":  appid,
				"remoteAddr": req.RemoteAddr})
		return
	}

	if iport, ok := self.config["port"]; ok {
		port = iport.(string)
	}
	if port != "" && port != "80" {
		port = ":" + port
	}
	currentHost := util.MzGet(self.config, "shard.current_host", "localhost")
	host, err := store.GetUAIDHost(uaid)
	if err != nil {
		self.logger.Error("update",
			"Could not discover host for UAID",
			util.JsMap{"uaid": uaid,
				"error": err})
		host = util.MzGet(self.config, "shard.defaultHost", "localhost")
	}
	if util.MzGetFlag(self.config, "shard.doProxy") {
		if host != currentHost && host != "localhost" {
			self.logger.Info("update",
				"Proxying request for UAID",
				util.JsMap{"uaid": uaid,
					"destination": host + port})
			err = proxyNotification(host+port, req.URL.Path)
			if err != nil {
				self.logger.Error("update",
					"Proxy failed", util.JsMap{
						"uaid":        uaid,
						"destination": host + port,
						"error":       err})
			}
			return
		}
	}

	defer func(uaid, appid, path string, timer time.Time) {
		self.logger.Info("timer", "Client Update complete",
			util.JsMap{
				"uaid":      uaid,
				"path":      req.URL.Path,
				"channelID": appid,
				"duration":  time.Now().Sub(timer).Nanoseconds()})
	}(uaid, appid, req.URL.Path, timer)

	self.logger.Info("update",
		"setting version for ChannelID",
		util.JsMap{"uaid": uaid, "channelID": appid, "version": vers})
	err = store.UpdateChannel(pk, vers)

	if err != nil {
		self.logger.Error("update", "Cound not update channel",
			util.JsMap{"UAID": uaid,
				"channelID": appid,
				"version":   vers,
				"error":     err})
		status, _ := sperrors.ErrToStatus(err)
		http.Error(resp, "Could not update channel version", status)
		return
	}
	resp.Header().Set("Content-Type", "application/json")
	resp.Write([]byte("{}"))
	self.logger.Info("timer", "Client Update complete",
		util.JsMap{"uaid": uaid,
			"channelID": appid,
			"duration":  time.Now().Sub(timer).Nanoseconds()})
	// Ping the appropriate server
	if client, ok := Clients[uaid]; ok {
		Flush(client)
	}
	return
}

func (self *Handler) PushSocketHandler(ws *websocket.Conn) {
	timer := time.Now()
	store := storage.New(self.config, self.logger)
	sock := PushWS{Uaid: "",
		Socket: ws,
		Scmd:   make(chan PushCommand),
		Ccmd:   make(chan PushCommand),
		Store:  store,
		Logger: self.logger,
		Born:   timer}

	sock.Logger.Info("main", "New socket connection detected", nil)
	defer func(log *util.HekaLogger) {
		if r := recover(); r != nil {
			debug.PrintStack()
			log.Error("main", "Unknown error",
				util.JsMap{"error": r.(error).Error()})
		}
	}(sock.Logger)

	go NewWorker(self.config).Run(sock)
	for {
		select {
		case serv_cmd := <-sock.Scmd:
			result, args := HandleServerCommand(serv_cmd, &sock)
			sock.Logger.Debug("main",
				"Server Returning Result",
				util.JsMap{"result": result,
					"args": args})
			sock.Scmd <- PushCommand{result, args}
		}
	}
}

// o4fs
// vim: set tabstab=4 softtabstop=4 shiftwidth=4 noexpandtab
<|endoftext|>


<commit_before>package pack

import (
	"testing"
)

func BenchmarkTemplateReportallocs(b *testing.B) {
	for i := 0; i < b.N; i++ {
		user := NewUserReportallocs("test2")
		SayHelloReportallocs(user)
	}
}

func BenchmarkTemplateCopy(b *testing.B) {
	for i := 0; i < b.N; i++ {
		user := NewUserReportallocs("test2")
		SayHelloReportallocs(user)
	}
}
<commit_msg>reportallocs benchmark test<commit_after>package pack

import (
	"testing"
)

func BenchmarkTemplateReportallocs(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		user := NewUserReportallocs("test2")
		SayHelloReportallocs(user)
	}
}

func BenchmarkTemplateCopy(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		user := NewUserReportallocs("test2")
		SayHelloReportallocs(user)
	}
}
<|endoftext|>


<commit_before>package gomegamatchers

import (
	"fmt"
	"reflect"

	"github.com/cloudfoundry-incubator/candiedyaml"
	"github.com/onsi/gomega/format"
	"github.com/onsi/gomega/types"
)

func MatchYAML(expected interface{}) types.GomegaMatcher {
	return &MatchYAMLMatcher{expected}
}

type MatchYAMLMatcher struct {
	YAMLToMatch interface{}
}

func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) {
	actualString, err := matcher.prettyPrint(actual)
	if err != nil {
		return false, err
	}

	expectedString, err := matcher.prettyPrint(matcher.YAMLToMatch)
	if err != nil {
		return false, err
	}

	var aval interface{}
	var eval interface{}

	// this is guarded by prettyPrint
	candiedyaml.Unmarshal([]byte(actualString), &aval)
	candiedyaml.Unmarshal([]byte(expectedString), &eval)

	return reflect.DeepEqual(aval, eval), nil
}

func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
	actualString, _ := matcher.prettyPrint(actual)
	expectedString, _ := matcher.prettyPrint(matcher.YAMLToMatch)
	return format.Message(actualString, "to match YAML of", expectedString)
}

func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	actualString, _ := matcher.prettyPrint(actual)
	expectedString, _ := matcher.prettyPrint(matcher.YAMLToMatch)
	return format.Message(actualString, "not to match YAML of", expectedString)
}

func (matcher *MatchYAMLMatcher) prettyPrint(input interface{}) (formatted string, err error) {
	inputString, ok := toString(input)
	if !ok {
		return "", fmt.Errorf("MatchYAMLMatcher matcher requires a string or stringer.  Got:\n%s", format.Object(input, 1))
	}

	var data interface{}
	if err := candiedyaml.Unmarshal([]byte(inputString), &data); err != nil {
		return "", err
	}
	buf, _ := candiedyaml.Marshal(data)

	return string(buf), nil
}

func toString(a interface{}) (string, bool) {
	aString, isString := a.(string)
	if isString {
		return aString, true
	}

	aBytes, isBytes := a.([]byte)
	if isBytes {
		return string(aBytes), true
	}

	aStringer, isStringer := a.(fmt.Stringer)
	if isStringer {
		return aStringer.String(), true
	}

	return "", false
}
<commit_msg>Improve variable naming<commit_after>package gomegamatchers

import (
	"fmt"
	"reflect"

	"github.com/cloudfoundry-incubator/candiedyaml"
	"github.com/onsi/gomega/format"
	"github.com/onsi/gomega/types"
)

func MatchYAML(expected interface{}) types.GomegaMatcher {
	return &MatchYAMLMatcher{expected}
}

type MatchYAMLMatcher struct {
	YAMLToMatch interface{}
}

func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) {
	actualString, err := matcher.prettyPrint(actual)
	if err != nil {
		return false, err
	}

	expectedString, err := matcher.prettyPrint(matcher.YAMLToMatch)
	if err != nil {
		return false, err
	}

	var actualValue interface{}
	var expectedValue interface{}

	// this is guarded by prettyPrint
	candiedyaml.Unmarshal([]byte(actualString), &actualValue)
	candiedyaml.Unmarshal([]byte(expectedString), &expectedValue)

	return reflect.DeepEqual(actualValue, expectedValue), nil
}

func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
	actualString, _ := matcher.prettyPrint(actual)
	expectedString, _ := matcher.prettyPrint(matcher.YAMLToMatch)
	return format.Message(actualString, "to match YAML of", expectedString)
}

func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
	actualString, _ := matcher.prettyPrint(actual)
	expectedString, _ := matcher.prettyPrint(matcher.YAMLToMatch)
	return format.Message(actualString, "not to match YAML of", expectedString)
}

func (matcher *MatchYAMLMatcher) prettyPrint(input interface{}) (formatted string, err error) {
	inputString, ok := toString(input)
	if !ok {
		return "", fmt.Errorf("MatchYAMLMatcher matcher requires a string or stringer.  Got:\n%s", format.Object(input, 1))
	}

	var data interface{}
	if err := candiedyaml.Unmarshal([]byte(inputString), &data); err != nil {
		return "", err
	}
	buf, _ := candiedyaml.Marshal(data)

	return string(buf), nil
}

func toString(value interface{}) (string, bool) {
	valueString, isString := value.(string)
	if isString {
		return valueString, true
	}

	valueBytes, isBytes := value.([]byte)
	if isBytes {
		return string(valueBytes), true
	}

	valueStringer, isStringer := value.(fmt.Stringer)
	if isStringer {
		return valueStringer.String(), true
	}

	return "", false
}
<|endoftext|>


<commit_before>package xrouter

import (
	"net/http"
	"strings"

	"github.com/julienschmidt/httprouter"
	"github.com/rs/xhandler"

	"golang.org/x/net/context"
)

// ParamsKey is the key for xhandler contexts which grant access to the url params.
const ParamsKey = "params"

// httpParamsHandler is middleware which links xhandler and httprouter.
func httpParamsHandler(chain *xhandler.Chain, handler xhandler.HandlerFuncC) httprouter.Handle {
	h := chain.HandlerC(xhandler.HandlerFuncC(handler))
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := context.WithValue(context.Background(), ParamsKey, params)
		h.ServeHTTPC(ctx, w, req)
	}
}

// httpParamsHandler is middleware which links xhandler and httprouter.
func stripPrefixHandler(prefix string, handler xhandler.HandlerFuncC) xhandler.HandlerFuncC {
	if prefix == "" {
		return handler
	}
	return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
			r.URL.Path = p
			handler.ServeHTTPC(ctx, w, r)
		} else {
			http.NotFound(w, r)
		}
	})
}

// HttpHandler wraps a raw http.Handler in chain middleware.
func HttpHandler(c *xhandler.Chain, fs http.Handler) http.Handler {
	return c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		fs.ServeHTTP(w, r)
	}))
}
<commit_msg>Add logging middleware<commit_after>package xrouter

import (
	"net/http"
	"strings"
	"time"

	"github.com/julienschmidt/httprouter"
	"github.com/rs/xhandler"
	"github.com/rs/xlog"

	"golang.org/x/net/context"
)

// ParamsKey is the key for xhandler contexts which grant access to the url params.
const ParamsKey = "params"

// httpParamsHandler is middleware which links xhandler and httprouter.
func httpParamsHandler(chain *xhandler.Chain, handler xhandler.HandlerFuncC) httprouter.Handle {
	h := chain.HandlerC(xhandler.HandlerFuncC(handler))
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := context.WithValue(context.Background(), ParamsKey, params)
		h.ServeHTTPC(ctx, w, req)
	}
}

// httpParamsHandler is middleware which links xhandler and httprouter.
func stripPrefixHandler(prefix string, handler xhandler.HandlerFuncC) xhandler.HandlerFuncC {
	if prefix == "" {
		return handler
	}
	return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
			r.URL.Path = p
			handler.ServeHTTPC(ctx, w, r)
		} else {
			http.NotFound(w, r)
		}
	})
}

// HttpHandler wraps a raw http.Handler in chain middleware.
func HttpHandler(c *xhandler.Chain, fs http.Handler) http.Handler {
	return c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		fs.ServeHTTP(w, r)
	}))
}

// LogHandler instantiates a new xlog HTTP handler using the given log.
func LogHandler(l xlog.Logger) func(xhandler.HandlerC) xhandler.HandlerC {
	return func(next xhandler.HandlerC) xhandler.HandlerC {
		return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			ptw := passThroughResponseWriter{200, w}
			ctx = xlog.NewContext(ctx, l)
			start := time.Now()
			next.ServeHTTPC(ctx, &ptw, r)
			l.Info(http.StatusText(ptw.StatusCode), xlog.F{
				"duration": time.Now().Sub(start).String(),
				"status":   ptw.StatusCode,
			})
		})
	}
}

type passThroughResponseWriter struct {
	StatusCode     int
	ResponseWriter http.ResponseWriter
}

func (p *passThroughResponseWriter) WriteHeader(code int) {
	p.StatusCode = code
	p.ResponseWriter.WriteHeader(code)
}

func (p *passThroughResponseWriter) Header() http.Header {
	return p.ResponseWriter.Header()
}

func (p *passThroughResponseWriter) Write(data []byte) (int, error) {
	return p.ResponseWriter.Write(data)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 RightScale, Inc., see LICENSE

// Middlewares fo goji

package gojiutil

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"github.com/zenazn/goji/web/mutil"
	"gopkg.in/inconshreveable/log15.v2"
)

// ContextLog is the hash key in which ContextLogger places the log15 context logger
var ContextLog string = "log"

// Add the following common middlewares: EnvInit, RealIP, RequestID
func AddCommon(mx *web.Mux) {
	mx.Use(middleware.EnvInit)
	mx.Use(RequestID)
	mx.Use(middleware.RealIP)
}

// Add the following common middlewares: EnvInit, RealIP, RequestID, Logger15, Recoverer, FormParser
func AddCommon15(mx *web.Mux, log log15.Logger) {
	AddCommon(mx)
	mx.Use(ContextLogger)
	mx.Use(Logger15(log))
	mx.Use(Recoverer)
	mx.Use(FormParser)
}

// Create a simple middleware that merges a map into c.Env
func EnvAdd(m map[string]interface{}) web.MiddlewareType {
	return func(c *web.C, h http.Handler) http.Handler {
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			for k, v := range m {
				c.Env[k] = v
			}
			h.ServeHTTP(rw, r)
		})
	}
}

// Create a logger middleware that logs HTTP requests and results to log15
// Assumes that c.Env is allocated, use goji/middleware.EnvInit for that
// Prints a requestID if one is present, use goji/middleware.RequestID
// Prints the requestor's IP address, use goji/middleware.RealIP
func Logger15(logger log15.Logger) web.MiddlewareType {
	// Logger15 returns a middleware (which is a function):
	return func(c *web.C, h http.Handler) http.Handler {
		// The middleware returns a function to process requests:
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			ctx := make([]interface{}, 0)

			// record info about the request
			if id := middleware.GetReqID(*c); id != "" {
				ctx = append(ctx, "req", id)
			}
			ctx = append(ctx, "verb", r.Method)
			path := r.URL.Path
			ip := r.RemoteAddr
			if ip != "" {
				ctx = append(ctx, "ip", ip)
			}

			// call handler down the stack with a wrapper writer so we see what it does
			wp := mutil.WrapWriter(rw)
			start := time.Now()
			h.ServeHTTP(wp, r)
			ctx = append(ctx, "time", time.Now().Sub(start).String())

			// record info about the response
			s := wp.Status()
			ctx = append(ctx, "status", strconv.Itoa(s))
			if e, ok := c.Env["err"].(string); ok {
				ctx = append(ctx, "err", e)
			}

			switch {
			// for 500 errors be prepared to log a stack trace
			case s >= 500:
				switch s := c.Env["stack"].(type) {
				case string:
					ctx = append(ctx, "stack", s)
				case []string:
					// got full stack trace, then remove goroutine number
					// and top-level (which is where runtime.Stack is called)
					if strings.HasPrefix(s[0], "goroutine") && len(s) > 3 {
						s = s[3:]
					}
					// now put top N levels into stack%d variables
					const levels = 3 // number of stack levels to print
					for i := 0; i < levels && 2*i+1 < len(s); i += 1 {
						funcName := s[2*i][:strings.Index(s[2*i], "(")]
						sourceLine := strings.TrimLeft(s[2*i+1], "\t")
						ctx = append(ctx, fmt.Sprintf("stack%d", i), funcName+" @ "+sourceLine)
					}
				}
				logger.Crit(path, ctx...)
			// for 400 errors log a warning (debatable)
			case s >= 400:
				logger.Warn(path, ctx...)
			// for everything else just log info
			default:
				logger.Info(path, ctx...)
			}
		})
	}
}

// ParamsLogger logs all query string / form parameters primarily for debug purposes. It logs
// at the start of a request using log15.Debug (or c.Env[ContextLog].Debug if defined) unlike
// the Logger15 middleware, which logs at the end. If verbose is true then
// the c.URLParams and the c.Env hashes are also logged
func ParamsLogger(verbose bool) web.MiddlewareType {
	return func(c *web.C, h http.Handler) http.Handler {
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			params := []interface{}{}
			for k, v := range r.Form {
				params = append(params, k, v[0])
			}
			log, ok := c.Env[ContextLog].(log15.Logger)
			if !ok || log == nil {
				log = log15.Root()
			}
			if verbose {
				log.Debug("Begin "+r.Method+" "+r.URL.Path,
					"params", fmt.Sprintf("%+v", params),
					"URLParams", fmt.Sprintf("%+v", c.URLParams),
					"Env", fmt.Sprintf("%+v", c.Env))
			} else {
				log.Debug("Begin "+r.Method+" "+r.URL.Path, params...)
			}
			h.ServeHTTP(rw, r)
		})
	}
}

// Create a panic-catching middleware for Echo that ensures the server doesn't die if one of
// the handlers panics. Also puts the call stack into the Echo Context which causes the logger
// middleware to log it.
func Recoverer(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		// Handle panics
		defer func() {
			if err := recover(); err != nil {
				// write stack backtrace into c.Env, max 64KB
				const size = 64 << 10 // 64KB
				buf := make([]byte, size)
				buf = buf[:runtime.Stack(buf, false)]
				lines := strings.Split(string(buf), "\n")
				//log15.Warn("Panic skipping", "l0", lines[0], "l1", lines[1],
				//	"l2", lines[2])
				c.Env["stack"] = lines[3:]
				Errorf(*c, rw, 500, "panic: %v", err)
			}
		}()
		h.ServeHTTP(rw, r)
	})
}

// FormParser simply calls Request.FormParse to get all params into the request
func FormParser(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		if err := r.ParseForm(); err != nil {
			// we assume any errors are due to the request, not internal
			ErrorString(*c, rw, http.StatusBadRequest, err.Error())
			return
		}
		h.ServeHTTP(rw, r)
	})
}

var RequestIDHeader = "X-Request-Id"
var reqPrefix string
var reqID int64

func init() {
	// algorithm taken from https://github.com/zenazn/goji/blob/master/web/middleware/request_id.go#L44-L50
	var buf [12]byte
	var b64 string
	for len(b64) < 10 {
		rand.Read(buf[:])
		b64 = base64.StdEncoding.EncodeToString(buf[:])
		b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
	}
	reqPrefix = string(b64[0:10])
}

// RequestID injects a request ID into the context of each request. Retrieve it using
// goji's GetReqID(). If the incoming request has a header of RequestIDHeader then that
// value is used, else a random value is generated
func RequestID(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		id := r.Header.Get(RequestIDHeader)
		if id == "" {
			id = fmt.Sprintf("%s-%d", reqPrefix, atomic.AddInt64(&reqID, 1))
		}
		c.Env[middleware.RequestIDKey] = id

		h.ServeHTTP(rw, r)
	})
}

// ContextLogger injects a log15 logger that is initialized to print the request ID. It
// assumes that c.Env[middleware.RequestIDKey] is set (e.g. by the RequestID middleware).
// It puts the logger into c.Env[gojiutil.ContextLogger].
func ContextLogger(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		if id, ok := c.Env[middleware.RequestIDKey].(string); ok {
			c.Env[ContextLog] = log15.New("req", id)
		}

		h.ServeHTTP(rw, r)
	})
}
<commit_msg>added GetJSONBody middleware<commit_after>// Copyright (c) 2015 RightScale, Inc., see LICENSE

// Middlewares fo goji

package gojiutil

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"github.com/zenazn/goji/web/mutil"
	"gopkg.in/inconshreveable/log15.v2"
)

// ContextLog is the hash key in which ContextLogger places the log15 context logger
var ContextLog string = "log"

// Add the following common middlewares: EnvInit, RealIP, RequestID
func AddCommon(mx *web.Mux) {
	mx.Use(middleware.EnvInit)
	mx.Use(RequestID)
	mx.Use(middleware.RealIP)
}

// Add the following common middlewares: EnvInit, RealIP, RequestID, Logger15, Recoverer, FormParser
func AddCommon15(mx *web.Mux, log log15.Logger) {
	AddCommon(mx)
	mx.Use(ContextLogger)
	mx.Use(Logger15(log))
	mx.Use(Recoverer)
	mx.Use(FormParser)
}

// Create a simple middleware that merges a map into c.Env
func EnvAdd(m map[string]interface{}) web.MiddlewareType {
	return func(c *web.C, h http.Handler) http.Handler {
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			for k, v := range m {
				c.Env[k] = v
			}
			h.ServeHTTP(rw, r)
		})
	}
}

// Create a logger middleware that logs HTTP requests and results to log15
// Assumes that c.Env is allocated, use goji/middleware.EnvInit for that
// Prints a requestID if one is present, use goji/middleware.RequestID
// Prints the requestor's IP address, use goji/middleware.RealIP
func Logger15(logger log15.Logger) web.MiddlewareType {
	// Logger15 returns a middleware (which is a function):
	return func(c *web.C, h http.Handler) http.Handler {
		// The middleware returns a function to process requests:
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			ctx := make([]interface{}, 0)

			// record info about the request
			if id := middleware.GetReqID(*c); id != "" {
				ctx = append(ctx, "req", id)
			}
			ctx = append(ctx, "verb", r.Method)
			path := r.URL.Path
			ip := r.RemoteAddr
			if ip != "" {
				ctx = append(ctx, "ip", ip)
			}

			// call handler down the stack with a wrapper writer so we see what it does
			wp := mutil.WrapWriter(rw)
			start := time.Now()
			h.ServeHTTP(wp, r)
			ctx = append(ctx, "time", time.Now().Sub(start).String())

			// record info about the response
			s := wp.Status()
			ctx = append(ctx, "status", strconv.Itoa(s))
			if e, ok := c.Env["err"].(string); ok {
				ctx = append(ctx, "err", e)
			}

			switch {
			// for 500 errors be prepared to log a stack trace
			case s >= 500:
				switch s := c.Env["stack"].(type) {
				case string:
					ctx = append(ctx, "stack", s)
				case []string:
					// got full stack trace, then remove goroutine number
					// and top-level (which is where runtime.Stack is called)
					if strings.HasPrefix(s[0], "goroutine") && len(s) > 3 {
						s = s[3:]
					}
					// now put top N levels into stack%d variables
					const levels = 3 // number of stack levels to print
					for i := 0; i < levels && 2*i+1 < len(s); i += 1 {
						funcName := s[2*i][:strings.Index(s[2*i], "(")]
						sourceLine := strings.TrimLeft(s[2*i+1], "\t")
						ctx = append(ctx, fmt.Sprintf("stack%d", i), funcName+" @ "+sourceLine)
					}
				}
				logger.Crit(path, ctx...)
			// for 400 errors log a warning (debatable)
			case s >= 400:
				logger.Warn(path, ctx...)
			// for everything else just log info
			default:
				logger.Info(path, ctx...)
			}
		})
	}
}

// ParamsLogger logs all query string / form parameters primarily for debug purposes. It logs
// at the start of a request using log15.Debug (or c.Env[ContextLog].Debug if defined) unlike
// the Logger15 middleware, which logs at the end. If verbose is true then
// the c.URLParams and the c.Env hashes are also logged
func ParamsLogger(verbose bool) web.MiddlewareType {
	return func(c *web.C, h http.Handler) http.Handler {
		return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			params := []interface{}{}
			for k, v := range r.Form {
				params = append(params, k, v[0])
			}
			log, ok := c.Env[ContextLog].(log15.Logger)
			if !ok || log == nil {
				log = log15.Root()
			}
			if verbose {
				log.Debug("Begin "+r.Method+" "+r.URL.Path,
					"params", fmt.Sprintf("%+v", params),
					"URLParams", fmt.Sprintf("%+v", c.URLParams),
					"Env", fmt.Sprintf("%+v", c.Env))
			} else {
				log.Debug("Begin "+r.Method+" "+r.URL.Path, params...)
			}
			h.ServeHTTP(rw, r)
		})
	}
}

// Create a panic-catching middleware for Echo that ensures the server doesn't die if one of
// the handlers panics. Also puts the call stack into the Echo Context which causes the logger
// middleware to log it.
func Recoverer(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		// Handle panics
		defer func() {
			if err := recover(); err != nil {
				// write stack backtrace into c.Env, max 64KB
				const size = 64 << 10 // 64KB
				buf := make([]byte, size)
				buf = buf[:runtime.Stack(buf, false)]
				lines := strings.Split(string(buf), "\n")
				//log15.Warn("Panic skipping", "l0", lines[0], "l1", lines[1],
				//	"l2", lines[2])
				c.Env["stack"] = lines[3:]
				Errorf(*c, rw, 500, "panic: %v", err)
			}
		}()
		h.ServeHTTP(rw, r)
	})
}

// FormParser simply calls Request.FormParse to get all params into the request
func FormParser(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		if err := r.ParseForm(); err != nil {
			// we assume any errors are due to the request, not internal
			ErrorString(*c, rw, http.StatusBadRequest, err.Error())
			return
		}
		h.ServeHTTP(rw, r)
	})
}

var RequestIDHeader = "X-Request-Id"
var reqPrefix string
var reqID int64

func init() {
	// algorithm taken from https://github.com/zenazn/goji/blob/master/web/middleware/request_id.go#L44-L50
	var buf [12]byte
	var b64 string
	for len(b64) < 10 {
		rand.Read(buf[:])
		b64 = base64.StdEncoding.EncodeToString(buf[:])
		b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
	}
	reqPrefix = string(b64[0:10])
}

// RequestID injects a request ID into the context of each request. Retrieve it using
// goji's GetReqID(). If the incoming request has a header of RequestIDHeader then that
// value is used, else a random value is generated
func RequestID(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		id := r.Header.Get(RequestIDHeader)
		if id == "" {
			id = fmt.Sprintf("%s-%d", reqPrefix, atomic.AddInt64(&reqID, 1))
		}
		c.Env[middleware.RequestIDKey] = id

		h.ServeHTTP(rw, r)
	})
}

// ContextLogger injects a log15 logger that is initialized to print the request ID. It
// assumes that c.Env[middleware.RequestIDKey] is set (e.g. by the RequestID middleware).
// It puts the logger into c.Env[gojiutil.ContextLogger].
func ContextLogger(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		if id, ok := c.Env[middleware.RequestIDKey].(string); ok {
			c.Env[ContextLog] = log15.New("req", id)
		}

		h.ServeHTTP(rw, r)
	})
}

// GetJSONBody is a middleware to read and parse an application/json body and store it in
// c.Env["json"] as a map[string]interface{}, which can be easily mapped to a proper struct
// using github.com/mitchellh/mapstructure.
// This middleware is pretty permissive: it allows for having no content-length and no
// content-type as long as either there's no body or the body parses as json.
func GetJSONBody(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		var err error

		// parse content-length header
		cl := 0
		if clh := r.Header.Get("content-length"); clh != "" {
			if cl, err = strconv.Atoi(clh); err != nil {
				ErrorString(*c, rw, 400, "Invalid content-length: "+err.Error())
				return
			}
		}

		// parse content-type header
		if ct := r.Header.Get("content-type"); ct != "" && ct != "application/json" {
			ErrorString(*c, rw, 400,
				"Invalid content-type '"+ct+"', application/json expected")
			return
		}

		/*
			// get the context logger, if available
			log, _ := c.Env[ContextLog].(log15.Logger)
			if log == nil {
				log = log15.Root()
			}
		*/

		// try to read body
		var js map[string]interface{}
		err = json.NewDecoder(r.Body).Decode(&js)
		switch err {
		case io.EOF:
			if cl != 0 {
				ErrorString(*c, rw, 400, "Premature EOF reading post body")
				return
			}
			//log.Debug("HTTP no request body")
			// got no body, so we're OK
		case nil:
			//log.Debug("HTTP Context", "body", js)
			// great!
		default:
			ErrorString(*c, rw, 400, "Cannot parse JSON request body: "+
				err.Error())
			return
		}

		c.Env["json"] = js
		h.ServeHTTP(rw, r)
	})
}
<|endoftext|>


<commit_before>package model

import (
	"bytes"
	"encoding/gob"

	"google.golang.org/appengine/datastore"
)

//go:generate generator

type Test struct {
	Tester int
	Name   string
	Params map[string]string
}

func (t *Test) Load(ps []datastore.Property) error {
	for _, p := range ps {
		switch p.Name {
		case "Tester":
			t.Tester = p.Value.(int)
		case "Name":
			t.Name = p.Value.(string)
		case "Params":
			if err := gob.NewDecoder(bytes.NewReader(p.Value.([]byte))).Decode(&t.Params); err != nil {
				return err
			}
		}
	}
	return nil
}

func (t *Test) Save() ([]datastore.Property, error) {
	buf := new(bytes.Buffer)

	if err := gob.NewEncoder(buf).Encode(t.Params); err != nil {
		return nil, err
	}

	return []datastore.Property{
		{
			Name:  "Tester",
			Value: int(t.Tester),
		},
		{
			Name:  "Name",
			Value: t.Name,
		},
		{
			Name:  "Params",
			Value: buf.Bytes(),
		},
	}, nil
}
<commit_msg>model: Fix PLS implementation of model.Test<commit_after>package model

import (
	"bytes"
	"encoding/gob"

	"google.golang.org/appengine/datastore"
)

//go:generate generator

type Test struct {
	Tester int
	Name   string
	Params map[string]string
}

func (t *Test) Load(ps []datastore.Property) error {
	for _, p := range ps {
		switch p.Name {
		case "Tester":
			t.Tester = p.Value.(int)
		case "Name":
			t.Name = p.Value.(string)
		case "Params":
			if err := gob.NewDecoder(bytes.NewReader(p.Value.([]byte))).Decode(&t.Params); err != nil {
				return err
			}
		}
	}
	return nil
}

func (t *Test) Save() ([]datastore.Property, error) {
	buf := new(bytes.Buffer)

	if err := gob.NewEncoder(buf).Encode(t.Params); err != nil {
		return nil, err
	}

	return []datastore.Property{
		{
			Name:  "Tester",
			Value: int64(t.Tester),
		},
		{
			Name:  "Name",
			Value: t.Name,
		},
		{
			Name:    "Params",
			Value:   buf.Bytes(),
			NoIndex: true,
		},
	}, nil
}
<|endoftext|>


<commit_before>package model

import (
	"time"
)

type User struct {
	ID              uint      `gorm:"column:user_id;primary_key"`
	Username        string    `gorm:"column:username"`
	Password        string    `gorm:"column:password"`
	Email           string    `gorm:"column:email"`
	Status          int       `gorm:"column:status"`
	CreatedAt       time.Time `gorm:"column:created_at"`
	UpdatedAt       time.Time `gorm:"column:updated_at"`
	Token           string    `gorm:"column:api_token"`
	TokenExpiration time.Time `gorm:"column:api_token_expiry"`
	Language        string    `gorm:"column:language"`

	// TODO: move this to PublicUser
	LikingCount int    `json:"likingCount" gorm:"-"`
	LikedCount  int    `json:"likedCount" gorm:"-"`
	Likings     []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
	Liked       []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`

	MD5      string    `json:"md5"` // Hash of email address, used for Gravatar
	Torrents []Torrent `gorm:"ForeignKey:UploaderID"`
}

// Returns the total size of memory recursively allocated for this struct
func (u User) Size() (s int) {
	s += 4 + // ints
		6*2 + // string pointers
		4*3 + //time.Time
		3*2 + // arrays
		// string arrays
		len(u.Username) + len(u.Password) + len(u.Email) + len(u.Token) + len(u.MD5) + len(u.Language)
	s *= 8

	// Ignoring foreign key users. Fuck them.

	return
}

type PublicUser struct {
	User *User
}

// different users following eachother
type UserFollows struct {
	UserID     uint `gorm:"column:user_id"`
	FollowerID uint `gorm:"column:following"`
}

type UserUploadsOld struct {
	Username  string `gorm:"column:username"`
	TorrentId uint   `gorm:"column:torrent_id"`
}

func (c UserUploadsOld) TableName() string {
	// TODO: rename this in db
	return "user_uploads_old"
}
<commit_msg>add md5 gorm column back<commit_after>package model

import (
	"time"
)

type User struct {
	ID              uint      `gorm:"column:user_id;primary_key"`
	Username        string    `gorm:"column:username"`
	Password        string    `gorm:"column:password"`
	Email           string    `gorm:"column:email"`
	Status          int       `gorm:"column:status"`
	CreatedAt       time.Time `gorm:"column:created_at"`
	UpdatedAt       time.Time `gorm:"column:updated_at"`
	Token           string    `gorm:"column:api_token"`
	TokenExpiration time.Time `gorm:"column:api_token_expiry"`
	Language        string    `gorm:"column:language"`

	// TODO: move this to PublicUser
	LikingCount int    `json:"likingCount" gorm:"-"`
	LikedCount  int    `json:"likedCount" gorm:"-"`
	Likings     []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
	Liked       []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`

	MD5      string    `json:"md5" gorm:"column:md5"` // Hash of email address, used for Gravatar
	Torrents []Torrent `gorm:"ForeignKey:UploaderID"`
}

// Returns the total size of memory recursively allocated for this struct
func (u User) Size() (s int) {
	s += 4 + // ints
		6*2 + // string pointers
		4*3 + //time.Time
		3*2 + // arrays
		// string arrays
		len(u.Username) + len(u.Password) + len(u.Email) + len(u.Token) + len(u.MD5) + len(u.Language)
	s *= 8

	// Ignoring foreign key users. Fuck them.

	return
}

type PublicUser struct {
	User *User
}

// different users following eachother
type UserFollows struct {
	UserID     uint `gorm:"column:user_id"`
	FollowerID uint `gorm:"column:following"`
}

type UserUploadsOld struct {
	Username  string `gorm:"column:username"`
	TorrentId uint   `gorm:"column:torrent_id"`
}

func (c UserUploadsOld) TableName() string {
	// TODO: rename this in db
	return "user_uploads_old"
}
<|endoftext|>


<commit_before>// Copyright 2015 Unknwon
//
// 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 models

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"
	"github.com/mschoch/blackfriday-text"
	"github.com/russross/blackfriday"
	"gopkg.in/ini.v1"

	"github.com/peachdocs/peach/modules/setting"
)

type Node struct {
	Name  string // Name in TOC
	Title string // Name in given language
	text  []byte // Clean text without formatting
	runes []rune

	Plain         bool // Root node without content
	DocumentPath  string
	FileName      string // Full path with .md extension
	Nodes         []*Node
	LastBuildTime int64
}

func (n *Node) SetText(text []byte) {
	n.text = text
	n.runes = []rune(string(n.text))
}

func (n *Node) Text() []byte {
	return n.text
}

var textRender = blackfridaytext.TextRenderer()
var (
	docsRoot = "data/docs"
	HTMLRoot = "data/html"
)

func parseNodeName(name string, data []byte) (string, []byte) {
	data = bytes.TrimSpace(data)
	if len(data) < 3 || string(data[:3]) != "---" {
		return name, []byte("")
	}
	endIdx := bytes.Index(data[3:], []byte("---")) + 3
	if endIdx == -1 {
		return name, []byte("")
	}

	opts := strings.Split(strings.TrimSpace(string(string(data[3:endIdx]))), "\n")

	title := name
	for _, opt := range opts {
		infos := strings.SplitN(opt, ":", 2)
		if len(infos) != 2 {
			continue
		}

		switch strings.TrimSpace(infos[0]) {
		case "name":
			title = strings.TrimSpace(infos[1])
		}
	}

	return title, data[endIdx+3:]
}

func (n *Node) ReloadContent() error {
	data, err := ioutil.ReadFile(n.FileName)
	if err != nil {
		return err
	}

	n.Title, data = parseNodeName(n.Name, data)
	n.Plain = len(bytes.TrimSpace(data)) == 0

	if !n.Plain {
		n.SetText(bytes.ToLower(blackfriday.Markdown(data, textRender, 0)))
		data = markdown(data)
	}

	return n.GenHTML(data)
}

// HTML2JS converts []byte type of HTML content into JS format.
func HTML2JS(data []byte) []byte {
	s := string(data)
	s = strings.Replace(s, `\`, `\\`, -1)
	s = strings.Replace(s, "\n", `\n`, -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\"", `\"`, -1)
	return []byte(s)
}

func (n *Node) GenHTML(data []byte) error {
	var htmlPath string
	if setting.Docs.Type.IsLocal() {
		htmlPath = path.Join(HTMLRoot, strings.TrimPrefix(n.FileName, setting.Docs.Target))
	} else {
		htmlPath = path.Join(HTMLRoot, strings.TrimPrefix(n.FileName, docsRoot))
	}
	htmlPath = strings.Replace(htmlPath, ".md", ".js", 1)

	buf := new(bytes.Buffer)
	buf.WriteString("document.write(\"")
	buf.Write(HTML2JS(data))
	buf.WriteString("\")")

	n.LastBuildTime = time.Now().Unix()
	if err := com.WriteFile(htmlPath+".tmp", buf.Bytes()); err != nil {
		return err
	}
	os.Remove(htmlPath)
	return os.Rename(htmlPath+".tmp", htmlPath)
}

// Toc represents table of content in a specific language.
type Toc struct {
	RootPath string
	Lang     string
	Nodes    []*Node
	Pages    []*Node
}

// GetDoc should only be called by top level toc.
func (t *Toc) GetDoc(name string) (*Node, bool) {
	name = strings.TrimPrefix(name, "/")

	// Returns first node whatever avaiable as default.
	if len(name) == 0 {
		if len(t.Nodes) == 0 ||
			t.Nodes[0].Plain {
			return nil, false
		}
		return t.Nodes[0], false
	}

	infos := strings.Split(name, "/")

	// Dir node.
	if len(infos) == 1 {
		for i := range t.Nodes {
			if t.Nodes[i].Name == infos[0] {
				return t.Nodes[i], false
			}
		}
		return nil, false
	}

	// File node.
	for i := range t.Nodes {
		if t.Nodes[i].Name == infos[0] {
			for j := range t.Nodes[i].Nodes {
				if t.Nodes[i].Nodes[j].Name == infos[1] {
					if com.IsFile(t.Nodes[i].Nodes[j].FileName) {
						return t.Nodes[i].Nodes[j], false
					}

					// If not default language, try again.
					n, _ := Tocs[setting.Docs.Langs[0]].GetDoc(name)
					return n, true
				}
			}
		}
	}

	return nil, false
}

type SearchResult struct {
	Title string
	Path  string
	Match string
}

func (n *Node) adjustRange(start int) (int, int) {
	start -= 20
	if start < 0 {
		start = 0
	}

	length := len(n.runes)
	end := start + 230
	if end > length {
		end = length
	}
	return start, end
}

func (t *Toc) Search(q string) []*SearchResult {
	if len(q) == 0 {
		return nil
	}
	q = strings.ToLower(q)

	results := make([]*SearchResult, 0, 5)

	// Dir node.
	for i := range t.Nodes {
		if idx := bytes.Index(t.Nodes[i].Text(), []byte(q)); idx > -1 {
			start, end := t.Nodes[i].adjustRange(utf8.RuneCount(t.Nodes[i].Text()[:idx]))
			results = append(results, &SearchResult{
				Title: t.Nodes[i].Title,
				Path:  t.Nodes[i].Name,
				Match: string(t.Nodes[i].runes[start:end]),
			})
		}
	}

	// File node.
	for i := range t.Nodes {
		for j := range t.Nodes[i].Nodes {
			if idx := bytes.Index(t.Nodes[i].Nodes[j].Text(), []byte(q)); idx > -1 {
				start, end := t.Nodes[i].Nodes[j].adjustRange(utf8.RuneCount(t.Nodes[i].Nodes[j].Text()[:idx]))
				results = append(results, &SearchResult{
					Title: t.Nodes[i].Nodes[j].Title,
					Path:  path.Join(t.Nodes[i].Name, t.Nodes[i].Nodes[j].Name),
					Match: string(t.Nodes[i].Nodes[j].runes[start:end]),
				})
			}
		}
	}

	return results
}

var (
	tocLocker = sync.RWMutex{}
	Tocs      map[string]*Toc
)

func initToc(localRoot string) (map[string]*Toc, error) {
	tocPath := path.Join(localRoot, "TOC.ini")
	if !com.IsFile(tocPath) {
		return nil, fmt.Errorf("TOC not found: %s", tocPath)
	}

	// Generate Toc.
	tocCfg, err := ini.Load(tocPath)
	if err != nil {
		return nil, fmt.Errorf("Fail to load TOC.ini: %v", err)
	}

	tocs := make(map[string]*Toc)
	for _, lang := range setting.Docs.Langs {
		toc := &Toc{
			RootPath: localRoot,
			Lang:     lang,
		}
		dirs := tocCfg.Section("").KeyStrings()
		toc.Nodes = make([]*Node, 0, len(dirs))
		for _, dir := range dirs {
			dirName := tocCfg.Section("").Key(dir).String()
			fmt.Println(dirName + "/")
			files := tocCfg.Section(dirName).KeyStrings()

			// Skip empty directory.
			if len(files) == 0 {
				continue
			}

			documentPath := path.Join(dirName, tocCfg.Section(dirName).Key(files[0]).String())
			dirNode := &Node{
				Name:         dirName,
				DocumentPath: documentPath,
				FileName:     path.Join(localRoot, lang, documentPath) + ".md",
				Nodes:        make([]*Node, 0, len(files)-1),
			}
			toc.Nodes = append(toc.Nodes, dirNode)

			for _, file := range files[1:] {
				fileName := tocCfg.Section(dirName).Key(file).String()
				fmt.Println(strings.Repeat(" ", len(dirName))+"|__", fileName)

				documentPath = path.Join(dirName, fileName)
				node := &Node{
					Name:         fileName,
					DocumentPath: documentPath,
					FileName:     path.Join(localRoot, lang, documentPath) + ".md",
				}
				dirNode.Nodes = append(dirNode.Nodes, node)
			}
		}

		// Single pages.
		pages := tocCfg.Section("pages").KeyStrings()
		toc.Pages = make([]*Node, 0, len(pages))
		for _, page := range pages {
			pageName := tocCfg.Section("pages").Key(page).String()
			fmt.Println(pageName)

			toc.Pages = append(toc.Pages, &Node{
				Name:         pageName,
				DocumentPath: pageName,
				FileName:     path.Join(localRoot, lang, pageName) + ".md",
			})
		}

		tocs[lang] = toc
	}
	return tocs, nil
}

func ReloadDocs() error {
	tocLocker.Lock()
	defer tocLocker.Unlock()

	localRoot := setting.Docs.Target

	// Fetch docs from remote.
	if setting.Docs.Type.IsRemote() {
		localRoot = docsRoot

		absRoot, err := filepath.Abs(localRoot)
		if err != nil {
			return fmt.Errorf("filepath.Abs: %v", err)
		}

		// Clone new or pull to update.
		if com.IsDir(absRoot) {
			stdout, stderr, err := com.ExecCmdDir(absRoot, "git", "pull")
			if err != nil {
				return fmt.Errorf("Fail to update docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr)
			}
			fmt.Println(stdout)
		} else {
			os.MkdirAll(path.Dir(absRoot), os.ModePerm)
			stdout, stderr, err := com.ExecCmd("git", "clone", setting.Docs.Target, absRoot)
			if err != nil {
				return fmt.Errorf("Fail to clone docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr)
			}
			fmt.Println(stdout)
		}
	}

	if !com.IsDir(localRoot) {
		return fmt.Errorf("Documentation not found: %s - %s", setting.Docs.Type, localRoot)
	}

	tocs, err := initToc(localRoot)
	if err != nil {
		return fmt.Errorf("initToc: %v", err)
	}
	initDocs(tocs, localRoot)
	Tocs = tocs
	return nil
}

func NewContext() {
	if com.IsExist(HTMLRoot) {
		if err := os.RemoveAll(HTMLRoot); err != nil {
			log.Fatal("Fail to clean up HTMLRoot: %v", err)
		}
	}

	if err := ReloadDocs(); err != nil {
		log.Fatal("Fail to init docs: %v", err)
	}
}
<commit_msg>fix mkdir all<commit_after>// Copyright 2015 Unknwon
//
// 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 models

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"
	"github.com/mschoch/blackfriday-text"
	"github.com/russross/blackfriday"
	"gopkg.in/ini.v1"

	"github.com/peachdocs/peach/modules/setting"
)

type Node struct {
	Name  string // Name in TOC
	Title string // Name in given language
	text  []byte // Clean text without formatting
	runes []rune

	Plain         bool // Root node without content
	DocumentPath  string
	FileName      string // Full path with .md extension
	Nodes         []*Node
	LastBuildTime int64
}

func (n *Node) SetText(text []byte) {
	n.text = text
	n.runes = []rune(string(n.text))
}

func (n *Node) Text() []byte {
	return n.text
}

var textRender = blackfridaytext.TextRenderer()
var (
	docsRoot = "data/docs"
	HTMLRoot = "data/html"
)

func parseNodeName(name string, data []byte) (string, []byte) {
	data = bytes.TrimSpace(data)
	if len(data) < 3 || string(data[:3]) != "---" {
		return name, []byte("")
	}
	endIdx := bytes.Index(data[3:], []byte("---")) + 3
	if endIdx == -1 {
		return name, []byte("")
	}

	opts := strings.Split(strings.TrimSpace(string(string(data[3:endIdx]))), "\n")

	title := name
	for _, opt := range opts {
		infos := strings.SplitN(opt, ":", 2)
		if len(infos) != 2 {
			continue
		}

		switch strings.TrimSpace(infos[0]) {
		case "name":
			title = strings.TrimSpace(infos[1])
		}
	}

	return title, data[endIdx+3:]
}

func (n *Node) ReloadContent() error {
	data, err := ioutil.ReadFile(n.FileName)
	if err != nil {
		return err
	}

	n.Title, data = parseNodeName(n.Name, data)
	n.Plain = len(bytes.TrimSpace(data)) == 0

	if !n.Plain {
		n.SetText(bytes.ToLower(blackfriday.Markdown(data, textRender, 0)))
		data = markdown(data)
	}

	return n.GenHTML(data)
}

// HTML2JS converts []byte type of HTML content into JS format.
func HTML2JS(data []byte) []byte {
	s := string(data)
	s = strings.Replace(s, `\`, `\\`, -1)
	s = strings.Replace(s, "\n", `\n`, -1)
	s = strings.Replace(s, "\r", "", -1)
	s = strings.Replace(s, "\"", `\"`, -1)
	return []byte(s)
}

func (n *Node) GenHTML(data []byte) error {
	var htmlPath string
	if setting.Docs.Type.IsLocal() {
		htmlPath = path.Join(HTMLRoot, strings.TrimPrefix(n.FileName, setting.Docs.Target))
	} else {
		htmlPath = path.Join(HTMLRoot, strings.TrimPrefix(n.FileName, docsRoot))
	}
	htmlPath = strings.Replace(htmlPath, ".md", ".js", 1)

	buf := new(bytes.Buffer)
	buf.WriteString("document.write(\"")
	buf.Write(HTML2JS(data))
	buf.WriteString("\")")

	n.LastBuildTime = time.Now().Unix()
	if err := com.WriteFile(htmlPath+".tmp", buf.Bytes()); err != nil {
		return err
	}
	os.Remove(htmlPath)
	return os.Rename(htmlPath+".tmp", htmlPath)
}

// Toc represents table of content in a specific language.
type Toc struct {
	RootPath string
	Lang     string
	Nodes    []*Node
	Pages    []*Node
}

// GetDoc should only be called by top level toc.
func (t *Toc) GetDoc(name string) (*Node, bool) {
	name = strings.TrimPrefix(name, "/")

	// Returns first node whatever avaiable as default.
	if len(name) == 0 {
		if len(t.Nodes) == 0 ||
			t.Nodes[0].Plain {
			return nil, false
		}
		return t.Nodes[0], false
	}

	infos := strings.Split(name, "/")

	// Dir node.
	if len(infos) == 1 {
		for i := range t.Nodes {
			if t.Nodes[i].Name == infos[0] {
				return t.Nodes[i], false
			}
		}
		return nil, false
	}

	// File node.
	for i := range t.Nodes {
		if t.Nodes[i].Name == infos[0] {
			for j := range t.Nodes[i].Nodes {
				if t.Nodes[i].Nodes[j].Name == infos[1] {
					if com.IsFile(t.Nodes[i].Nodes[j].FileName) {
						return t.Nodes[i].Nodes[j], false
					}

					// If not default language, try again.
					n, _ := Tocs[setting.Docs.Langs[0]].GetDoc(name)
					return n, true
				}
			}
		}
	}

	return nil, false
}

type SearchResult struct {
	Title string
	Path  string
	Match string
}

func (n *Node) adjustRange(start int) (int, int) {
	start -= 20
	if start < 0 {
		start = 0
	}

	length := len(n.runes)
	end := start + 230
	if end > length {
		end = length
	}
	return start, end
}

func (t *Toc) Search(q string) []*SearchResult {
	if len(q) == 0 {
		return nil
	}
	q = strings.ToLower(q)

	results := make([]*SearchResult, 0, 5)

	// Dir node.
	for i := range t.Nodes {
		if idx := bytes.Index(t.Nodes[i].Text(), []byte(q)); idx > -1 {
			start, end := t.Nodes[i].adjustRange(utf8.RuneCount(t.Nodes[i].Text()[:idx]))
			results = append(results, &SearchResult{
				Title: t.Nodes[i].Title,
				Path:  t.Nodes[i].Name,
				Match: string(t.Nodes[i].runes[start:end]),
			})
		}
	}

	// File node.
	for i := range t.Nodes {
		for j := range t.Nodes[i].Nodes {
			if idx := bytes.Index(t.Nodes[i].Nodes[j].Text(), []byte(q)); idx > -1 {
				start, end := t.Nodes[i].Nodes[j].adjustRange(utf8.RuneCount(t.Nodes[i].Nodes[j].Text()[:idx]))
				results = append(results, &SearchResult{
					Title: t.Nodes[i].Nodes[j].Title,
					Path:  path.Join(t.Nodes[i].Name, t.Nodes[i].Nodes[j].Name),
					Match: string(t.Nodes[i].Nodes[j].runes[start:end]),
				})
			}
		}
	}

	return results
}

var (
	tocLocker = sync.RWMutex{}
	Tocs      map[string]*Toc
)

func initToc(localRoot string) (map[string]*Toc, error) {
	tocPath := path.Join(localRoot, "TOC.ini")
	if !com.IsFile(tocPath) {
		return nil, fmt.Errorf("TOC not found: %s", tocPath)
	}

	// Generate Toc.
	tocCfg, err := ini.Load(tocPath)
	if err != nil {
		return nil, fmt.Errorf("Fail to load TOC.ini: %v", err)
	}

	tocs := make(map[string]*Toc)
	for _, lang := range setting.Docs.Langs {
		toc := &Toc{
			RootPath: localRoot,
			Lang:     lang,
		}
		dirs := tocCfg.Section("").KeyStrings()
		toc.Nodes = make([]*Node, 0, len(dirs))
		for _, dir := range dirs {
			dirName := tocCfg.Section("").Key(dir).String()
			fmt.Println(dirName + "/")
			files := tocCfg.Section(dirName).KeyStrings()

			// Skip empty directory.
			if len(files) == 0 {
				continue
			}

			documentPath := path.Join(dirName, tocCfg.Section(dirName).Key(files[0]).String())
			dirNode := &Node{
				Name:         dirName,
				DocumentPath: documentPath,
				FileName:     path.Join(localRoot, lang, documentPath) + ".md",
				Nodes:        make([]*Node, 0, len(files)-1),
			}
			toc.Nodes = append(toc.Nodes, dirNode)

			for _, file := range files[1:] {
				fileName := tocCfg.Section(dirName).Key(file).String()
				fmt.Println(strings.Repeat(" ", len(dirName))+"|__", fileName)

				documentPath = path.Join(dirName, fileName)
				node := &Node{
					Name:         fileName,
					DocumentPath: documentPath,
					FileName:     path.Join(localRoot, lang, documentPath) + ".md",
				}
				dirNode.Nodes = append(dirNode.Nodes, node)
			}
		}

		// Single pages.
		pages := tocCfg.Section("pages").KeyStrings()
		toc.Pages = make([]*Node, 0, len(pages))
		for _, page := range pages {
			pageName := tocCfg.Section("pages").Key(page).String()
			fmt.Println(pageName)

			toc.Pages = append(toc.Pages, &Node{
				Name:         pageName,
				DocumentPath: pageName,
				FileName:     path.Join(localRoot, lang, pageName) + ".md",
			})
		}

		tocs[lang] = toc
	}
	return tocs, nil
}

func ReloadDocs() error {
	tocLocker.Lock()
	defer tocLocker.Unlock()

	localRoot := setting.Docs.Target

	// Fetch docs from remote.
	if setting.Docs.Type.IsRemote() {
		localRoot = docsRoot

		absRoot, err := filepath.Abs(localRoot)
		if err != nil {
			return fmt.Errorf("filepath.Abs: %v", err)
		}

		// Clone new or pull to update.
		if com.IsDir(absRoot) {
			stdout, stderr, err := com.ExecCmdDir(absRoot, "git", "pull")
			if err != nil {
				return fmt.Errorf("Fail to update docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr)
			}
			fmt.Println(stdout)
		} else {
			os.MkdirAll(filepath.Dir(absRoot), os.ModePerm)
			stdout, stderr, err := com.ExecCmd("git", "clone", setting.Docs.Target, absRoot)
			if err != nil {
				return fmt.Errorf("Fail to clone docs from remote source(%s): %v - %s", setting.Docs.Target, err, stderr)
			}
			fmt.Println(stdout)
		}
	}

	if !com.IsDir(localRoot) {
		return fmt.Errorf("Documentation not found: %s - %s", setting.Docs.Type, localRoot)
	}

	tocs, err := initToc(localRoot)
	if err != nil {
		return fmt.Errorf("initToc: %v", err)
	}
	initDocs(tocs, localRoot)
	Tocs = tocs
	return nil
}

func NewContext() {
	if com.IsExist(HTMLRoot) {
		if err := os.RemoveAll(HTMLRoot); err != nil {
			log.Fatal("Fail to clean up HTMLRoot: %v", err)
		}
	}

	if err := ReloadDocs(); err != nil {
		log.Fatal("Fail to init docs: %v", err)
	}
}
<|endoftext|>


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

package mongostore

import (
	"errors"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"net/http"
	"time"
)

var (
	ErrInvalidId = errors.New("mgostore: invalid session id")
)

// Session object store in MongoDB
type Session struct {
	Id       bson.ObjectId `bson:"_id,omitempty"`
	Data     string
	Modified time.Time
}

// MongoStore stores sessions in MongoDB
type MongoStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options
	Token   TokenGetSeter
	coll    *mgo.Collection
}

// NewMongoStore returns a new MongoStore.
// Set ensureTTL to true let the database auto-remove expired object by maxAge.
func NewMongoStore(c *mgo.Collection, maxAge int, ensureTTL bool,
	keyPairs ...[]byte) *MongoStore {
	store := &MongoStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			MaxAge: maxAge,
		},
		Token: &CookieToken{},
		coll:  c,
	}

	if ensureTTL {
		c.EnsureIndex(mgo.Index{
			Key:         []string{"modified"},
			Background:  true,
			Sparse:      true,
			ExpireAfter: time.Duration(maxAge) * time.Second,
		})
	}

	return store
}

// Get registers and returns a session for the given name and session store.
// It returns a new session if there are no sessions registered for the name.
func (m *MongoStore) Get(r *http.Request, name string) (
	*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(m, name)
}

// New returns a session for the given name without adding it to the registry.
func (m *MongoStore) New(r *http.Request, name string) (
	*sessions.Session, error) {
	session := sessions.NewSession(m, name)
	session.Options = &sessions.Options{
		Path:   m.Options.Path,
		MaxAge: m.Options.MaxAge,
	}
	session.IsNew = true
	var err error
	if cook, errToken := m.Token.GetToken(r, name); errToken == nil {
		err = securecookie.DecodeMulti(name, cook, &session.ID, m.Codecs...)
		if err == nil {
			err = m.load(session)
			if err == nil {
				session.IsNew = false
			} else {
				err = nil
			}
		}
	}
	return session, err
}

// Save saves all sessions registered for the current request.
func (m *MongoStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.Options.MaxAge < 0 {
		if err := m.delete(session); err != nil {
			return err
		}
		m.Token.SetToken(w, session.Name(), "", session.Options)
		return nil
	}

	if session.ID == "" {
		session.ID = bson.NewObjectId().Hex()
	}

	if err := m.upsert(session); err != nil {
		return err
	}

	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		m.Codecs...)
	if err != nil {
		return err
	}

	m.Token.SetToken(w, session.Name(), encoded, session.Options)
	return nil
}

func (m *MongoStore) load(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	s := Session{}
	err := m.coll.FindId(bson.ObjectIdHex(session.ID)).One(&s)
	if err != nil {
		return err
	}

	if err := securecookie.DecodeMulti(session.Name(), s.Data, &session.Values,
		m.Codecs...); err != nil {
		return err
	}

	return nil
}

func (m *MongoStore) upsert(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	var modified time.Time
	if val, ok := session.Values["modified"]; ok {
		modified, ok = val.(time.Time)
		if !ok {
			return errors.New("mongostore: invalid modified value")
		}
	} else {
		modified = time.Now()
	}

	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		m.Codecs...)
	if err != nil {
		return err
	}

	s := Session{
		Id:       bson.ObjectIdHex(session.ID),
		Data:     encoded,
		Modified: modified,
	}

	_, err = m.coll.UpsertId(s.Id, &s)
	if err != nil {
		return err
	}

	return nil
}

func (m *MongoStore) delete(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	return m.coll.RemoveId(bson.ObjectIdHex(session.ID))
}
<commit_msg>Add default Path to fix #3<commit_after>// Copyright 2012 The KidStuff Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mongostore

import (
	"errors"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"net/http"
	"time"
)

var (
	ErrInvalidId = errors.New("mgostore: invalid session id")
)

// Session object store in MongoDB
type Session struct {
	Id       bson.ObjectId `bson:"_id,omitempty"`
	Data     string
	Modified time.Time
}

// MongoStore stores sessions in MongoDB
type MongoStore struct {
	Codecs  []securecookie.Codec
	Options *sessions.Options
	Token   TokenGetSeter
	coll    *mgo.Collection
}

// NewMongoStore returns a new MongoStore.
// Set ensureTTL to true let the database auto-remove expired object by maxAge.
func NewMongoStore(c *mgo.Collection, maxAge int, ensureTTL bool,
	keyPairs ...[]byte) *MongoStore {
	store := &MongoStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path: "/",
			MaxAge: maxAge,
		},
		Token: &CookieToken{},
		coll:  c,
	}

	if ensureTTL {
		c.EnsureIndex(mgo.Index{
			Key:         []string{"modified"},
			Background:  true,
			Sparse:      true,
			ExpireAfter: time.Duration(maxAge) * time.Second,
		})
	}

	return store
}

// Get registers and returns a session for the given name and session store.
// It returns a new session if there are no sessions registered for the name.
func (m *MongoStore) Get(r *http.Request, name string) (
	*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(m, name)
}

// New returns a session for the given name without adding it to the registry.
func (m *MongoStore) New(r *http.Request, name string) (
	*sessions.Session, error) {
	session := sessions.NewSession(m, name)
	session.Options = &sessions.Options{
		Path:   m.Options.Path,
		MaxAge: m.Options.MaxAge,
	}
	session.IsNew = true
	var err error
	if cook, errToken := m.Token.GetToken(r, name); errToken == nil {
		err = securecookie.DecodeMulti(name, cook, &session.ID, m.Codecs...)
		if err == nil {
			err = m.load(session)
			if err == nil {
				session.IsNew = false
			} else {
				err = nil
			}
		}
	}
	return session, err
}

// Save saves all sessions registered for the current request.
func (m *MongoStore) Save(r *http.Request, w http.ResponseWriter,
	session *sessions.Session) error {
	if session.Options.MaxAge < 0 {
		if err := m.delete(session); err != nil {
			return err
		}
		m.Token.SetToken(w, session.Name(), "", session.Options)
		return nil
	}

	if session.ID == "" {
		session.ID = bson.NewObjectId().Hex()
	}

	if err := m.upsert(session); err != nil {
		return err
	}

	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		m.Codecs...)
	if err != nil {
		return err
	}

	m.Token.SetToken(w, session.Name(), encoded, session.Options)
	return nil
}

func (m *MongoStore) load(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	s := Session{}
	err := m.coll.FindId(bson.ObjectIdHex(session.ID)).One(&s)
	if err != nil {
		return err
	}

	if err := securecookie.DecodeMulti(session.Name(), s.Data, &session.Values,
		m.Codecs...); err != nil {
		return err
	}

	return nil
}

func (m *MongoStore) upsert(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	var modified time.Time
	if val, ok := session.Values["modified"]; ok {
		modified, ok = val.(time.Time)
		if !ok {
			return errors.New("mongostore: invalid modified value")
		}
	} else {
		modified = time.Now()
	}

	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		m.Codecs...)
	if err != nil {
		return err
	}

	s := Session{
		Id:       bson.ObjectIdHex(session.ID),
		Data:     encoded,
		Modified: modified,
	}

	_, err = m.coll.UpsertId(s.Id, &s)
	if err != nil {
		return err
	}

	return nil
}

func (m *MongoStore) delete(session *sessions.Session) error {
	if !bson.IsObjectIdHex(session.ID) {
		return ErrInvalidId
	}

	return m.coll.RemoveId(bson.ObjectIdHex(session.ID))
}
<|endoftext|>


<commit_before>// Copyright © 2009 Fazlul Shahriar <fshahriar@gmail.com>.
// See LICENSE file for license details.

// This package provides the client side interface to MPD (Music Player Daemon).
// The protocol reference can be found at http://www.musicpd.org/doc/protocol/index.html
package mpd

import (
	"net/textproto"
	"os"
	"strconv"
	"strings"
)

type Client struct {
	text *textproto.Conn
}

type Attrs map[string]string

// Dial connects to MPD listening on address addr (e.g. "127.0.0.1:6600")
// on network network (e.g. "tcp").
func Dial(network, addr string) (c *Client, err os.Error) {
	text, err := textproto.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	line, err := text.ReadLine()
	if err != nil {
		return nil, err
	}
	if line[0:6] != "OK MPD" {
		return nil, textproto.ProtocolError("no greeting")
	}
	return &Client{text: text}, nil
}

// Close terminates the connection with MPD.
func (c *Client) Close() (err os.Error) {
	if c.text != nil {
		c.text.PrintfLine("close")
		err = c.text.Close()
		c.text = nil
	}
	return
}

func (c *Client) readPlaylist() (pls []Attrs, err os.Error) {
	pls = make([]Attrs, 100)

	n := 0
	for {
		line, err := c.text.ReadLine()
		if err != nil {
			return nil, err
		}
		if line == "OK" {
			break
		}
		if strings.HasPrefix(line, "file:") { // new song entry begins
			n++
			if n > len(pls) || n > cap(pls) {
				pls1 := make([]Attrs, 2*cap(pls))
				for k, a := range pls {
					pls1[k] = a
				}
				pls = pls1
			}
			pls[n-1] = make(Attrs)
		}
		if n == 0 {
			return nil, textproto.ProtocolError("unexpected: " + line)
		}
		z := strings.Index(line, ": ")
		if z < 0 {
			return nil, textproto.ProtocolError("can't parse line: " + line)
		}
		key := line[0:z]
		pls[n-1][key] = line[z+2:]
	}
	return pls[0:n], nil
}

func (c *Client) readAttrs() (attrs Attrs, err os.Error) {
	attrs = make(Attrs)
	for {
		line, err := c.text.ReadLine()
		if err != nil {
			return nil, err
		}
		if line == "OK" {
			break
		}
		z := strings.Index(line, ": ")
		if z < 0 {
			return nil, textproto.ProtocolError("can't parse line: " + line)
		}
		key := line[0:z]
		attrs[key] = line[z+2:]
	}
	return
}

// CurrentSong returns information about the current song in the playlist.
func (c *Client) CurrentSong() (Attrs, os.Error) {
	id, err := c.text.Cmd("currentsong")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readAttrs()
}

// Status returns information about the current status of MPD.
func (c *Client) Status() (Attrs, os.Error) {
	id, err := c.text.Cmd("status")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readAttrs()
}

func (c *Client) readOKLine() (err os.Error) {
	line, err := c.text.ReadLine()
	if err != nil {
		return
	}
	if line == "OK" {
		return nil
	}
	return textproto.ProtocolError("unexpected response: " + line)
}

func (c *Client) okCmd(format string, args ...interface{}) os.Error {
	id, err := c.text.Cmd(format, args...)
	if err != nil {
		return err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readOKLine()
}

//
// Playback control
//

// Next plays next song in the playlist.
func (c *Client) Next() os.Error {
	return c.okCmd("next")
}

// Pause pauses playback if pause is true; resumes playback otherwise.
func (c *Client) Pause(pause bool) os.Error {
	if pause {
		return c.okCmd("pause 1")
	}
	return c.okCmd("pause 0")
}

// Play starts playing the song at playlist position pos. If pos is negative,
// start playing at the current position in the playlist.
func (c *Client) Play(pos int) os.Error {
	if pos < 0 {
		c.okCmd("play")
	}
	return c.okCmd("play %d", pos)
}

// PlayId plays the song identified by id. If id is negative, start playing
// at the currect position in playlist.
func (c *Client) PlayId(id int) os.Error {
	if id < 0 {
		return c.okCmd("playid")
	}
	return c.okCmd("playid %d", id)
}

// Previous plays previous song in the playlist.
func (c *Client) Previous() os.Error {
	return c.okCmd("next")
}

// Seek seeks to the position time (in seconds) of the song at playlist position pos.
func (c *Client) Seek(pos, time int) os.Error {
	return c.okCmd("seek %d %d", pos, time)
}

// SeekId is identical to Seek except the song is identified by it's id
// (not position in playlist).
func (c *Client) SeekId(id, time int) os.Error {
	return c.okCmd("seekid %d %d", id, time)
}

// Stop stops playback.
func (c *Client) Stop() os.Error {
	return c.okCmd("stop")
}

//
// Playlist related functions
//

// PlaylistInfo returns attributes for songs in the current playlist. If
// both start and end are negative, it does this for all songs in
// playlist. If end is negative but start is positive, it does it for the
// song at position start. If both start and end are positive, it does it
// for positions in range [start, end).
func (c *Client) PlaylistInfo(start, end int) (pls []Attrs, err os.Error) {
	if start < 0 && end >= 0 {
		return nil, os.NewError("negative start index")
	}
	if start >= 0 && end < 0 {
		id, err := c.text.Cmd("playlistinfo %d", start)
		if err != nil {
			return nil, err
		}
		c.text.StartResponse(id)
		defer c.text.EndResponse(id)
		return c.readPlaylist()
	}
	id, err := c.text.Cmd("playlistinfo")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	pls, err = c.readPlaylist()
	if err != nil || start < 0 || end < 0 {
		return
	}
	return pls[start:end], nil
}

// Delete deletes songs from playlist. If both start and end are positive,
// it deletes those at positions in range [start, end). If end is negative,
// it deletes the song at position start.
func (c *Client) Delete(start, end int) os.Error {
	if start < 0 {
		return os.NewError("negative start index")
	}
	if end < 0 {
		return c.okCmd("delete %d", start)
	}
	return c.okCmd("delete %d %d", start, end)
}

// DeleteId deletes the song identified by id.
func (c *Client) DeleteId(id int) os.Error {
	return c.okCmd("deleteid %d", id)
}

// Add adds the file/directory uri to playlist. Directories add recursively.
func (c *Client) Add(uri string) os.Error {
	return c.okCmd("add %q", uri)
}

// AddId adds the file/directory uri to playlist and returns the identity
// id of the song added. If pos is positive, the song is added to position
// pos.
func (c *Client) AddId(uri string, pos int) (int, os.Error) {
	var id uint
	var err os.Error
	if pos >= 0 {
		id, err = c.text.Cmd("addid %q %d", uri, pos)
	}
	id, err = c.text.Cmd("addid %q", uri)
	if err != nil {
		return -1, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	attrs, err := c.readAttrs()
	if err != nil {
		return -1, err
	}
	tok, ok := attrs["Id"]
	if !ok {
		return -1, textproto.ProtocolError("addid did not return Id")
	}
	return strconv.Atoi(tok)
}

// Clear clears the current playlist.
func (c *Client) Clear() os.Error {
	return c.okCmd("clear")
}
<commit_msg>use append<commit_after>// Copyright © 2009 Fazlul Shahriar <fshahriar@gmail.com>.
// See LICENSE file for license details.

// This package provides the client side interface to MPD (Music Player Daemon).
// The protocol reference can be found at http://www.musicpd.org/doc/protocol/index.html
package mpd

import (
	"net/textproto"
	"os"
	"strconv"
	"strings"
)

type Client struct {
	text *textproto.Conn
}

type Attrs map[string]string

// Dial connects to MPD listening on address addr (e.g. "127.0.0.1:6600")
// on network network (e.g. "tcp").
func Dial(network, addr string) (c *Client, err os.Error) {
	text, err := textproto.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	line, err := text.ReadLine()
	if err != nil {
		return nil, err
	}
	if line[0:6] != "OK MPD" {
		return nil, textproto.ProtocolError("no greeting")
	}
	return &Client{text: text}, nil
}

// Close terminates the connection with MPD.
func (c *Client) Close() (err os.Error) {
	if c.text != nil {
		c.text.PrintfLine("close")
		err = c.text.Close()
		c.text = nil
	}
	return
}

func (c *Client) readPlaylist() (pls []Attrs, err os.Error) {
	pls = []Attrs{}

	for {
		line, err := c.text.ReadLine()
		if err != nil {
			return nil, err
		}
		if line == "OK" {
			break
		}
		if strings.HasPrefix(line, "file:") { // new song entry begins
			pls = append(pls, Attrs{})
		}
		if len(pls) == 0 {
			return nil, textproto.ProtocolError("unexpected: " + line)
		}
		z := strings.Index(line, ": ")
		if z < 0 {
			return nil, textproto.ProtocolError("can't parse line: " + line)
		}
		key := line[0:z]
		pls[len(pls)-1][key] = line[z+2:]
	}
	return pls, nil
}

func (c *Client) readAttrs() (attrs Attrs, err os.Error) {
	attrs = make(Attrs)
	for {
		line, err := c.text.ReadLine()
		if err != nil {
			return nil, err
		}
		if line == "OK" {
			break
		}
		z := strings.Index(line, ": ")
		if z < 0 {
			return nil, textproto.ProtocolError("can't parse line: " + line)
		}
		key := line[0:z]
		attrs[key] = line[z+2:]
	}
	return
}

// CurrentSong returns information about the current song in the playlist.
func (c *Client) CurrentSong() (Attrs, os.Error) {
	id, err := c.text.Cmd("currentsong")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readAttrs()
}

// Status returns information about the current status of MPD.
func (c *Client) Status() (Attrs, os.Error) {
	id, err := c.text.Cmd("status")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readAttrs()
}

func (c *Client) readOKLine() (err os.Error) {
	line, err := c.text.ReadLine()
	if err != nil {
		return
	}
	if line == "OK" {
		return nil
	}
	return textproto.ProtocolError("unexpected response: " + line)
}

func (c *Client) okCmd(format string, args ...interface{}) os.Error {
	id, err := c.text.Cmd(format, args...)
	if err != nil {
		return err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	return c.readOKLine()
}

//
// Playback control
//

// Next plays next song in the playlist.
func (c *Client) Next() os.Error {
	return c.okCmd("next")
}

// Pause pauses playback if pause is true; resumes playback otherwise.
func (c *Client) Pause(pause bool) os.Error {
	if pause {
		return c.okCmd("pause 1")
	}
	return c.okCmd("pause 0")
}

// Play starts playing the song at playlist position pos. If pos is negative,
// start playing at the current position in the playlist.
func (c *Client) Play(pos int) os.Error {
	if pos < 0 {
		c.okCmd("play")
	}
	return c.okCmd("play %d", pos)
}

// PlayId plays the song identified by id. If id is negative, start playing
// at the currect position in playlist.
func (c *Client) PlayId(id int) os.Error {
	if id < 0 {
		return c.okCmd("playid")
	}
	return c.okCmd("playid %d", id)
}

// Previous plays previous song in the playlist.
func (c *Client) Previous() os.Error {
	return c.okCmd("next")
}

// Seek seeks to the position time (in seconds) of the song at playlist position pos.
func (c *Client) Seek(pos, time int) os.Error {
	return c.okCmd("seek %d %d", pos, time)
}

// SeekId is identical to Seek except the song is identified by it's id
// (not position in playlist).
func (c *Client) SeekId(id, time int) os.Error {
	return c.okCmd("seekid %d %d", id, time)
}

// Stop stops playback.
func (c *Client) Stop() os.Error {
	return c.okCmd("stop")
}

//
// Playlist related functions
//

// PlaylistInfo returns attributes for songs in the current playlist. If
// both start and end are negative, it does this for all songs in
// playlist. If end is negative but start is positive, it does it for the
// song at position start. If both start and end are positive, it does it
// for positions in range [start, end).
func (c *Client) PlaylistInfo(start, end int) (pls []Attrs, err os.Error) {
	if start < 0 && end >= 0 {
		return nil, os.NewError("negative start index")
	}
	if start >= 0 && end < 0 {
		id, err := c.text.Cmd("playlistinfo %d", start)
		if err != nil {
			return nil, err
		}
		c.text.StartResponse(id)
		defer c.text.EndResponse(id)
		return c.readPlaylist()
	}
	id, err := c.text.Cmd("playlistinfo")
	if err != nil {
		return nil, err
	}
	c.text.StartResponse(id)
	defer c.text.EndResponse(id)
	pls, err = c.readPlaylist()
	if err != nil || start < 0 || end < 0 {
		return
	}
	return pls[start:end], nil
}

// Delete deletes songs from playlist. If both start and end are positive,
// it deletes those at positions in range [start, end). If end is negative,
// it deletes the song at position start.
func (c *Client) Delete(start, end int) os.Error {
	if start < 0 {
		return os.NewError("negative start index")
	}
	if end < 0 {
		return c.okCmd("delete %d", start)
	}
	return c.okCmd("delete %d %d", start, end)
}

// DeleteId deletes the song identified by id.
func (c *Client) DeleteId(id int) os.Error {
	return c.okCmd("deleteid %d", id)
}

// Add adds the file/directory uri to playlist. Directories add recursively.
func (c *Client) Add(uri string) os.Error {
	return c.okCmd("add %q", uri)
}

// AddId adds the file/directory uri to playlist and returns the identity
// id of the song added. If pos is positive, the song is added to position
// pos.
func (c *Client) AddId(uri string, pos int) (int, os.Error) {
	var id uint
	var err os.Error
	if pos >= 0 {
		id, err = c.text.Cmd("addid %q %d", uri, pos)
	}
	id, err = c.text.Cmd("addid %q", uri)
	if err != nil {
		return -1, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	attrs, err := c.readAttrs()
	if err != nil {
		return -1, err
	}
	tok, ok := attrs["Id"]
	if !ok {
		return -1, textproto.ProtocolError("addid did not return Id")
	}
	return strconv.Atoi(tok)
}

// Clear clears the current playlist.
func (c *Client) Clear() os.Error {
	return c.okCmd("clear")
}
<|endoftext|>