<commit_before>package main

import (
	"fmt"
	"github.com/alphagov/router/handlers"
	"github.com/alphagov/router/logger"
	"github.com/alphagov/router/triemux"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"net/url"
	"time"
)

// Router is a wrapper around an HTTP multiplexer (trie.Mux) which retrieves its
// routes from a passed mongo database.
type Router struct {
	mux                   *triemux.Mux
	mongoUrl              string
	mongoDbName           string
	backendConnectTimeout time.Duration
	backendHeaderTimeout  time.Duration
	logger                logger.Logger
}

type Backend struct {
	BackendId  string `bson:"backend_id"`
	BackendURL string `bson:"backend_url"`
}

type Route struct {
	IncomingPath string `bson:"incoming_path"`
	RouteType    string `bson:"route_type"`
	Handler      string `bson:"handler"`
	BackendId    string `bson:"backend_id"`
	RedirectTo   string `bson:"redirect_to"`
	RedirectType string `bson:"redirect_type"`
}

// NewRouter returns a new empty router instance. You will still need to call
// ReloadRoutes() to do the initial route load.
func NewRouter(mongoUrl, mongoDbName, backendConnectTimeout, backendHeaderTimeout, logFileName string) (rt *Router, err error) {
	beConnTimeout, err := time.ParseDuration(backendConnectTimeout)
	if err != nil {
		return nil, err
	}
	beHeaderTimeout, err := time.ParseDuration(backendHeaderTimeout)
	if err != nil {
		return nil, err
	}
	log.Printf("router: using backend connect timeout: %v", beConnTimeout)
	log.Printf("router: using backend header timeout: %v", beHeaderTimeout)

	l, err := logger.New(logFileName)
	if err != nil {
		return nil, err
	}
	log.Printf("router: logging errors as JSON to %v", logFileName)

	rt = &Router{
		mux:                   triemux.NewMux(),
		mongoUrl:              mongoUrl,
		mongoDbName:           mongoDbName,
		backendConnectTimeout: beConnTimeout,
		backendHeaderTimeout:  beHeaderTimeout,
		logger:                l,
	}
	return rt, nil
}

// ServeHTTP delegates responsibility for serving requests to the proxy mux
// instance for this router.
func (rt *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("router: recovered from panic in ServeHTTP:", r)
			rt.logger.LogFromClientRequest(map[string]interface{}{"error": fmt.Sprintf("panic: %v", r), "status": 500}, req)
			w.WriteHeader(http.StatusInternalServerError)
		}
	}()

	rt.mux.ServeHTTP(w, req)
}

// ReloadRoutes reloads the routes for this Router instance on the fly. It will
// create a new proxy mux, load applications (backends) and routes into it, and
// then flip the "mux" pointer in the Router.
func (rt *Router) ReloadRoutes() {
	// save a reference to the previous mux in case we have to restore it
	oldmux := rt.mux
	defer func() {
		if r := recover(); r != nil {
			log.Println("router: recovered from panic in ReloadRoutes:", r)
			rt.mux = oldmux
			log.Println("router: original routes have been restored")
		}
	}()

	log.Println("mgo: connecting to", rt.mongoUrl)
	sess, err := mgo.Dial(rt.mongoUrl)
	if err != nil {
		panic(fmt.Sprintln("mgo:", err))
	}
	defer sess.Close()
	sess.SetMode(mgo.Monotonic, true)

	db := sess.DB(rt.mongoDbName)

	log.Printf("router: reloading routes")
	newmux := triemux.NewMux()

	backends := rt.loadBackends(db.C("backends"))
	loadRoutes(db.C("routes"), newmux, backends)

	rt.mux = newmux
	log.Printf("router: reloaded %d routes (checksum: %x)", rt.mux.RouteCount(), rt.mux.RouteChecksum())
}

// loadBackends is a helper function which loads backends from the
// passed mongo collection, constructs a Handler for each one, and returns
// them in map keyed on the backend_id
func (rt *Router) loadBackends(c *mgo.Collection) (backends map[string]http.Handler) {
	backend := &Backend{}
	backends = make(map[string]http.Handler)

	iter := c.Find(nil).Iter()

	for iter.Next(&backend) {
		backendUrl, err := url.Parse(backend.BackendURL)
		if err != nil {
			log.Printf("router: couldn't parse URL %s for backend %s "+
				"(error: %v), skipping!", backend.BackendURL, backend.BackendId, err)
			continue
		}

		backends[backend.BackendId] = handlers.NewBackendHandler(backendUrl, rt.backendConnectTimeout, rt.backendHeaderTimeout, rt.logger)
	}

	if err := iter.Err(); err != nil {
		panic(err)
	}

	return
}

// loadRoutes is a helper function which loads routes from the passed mongo
// collection and registers them with the passed proxy mux.
func loadRoutes(c *mgo.Collection, mux *triemux.Mux, backends map[string]http.Handler) {
	route := &Route{}

	iter := c.Find(nil).Sort("incoming_path", "route_type").Iter()

	for iter.Next(&route) {
		prefix := (route.RouteType == "prefix")
		switch route.Handler {
		case "backend":
			handler, ok := backends[route.BackendId]
			if !ok {
				log.Printf("router: found route %+v which references unknown application "+
					"%s, skipping!", route, route.BackendId)
				continue
			}
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) for %s",
				route.IncomingPath, prefix, route.BackendId)
		case "redirect":
			redirectTemporarily := (route.RedirectType == "temporary")
			handler := handlers.NewRedirectHandler(route.IncomingPath, route.RedirectTo, prefix, redirectTemporarily)
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) -> %s",
				route.IncomingPath, prefix, route.RedirectTo)
		case "gone":
			handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusGone)
			})
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) -> Gone", route.IncomingPath, prefix)
		case "boom":
			// Special handler so that we can test failure behaviour.
			mux.Handle(route.IncomingPath, prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				panic("Boom!!!")
			}))
			log.Printf("router: registered %s (prefix: %v) -> Boom!!!", route.IncomingPath, prefix)
		default:
			log.Printf("router: found route %+v with unknown handler type "+
				"%s, skipping!", route, route.Handler)
			continue
		}
	}

	if err := iter.Err(); err != nil {
		panic(err)
	}
}

func (rt *Router) RouteStats() (stats map[string]interface{}) {
	stats = make(map[string]interface{})
	stats["count"] = rt.mux.RouteCount()
	stats["checksum"] = fmt.Sprintf("%x", rt.mux.RouteChecksum())
	return
}
<commit_msg>Always read from the mongo primary.<commit_after>package main

import (
	"fmt"
	"github.com/alphagov/router/handlers"
	"github.com/alphagov/router/logger"
	"github.com/alphagov/router/triemux"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"net/url"
	"time"
)

// Router is a wrapper around an HTTP multiplexer (trie.Mux) which retrieves its
// routes from a passed mongo database.
type Router struct {
	mux                   *triemux.Mux
	mongoUrl              string
	mongoDbName           string
	backendConnectTimeout time.Duration
	backendHeaderTimeout  time.Duration
	logger                logger.Logger
}

type Backend struct {
	BackendId  string `bson:"backend_id"`
	BackendURL string `bson:"backend_url"`
}

type Route struct {
	IncomingPath string `bson:"incoming_path"`
	RouteType    string `bson:"route_type"`
	Handler      string `bson:"handler"`
	BackendId    string `bson:"backend_id"`
	RedirectTo   string `bson:"redirect_to"`
	RedirectType string `bson:"redirect_type"`
}

// NewRouter returns a new empty router instance. You will still need to call
// ReloadRoutes() to do the initial route load.
func NewRouter(mongoUrl, mongoDbName, backendConnectTimeout, backendHeaderTimeout, logFileName string) (rt *Router, err error) {
	beConnTimeout, err := time.ParseDuration(backendConnectTimeout)
	if err != nil {
		return nil, err
	}
	beHeaderTimeout, err := time.ParseDuration(backendHeaderTimeout)
	if err != nil {
		return nil, err
	}
	log.Printf("router: using backend connect timeout: %v", beConnTimeout)
	log.Printf("router: using backend header timeout: %v", beHeaderTimeout)

	l, err := logger.New(logFileName)
	if err != nil {
		return nil, err
	}
	log.Printf("router: logging errors as JSON to %v", logFileName)

	rt = &Router{
		mux:                   triemux.NewMux(),
		mongoUrl:              mongoUrl,
		mongoDbName:           mongoDbName,
		backendConnectTimeout: beConnTimeout,
		backendHeaderTimeout:  beHeaderTimeout,
		logger:                l,
	}
	return rt, nil
}

// ServeHTTP delegates responsibility for serving requests to the proxy mux
// instance for this router.
func (rt *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("router: recovered from panic in ServeHTTP:", r)
			rt.logger.LogFromClientRequest(map[string]interface{}{"error": fmt.Sprintf("panic: %v", r), "status": 500}, req)
			w.WriteHeader(http.StatusInternalServerError)
		}
	}()

	rt.mux.ServeHTTP(w, req)
}

// ReloadRoutes reloads the routes for this Router instance on the fly. It will
// create a new proxy mux, load applications (backends) and routes into it, and
// then flip the "mux" pointer in the Router.
func (rt *Router) ReloadRoutes() {
	// save a reference to the previous mux in case we have to restore it
	oldmux := rt.mux
	defer func() {
		if r := recover(); r != nil {
			log.Println("router: recovered from panic in ReloadRoutes:", r)
			rt.mux = oldmux
			log.Println("router: original routes have been restored")
		}
	}()

	log.Println("mgo: connecting to", rt.mongoUrl)
	sess, err := mgo.Dial(rt.mongoUrl)
	if err != nil {
		panic(fmt.Sprintln("mgo:", err))
	}
	defer sess.Close()
	sess.SetMode(mgo.Strong, true)

	db := sess.DB(rt.mongoDbName)

	log.Printf("router: reloading routes")
	newmux := triemux.NewMux()

	backends := rt.loadBackends(db.C("backends"))
	loadRoutes(db.C("routes"), newmux, backends)

	rt.mux = newmux
	log.Printf("router: reloaded %d routes (checksum: %x)", rt.mux.RouteCount(), rt.mux.RouteChecksum())
}

// loadBackends is a helper function which loads backends from the
// passed mongo collection, constructs a Handler for each one, and returns
// them in map keyed on the backend_id
func (rt *Router) loadBackends(c *mgo.Collection) (backends map[string]http.Handler) {
	backend := &Backend{}
	backends = make(map[string]http.Handler)

	iter := c.Find(nil).Iter()

	for iter.Next(&backend) {
		backendUrl, err := url.Parse(backend.BackendURL)
		if err != nil {
			log.Printf("router: couldn't parse URL %s for backend %s "+
				"(error: %v), skipping!", backend.BackendURL, backend.BackendId, err)
			continue
		}

		backends[backend.BackendId] = handlers.NewBackendHandler(backendUrl, rt.backendConnectTimeout, rt.backendHeaderTimeout, rt.logger)
	}

	if err := iter.Err(); err != nil {
		panic(err)
	}

	return
}

// loadRoutes is a helper function which loads routes from the passed mongo
// collection and registers them with the passed proxy mux.
func loadRoutes(c *mgo.Collection, mux *triemux.Mux, backends map[string]http.Handler) {
	route := &Route{}

	iter := c.Find(nil).Sort("incoming_path", "route_type").Iter()

	for iter.Next(&route) {
		prefix := (route.RouteType == "prefix")
		switch route.Handler {
		case "backend":
			handler, ok := backends[route.BackendId]
			if !ok {
				log.Printf("router: found route %+v which references unknown application "+
					"%s, skipping!", route, route.BackendId)
				continue
			}
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) for %s",
				route.IncomingPath, prefix, route.BackendId)
		case "redirect":
			redirectTemporarily := (route.RedirectType == "temporary")
			handler := handlers.NewRedirectHandler(route.IncomingPath, route.RedirectTo, prefix, redirectTemporarily)
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) -> %s",
				route.IncomingPath, prefix, route.RedirectTo)
		case "gone":
			handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusGone)
			})
			mux.Handle(route.IncomingPath, prefix, handler)
			log.Printf("router: registered %s (prefix: %v) -> Gone", route.IncomingPath, prefix)
		case "boom":
			// Special handler so that we can test failure behaviour.
			mux.Handle(route.IncomingPath, prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				panic("Boom!!!")
			}))
			log.Printf("router: registered %s (prefix: %v) -> Boom!!!", route.IncomingPath, prefix)
		default:
			log.Printf("router: found route %+v with unknown handler type "+
				"%s, skipping!", route, route.Handler)
			continue
		}
	}

	if err := iter.Err(); err != nil {
		panic(err)
	}
}

func (rt *Router) RouteStats() (stats map[string]interface{}) {
	stats = make(map[string]interface{})
	stats["count"] = rt.mux.RouteCount()
	stats["checksum"] = fmt.Sprintf("%x", rt.mux.RouteChecksum())
	return
}
<|endoftext|>


<commit_before>package webgo

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// Struct to define a route for each API
type Route struct {
	Name    string       // Just a label to name the route/API, this is not used anywhere
	Method  string       // Request type
	Pattern string       // URI
	Handler HandlerChain // Handler function with middlewares
	G       *Globals     // App globals
}

// Inject httprouter params to the context
func InjectParams(route Route) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		// convert httprouter params to map of string
		params := make(map[string]string)
		for i := range ps {
			params[ps[i].Key] = ps[i].Value
		}

		// Injecting multiplexer params to every request context
		newHandlerChain := StackInject(route.Handler, "params", params)
		// Injecting globals to every request context
		route.G.Params["routeName"] = route.Name
		newHandlerChain = StackInject(newHandlerChain, "globals", route.G)
		newHandlerChain.ServeHTTP(w, r)
	}
}

// Initiate Router settings
func InitRouter(routes []Route) *httprouter.Router {
	router := httprouter.New()

	// Handles all the route types
	for _, route := range routes {
		switch route.Method {
		case "OPTIONS":
			router.OPTIONS(
				route.Pattern,
				InjectParams(route))
		case "GET":
			router.GET(
				route.Pattern,
				InjectParams(route))
		case "POST":
			router.POST(
				route.Pattern,
				InjectParams(route))
		case "PUT":
			router.PUT(
				route.Pattern,
				InjectParams(route))
		case "DELETE":
			router.DELETE(
				route.Pattern,
				InjectParams(route))
		case "PATCH":
			router.PATCH(
				route.Pattern,
				InjectParams(route))
		}
	}
	return router
}

// ===
<commit_msg>the whole route handler is now injected rather than just globals<commit_after>package webgo

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// Struct to define a route for each API
type Route struct {
	Name    string       // Just a label to name the route/API, this is not used anywhere
	Method  string       // Request type
	Pattern string       // URI
	Handler HandlerChain // Handler function with middlewares
	G       *Globals     // App globals
}

// Inject httprouter params to the context
func InjectParams(route Route) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		// convert httprouter params to map of string
		params := make(map[string]string)
		for i := range ps {
			params[ps[i].Key] = ps[i].Value
		}

		// Injecting multiplexer params to every request context
		newHandlerChain := StackInject(route.Handler, "params", params)

		newHandlerChain = StackInject(newHandlerChain, "routeHandler", &route)
		newHandlerChain.ServeHTTP(w, r)
	}
}

// Initiate Router settings
func InitRouter(routes []Route) *httprouter.Router {
	router := httprouter.New()

	// Handles all the route types
	for _, route := range routes {
		switch route.Method {
		case "OPTIONS":
			router.OPTIONS(
				route.Pattern,
				InjectParams(route))
		case "GET":
			router.GET(
				route.Pattern,
				InjectParams(route))
		case "POST":
			router.POST(
				route.Pattern,
				InjectParams(route))
		case "PUT":
			router.PUT(
				route.Pattern,
				InjectParams(route))
		case "DELETE":
			router.DELETE(
				route.Pattern,
				InjectParams(route))
		case "PATCH":
			router.PATCH(
				route.Pattern,
				InjectParams(route))
		}
	}
	return router
}

// ===
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"github.com/kr/fs"
	"github.com/ogier/pflag"
	"os"
	"runtime"
	"strconv"
	"strings"
)

func getSearchSources() []string {
	home := os.Getenv("HOME")

	// OS X
	if runtime.GOOS == "darwin" {
		var sources []string

		sources = append(sources, home+"/.bash_profile")

		walker := fs.Walk("/etc/paths.d")
		for walker.Step() {
			if err := walker.Err(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				continue
			}
			sources = append(sources, walker.Path())
		}

		sources = append(sources, "/etc/paths")

		return sources
	}

	// Ubuntu
	bashrc := home + "/.bashrc"
	bashprofile := home + "/.bash_profile"
	profile := home + "/.profile"
	env := "/etc/environment"

	return []string{bashrc, bashprofile, profile, env}
}

func appendSource(path string, pathChan chan string) {
	pathSetBy := path + " set by: "
	for _, source := range getSearchSources() {
		f, err := os.Open(source)
		if err != nil {
			// Allow execution to continue as some files are optional.
			//panic(err)
		}
		defer f.Close()

		scanner := bufio.NewScanner(f)
		for i := 1; scanner.Scan(); i++ {
			if strings.Contains(scanner.Text(), "PATH=") {
				if strings.Contains(scanner.Text(), path) {
					p := pathSetBy + source + " (line " + strconv.Itoa(i) + ")"
					pathChan <- p
					return
				}
			}
		}
	}

	pathChan <- pathSetBy + "unknown"
	return
}

func returnPathList(detailedList bool) []string {
	pathList := strings.Split(os.Getenv("PATH"), ":")
	if !detailedList {
		return pathList
	}

	pathChan := make(chan string, len(pathList))
	for _, path := range pathList {
		go appendSource(path, pathChan)
	}

	var appendedPathList []string
	for i := 0; i < len(pathList); i++ {
		appendedPathList = append(appendedPathList, <-pathChan)
	}

	return appendedPathList
}

func main() {
	const listUsage = "use a long listing format"
	useList := pflag.BoolP("list", "l", false, listUsage)

	const detailedUsage = "use a (detailed) long listing format"
	detailedList := pflag.BoolP("detailed-list", "d", false, detailedUsage)

	pflag.Parse()

	if !(*useList || *detailedList) {
		fmt.Println(os.Getenv("PATH"))
		return
	}

	for _, p := range returnPathList(*detailedList) {
		fmt.Println(p)
	}
}
<commit_msg>Fixed detailed-list bug introduced by last commit.<commit_after>package main

import (
	"bufio"
	"fmt"
	"github.com/kr/fs"
	"github.com/ogier/pflag"
	"os"
	"runtime"
	"strconv"
	"strings"
)

func getSearchSources() []string {
	home := os.Getenv("HOME")

	// OS X
	if runtime.GOOS == "darwin" {
		var sources []string

		sources = append(sources, "/etc/paths")

		walker := fs.Walk("/etc/paths.d")
		for walker.Step() {
			if err := walker.Err(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				continue
			}

			if walker.Path() != "/etc/paths.d" {
				sources = append(sources, walker.Path())
			}
		}

		sources = append(sources, home+"/.bash_profile")

		return sources
	}

	// Ubuntu
	bashrc := home + "/.bashrc"
	bashprofile := home + "/.bash_profile"
	profile := home + "/.profile"
	env := "/etc/environment"

	return []string{bashrc, bashprofile, profile, env}
}

func appendSource(path string, pathChan chan string) {
	pathSetBy := path + " set by: "

	for _, source := range getSearchSources() {
		f, err := os.Open(source)
		if err != nil {
			// Allow execution to continue as some files are optional.
			//panic(err)
		}
		defer f.Close()

		scanner := bufio.NewScanner(f)
		for i := 1; scanner.Scan(); i++ {
			if runtime.GOOS == "darwin" {
				if strings.Contains(scanner.Text(), path) {
					p := pathSetBy + source + " (line " + strconv.Itoa(i) + ")"
					pathChan <- p
					return
				}
			} else {
				if strings.Contains(scanner.Text(), "PATH=") {
					if strings.Contains(scanner.Text(), path) {
						p := pathSetBy + source + " (line " + strconv.Itoa(i) + ")"
						pathChan <- p
						return
					}
				}
			}
		}
	}

	pathChan <- pathSetBy + "unknown"
	return
}

func returnPathList(detailedList bool) []string {
	pathList := strings.Split(os.Getenv("PATH"), ":")
	if !detailedList {
		return pathList
	}

	pathChan := make(chan string, len(pathList))
	for _, path := range pathList {
		go appendSource(path, pathChan)
	}

	var appendedPathList []string
	for i := 0; i < len(pathList); i++ {
		appendedPathList = append(appendedPathList, <-pathChan)
	}

	return appendedPathList
}

func main() {
	const listUsage = "use a long listing format"
	useList := pflag.BoolP("list", "l", false, listUsage)

	const detailedUsage = "use a (detailed) long listing format"
	detailedList := pflag.BoolP("detailed-list", "d", false, detailedUsage)

	pflag.Parse()

	if !(*useList || *detailedList) {
		fmt.Println(os.Getenv("PATH"))
		return
	}

	for _, p := range returnPathList(*detailedList) {
		fmt.Println(p)
	}
}
<|endoftext|>


<commit_before>package glukit

import (
	"appengine"
	"appengine/channel"
	"appengine/datastore"
	"appengine/delay"
	"appengine/taskqueue"
	"appengine/user"
	"code.google.com/p/gorilla/mux"
	"github.com/alexandre-normand/glukit/app/engine"
	"github.com/alexandre-normand/glukit/app/model"
	"github.com/alexandre-normand/glukit/app/store"
	"github.com/alexandre-normand/glukit/app/util"
	"github.com/alexandre-normand/glukit/lib/goauth2/oauth"
	"html/template"
	"net/http"
	"sync"
	"time"
)

var graphTemplate = template.Must(template.ParseFiles("view/templates/graph.html"))
var reportTemplate = template.Must(template.ParseFiles("view/templates/report.html"))
var landingTemplate = template.Must(template.ParseFiles("view/templates/landing.html"))
var nodataTemplate = template.Must(template.ParseFiles("view/templates/nodata.html"))
var muxRouter = mux.NewRouter()
var initOnce sync.Once

const (
	DEMO_PATH_PREFIX = "demo."
	DEMO_PICTURE_URL = "http://farm8.staticflickr.com/7389/10813078553_ab4e1397f4_b_d.jpg"
)

// Some variables that are used during rendering of templates
type RenderVariables struct {
	PathPrefix   string
	ChannelToken string
}

// init initializes the routes and global initialization
func init() {
	http.Handle("/", muxRouter)

	// Create user Glukit Bernstein as a fallback for comparisons
	muxRouter.HandleFunc("/_ah/warmup", warmUp)
	muxRouter.HandleFunc("/initpower", warmUp)

	// Json endpoints
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"data", demoContent)
	muxRouter.HandleFunc("/data", personalData)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"steadySailor", demoSteadySailorData)
	muxRouter.HandleFunc("/steadySailor", steadySailorData)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"dashboard", demoDashboard)
	muxRouter.HandleFunc("/dashboard", dashboard)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"glukitScores", glukitScoresForDemo)
	muxRouter.HandleFunc("/glukitScores", glukitScores)

	// "main"-page for both demo and real users
	muxRouter.HandleFunc("/demo", renderDemo)
	muxRouter.HandleFunc("/graph", renderRealUser)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"report", demoReport)
	muxRouter.HandleFunc("/report", report)

	// Static pages
	muxRouter.HandleFunc("/", landing)
	muxRouter.HandleFunc("/nodata", nodata)

	muxRouter.HandleFunc("/realuser", handleRealUser)
	muxRouter.HandleFunc("/oauth2callback", oauthCallback)

	// Client API endpoints
	muxRouter.HandleFunc("/v1/calibrations", initializeAndHandleRequest).Methods("POST").Name(CALIBRATIONS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/injections", initializeAndHandleRequest).Methods("POST").Name(INJECTIONS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/meals", initializeAndHandleRequest).Methods("POST").Name(MEALS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/glucosereads", initializeAndHandleRequest).Methods("POST").Name(GLUCOSEREADS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/exercises", initializeAndHandleRequest).Methods("POST").Name(EXERCISES_V1_ROUTE)

	// Register oauth endpoints to warmup which will initilize the oauth server and replace the routes with the actual oauth handlers
	muxRouter.HandleFunc("/token", initializeAndHandleRequest).Name(TOKEN_ROUTE)
	muxRouter.HandleFunc("/authorize", initializeAndHandleRequest).Name(AUTHORIZE_ROUTE)

	// Initialize task functions that would otherwise be prone to initialization loops
	refreshUserData = delay.Func(REFRESH_USER_DATA_FUNCTION_NAME, updateUserData)
	processFile = delay.Func(PROCESS_FILE_FUNCTION_NAME, processSingleFile)
	engine.RunGlukitScoreCalculationChunk = delay.Func(engine.GLUKIT_SCORE_BATCH_CALCULATION_FUNCTION_NAME, engine.RunGlukitScoreBatchCalculation)
}

// landing executes the landing page template
func landing(w http.ResponseWriter, request *http.Request) {
	if err := landingTemplate.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// nodata renders the no-data available page that shows up when a user
// first accesses the app and doesn't have any dexcom files on Google Drive
func nodata(w http.ResponseWriter, request *http.Request) {
	if err := nodataTemplate.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// oauthCallback is invoked on return of the google oauth flow after being
// the user comes back from being redirected to google oauth for authorization
func oauthCallback(writer http.ResponseWriter, request *http.Request) {
	handleLoggedInUser(writer, request)
}

// renderDemo executes the graph template for the demo user
func renderDemo(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	_, key, _, err := store.GetUserData(context, DEMO_EMAIL)
	if err == datastore.ErrNoSuchEntity {
		context.Infof("No data found for demo user [%s], creating it", DEMO_EMAIL)
		dummyToken := oauth.Token{"", "", util.GLUKIT_EPOCH_TIME}
		// TODO: Populate GlukitUser correctly, this will likely require
		// getting rid of all data from the store when this is ready
		key, err = store.StoreUserProfile(context, time.Now(),
			model.GlukitUser{DEMO_EMAIL, "Demo", "OfMe", time.Now(), model.DIABETES_TYPE_1, "", time.Now(),
				model.UNDEFINED_GLUCOSE_READ, dummyToken, "", model.UNDEFINED_SCORE, model.UNDEFINED_SCORE, true, DEMO_PICTURE_URL, time.Now()})
		if err != nil {
			util.Propagate(err)
		}

		task, err := processDemoFile.Task(key)
		if err != nil {
			util.Propagate(err)
		}
		taskqueue.Add(context, task, DATASTORE_WRITES_QUEUE_NAME)

	} else if err != nil {
		util.Propagate(err)
	} else {
		context.Infof("Data already stored for demo user [%s], continuing...", DEMO_EMAIL)
	}

	render(DEMO_EMAIL, DEMO_PATH_PREFIX, w, request)
}

// renderRealUser executes the graph page template for a real user
func renderRealUser(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	user := user.Current(context)
	render(user.Email, "", w, request)
}

// report executes the report page template
func demoReport(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	renderVariables := &RenderVariables{PathPrefix: DEMO_PATH_PREFIX, ChannelToken: "none"}

	if err := reportTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// report executes the report page template
func report(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	renderVariables := &RenderVariables{PathPrefix: "", ChannelToken: "none"}

	if err := reportTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// render executed the graph page template
func render(email string, datapath string, w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	token, err := channel.Create(context, email)
	if err != nil {
		context.Criticalf("Error creating channel for user [%s]", email)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	renderVariables := &RenderVariables{PathPrefix: datapath, ChannelToken: token}

	if err := graphTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// handleRealUser handles the flow for a real non-demo user. It will redirect to authorization if required
func handleRealUser(writer http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	user := user.Current(context)

	glukitUser, _, _, err := store.GetUserData(context, user.Email)
	if _, ok := err.(store.StoreError); err != nil && !ok || len(glukitUser.RefreshToken) == 0 {
		context.Infof("Redirecting [%s], glukitUser [%v] for authorization. Error: [%v]", user.Email, glukitUser, err)

		configuration := config()
		context.Debugf("We don't current have a refresh token (either lost or it's " +
			"the first access). Let's set the ApprovalPrompt to force to get a new one...")

		configuration.ApprovalPrompt = "force"

		url := configuration.AuthCodeURL(request.URL.RawQuery)
		http.Redirect(writer, request, url, http.StatusFound)
	} else {
		context.Infof("User [%s] already exists with a valid refresh token [%s], skipping authorization step...",
			glukitUser.RefreshToken, user.Email)
		oauthCallback(writer, request)
	}
}

func warmUp(writer http.ResponseWriter, request *http.Request) {
	initOnce.Do(func() {
		c := appengine.NewContext(request)
		c.Infof("Initializing application...")
		initializeApp(writer, request)
	})
}

func initializeAndHandleRequest(writer http.ResponseWriter, request *http.Request) {
	warmUp(writer, request)

	muxRouter.ServeHTTP(writer, request)
}

func initializeApp(writer http.ResponseWriter, request *http.Request) {
	initOauthProvider(writer, request)
	initApiEndpoints(writer, request)
	//initializeGlukitBernstein(writer, request)
}
<commit_msg>Allow Only POSTs on /token.<commit_after>package glukit

import (
	"appengine"
	"appengine/channel"
	"appengine/datastore"
	"appengine/delay"
	"appengine/taskqueue"
	"appengine/user"
	"code.google.com/p/gorilla/mux"
	"github.com/alexandre-normand/glukit/app/engine"
	"github.com/alexandre-normand/glukit/app/model"
	"github.com/alexandre-normand/glukit/app/store"
	"github.com/alexandre-normand/glukit/app/util"
	"github.com/alexandre-normand/glukit/lib/goauth2/oauth"
	"html/template"
	"net/http"
	"sync"
	"time"
)

var graphTemplate = template.Must(template.ParseFiles("view/templates/graph.html"))
var reportTemplate = template.Must(template.ParseFiles("view/templates/report.html"))
var landingTemplate = template.Must(template.ParseFiles("view/templates/landing.html"))
var nodataTemplate = template.Must(template.ParseFiles("view/templates/nodata.html"))
var muxRouter = mux.NewRouter()
var initOnce sync.Once

const (
	DEMO_PATH_PREFIX = "demo."
	DEMO_PICTURE_URL = "http://farm8.staticflickr.com/7389/10813078553_ab4e1397f4_b_d.jpg"
)

// Some variables that are used during rendering of templates
type RenderVariables struct {
	PathPrefix   string
	ChannelToken string
}

// init initializes the routes and global initialization
func init() {
	http.Handle("/", muxRouter)

	// Create user Glukit Bernstein as a fallback for comparisons
	muxRouter.HandleFunc("/_ah/warmup", warmUp)
	muxRouter.HandleFunc("/initpower", warmUp)

	// Json endpoints
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"data", demoContent)
	muxRouter.HandleFunc("/data", personalData)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"steadySailor", demoSteadySailorData)
	muxRouter.HandleFunc("/steadySailor", steadySailorData)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"dashboard", demoDashboard)
	muxRouter.HandleFunc("/dashboard", dashboard)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"glukitScores", glukitScoresForDemo)
	muxRouter.HandleFunc("/glukitScores", glukitScores)

	// "main"-page for both demo and real users
	muxRouter.HandleFunc("/demo", renderDemo)
	muxRouter.HandleFunc("/graph", renderRealUser)
	muxRouter.HandleFunc("/"+DEMO_PATH_PREFIX+"report", demoReport)
	muxRouter.HandleFunc("/report", report)

	// Static pages
	muxRouter.HandleFunc("/", landing)
	muxRouter.HandleFunc("/nodata", nodata)

	muxRouter.HandleFunc("/realuser", handleRealUser)
	muxRouter.HandleFunc("/oauth2callback", oauthCallback)

	// Client API endpoints
	muxRouter.HandleFunc("/v1/calibrations", initializeAndHandleRequest).Methods("POST").Name(CALIBRATIONS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/injections", initializeAndHandleRequest).Methods("POST").Name(INJECTIONS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/meals", initializeAndHandleRequest).Methods("POST").Name(MEALS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/glucosereads", initializeAndHandleRequest).Methods("POST").Name(GLUCOSEREADS_V1_ROUTE)
	muxRouter.HandleFunc("/v1/exercises", initializeAndHandleRequest).Methods("POST").Name(EXERCISES_V1_ROUTE)

	// Register oauth endpoints to warmup which will initilize the oauth server and replace the routes with the actual oauth handlers
	muxRouter.HandleFunc("/token", initializeAndHandleRequest).Methods("POST").Name(TOKEN_ROUTE)
	muxRouter.HandleFunc("/authorize", initializeAndHandleRequest).Methods("GET").Name(AUTHORIZE_ROUTE)

	// Initialize task functions that would otherwise be prone to initialization loops
	refreshUserData = delay.Func(REFRESH_USER_DATA_FUNCTION_NAME, updateUserData)
	processFile = delay.Func(PROCESS_FILE_FUNCTION_NAME, processSingleFile)
	engine.RunGlukitScoreCalculationChunk = delay.Func(engine.GLUKIT_SCORE_BATCH_CALCULATION_FUNCTION_NAME, engine.RunGlukitScoreBatchCalculation)
}

// landing executes the landing page template
func landing(w http.ResponseWriter, request *http.Request) {
	if err := landingTemplate.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// nodata renders the no-data available page that shows up when a user
// first accesses the app and doesn't have any dexcom files on Google Drive
func nodata(w http.ResponseWriter, request *http.Request) {
	if err := nodataTemplate.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// oauthCallback is invoked on return of the google oauth flow after being
// the user comes back from being redirected to google oauth for authorization
func oauthCallback(writer http.ResponseWriter, request *http.Request) {
	handleLoggedInUser(writer, request)
}

// renderDemo executes the graph template for the demo user
func renderDemo(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	_, key, _, err := store.GetUserData(context, DEMO_EMAIL)
	if err == datastore.ErrNoSuchEntity {
		context.Infof("No data found for demo user [%s], creating it", DEMO_EMAIL)
		dummyToken := oauth.Token{"", "", util.GLUKIT_EPOCH_TIME}
		// TODO: Populate GlukitUser correctly, this will likely require
		// getting rid of all data from the store when this is ready
		key, err = store.StoreUserProfile(context, time.Now(),
			model.GlukitUser{DEMO_EMAIL, "Demo", "OfMe", time.Now(), model.DIABETES_TYPE_1, "", time.Now(),
				model.UNDEFINED_GLUCOSE_READ, dummyToken, "", model.UNDEFINED_SCORE, model.UNDEFINED_SCORE, true, DEMO_PICTURE_URL, time.Now()})
		if err != nil {
			util.Propagate(err)
		}

		task, err := processDemoFile.Task(key)
		if err != nil {
			util.Propagate(err)
		}
		taskqueue.Add(context, task, DATASTORE_WRITES_QUEUE_NAME)

	} else if err != nil {
		util.Propagate(err)
	} else {
		context.Infof("Data already stored for demo user [%s], continuing...", DEMO_EMAIL)
	}

	render(DEMO_EMAIL, DEMO_PATH_PREFIX, w, request)
}

// renderRealUser executes the graph page template for a real user
func renderRealUser(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	user := user.Current(context)
	render(user.Email, "", w, request)
}

// report executes the report page template
func demoReport(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	renderVariables := &RenderVariables{PathPrefix: DEMO_PATH_PREFIX, ChannelToken: "none"}

	if err := reportTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// report executes the report page template
func report(w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)

	renderVariables := &RenderVariables{PathPrefix: "", ChannelToken: "none"}

	if err := reportTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// render executed the graph page template
func render(email string, datapath string, w http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	token, err := channel.Create(context, email)
	if err != nil {
		context.Criticalf("Error creating channel for user [%s]", email)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	renderVariables := &RenderVariables{PathPrefix: datapath, ChannelToken: token}

	if err := graphTemplate.Execute(w, renderVariables); err != nil {
		context.Criticalf("Error executing template [%s]", graphTemplate.Name())
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// handleRealUser handles the flow for a real non-demo user. It will redirect to authorization if required
func handleRealUser(writer http.ResponseWriter, request *http.Request) {
	context := appengine.NewContext(request)
	user := user.Current(context)

	glukitUser, _, _, err := store.GetUserData(context, user.Email)
	if _, ok := err.(store.StoreError); err != nil && !ok || len(glukitUser.RefreshToken) == 0 {
		context.Infof("Redirecting [%s], glukitUser [%v] for authorization. Error: [%v]", user.Email, glukitUser, err)

		configuration := config()
		context.Debugf("We don't current have a refresh token (either lost or it's " +
			"the first access). Let's set the ApprovalPrompt to force to get a new one...")

		configuration.ApprovalPrompt = "force"

		url := configuration.AuthCodeURL(request.URL.RawQuery)
		http.Redirect(writer, request, url, http.StatusFound)
	} else {
		context.Infof("User [%s] already exists with a valid refresh token [%s], skipping authorization step...",
			glukitUser.RefreshToken, user.Email)
		oauthCallback(writer, request)
	}
}

func warmUp(writer http.ResponseWriter, request *http.Request) {
	initOnce.Do(func() {
		c := appengine.NewContext(request)
		c.Infof("Initializing application...")
		initializeApp(writer, request)
	})
}

func initializeAndHandleRequest(writer http.ResponseWriter, request *http.Request) {
	warmUp(writer, request)

	muxRouter.ServeHTTP(writer, request)
}

func initializeApp(writer http.ResponseWriter, request *http.Request) {
	initOauthProvider(writer, request)
	initApiEndpoints(writer, request)
	//initializeGlukitBernstein(writer, request)
}
<|endoftext|>


<commit_before>package ambition

import (
	"github.com/julienschmidt/httprouter"
)

// Add routes to http router
// TODO: Add route description parameters and useage
func AddRoutes(router *httprouter.Router) {
	router.GET("/actions", Actions)
	router.GET("/actions/:ActionId", ActionById)
	router.POST("/set/:SetId", PostAction)
	router.GET("/actions/:ActionId/occrurrences", Occurrences)
	router.GET("/occurrences/:OccurrenceId", OccurrenceById)

	// TODO:
	// router.POST("/actions/:ActionId", postOccurrence)
	// router.GET("/sets", sets)
	// router.GET("/sets/:SetId/actions", actionsFromSet)
}
<commit_msg>Fix Occurrence route typo<commit_after>package ambition

import (
	"github.com/julienschmidt/httprouter"
)

// Add routes to http router
// TODO: Add route description parameters and useage
func AddRoutes(router *httprouter.Router) {
	router.GET("/actions", Actions)
	router.GET("/actions/:ActionId", ActionById)
	router.POST("/set/:SetId", PostAction)
	router.GET("/actions/:ActionId/occurrences", Occurrences)
	router.GET("/occurrences/:OccurrenceId", OccurrenceById)

	// TODO:
	// router.POST("/actions/:ActionId", postOccurrence)
	// router.GET("/sets", sets)
	// router.GET("/sets/:SetId/actions", actionsFromSet)
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/raw_reader.go                                       *
 *                                                        *
 * hprose raw reader for Go.                              *
 *                                                        *
 * LastModified: Oct 15, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import "errors"

// RawReader is the hprose raw reader
type RawReader struct {
	ByteReader
}

// NewRawReader is a constructor for RawReader
func NewRawReader(buf []byte) (reader *RawReader) {
	reader = new(RawReader)
	reader.buf = buf
	return
}

// ReadRaw from stream
func (r *RawReader) ReadRaw() (raw []byte) {
	w := new(ByteWriter)
	r.ReadRawTo(w)
	raw = w.Bytes()
	return
}

// ReadRawTo buffer from stream
func (r *RawReader) ReadRawTo(w *ByteWriter) {
	r.readRaw(w, r.readByte())
}

func (r *RawReader) readRaw(w *ByteWriter, tag byte) {
	w.writeByte(tag)
	switch tag {
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
		TagNull, TagEmpty, TagTrue, TagFalse, TagNaN:
	case TagInfinity:
		w.writeByte(r.readByte())
	case TagInteger, TagLong, TagDouble, TagRef:
		r.readNumberRaw(w)
	case TagDate, TagTime:
		r.readDateTimeRaw(w)
	case TagUTF8Char:
		r.readUTF8CharRaw(w)
	case TagBytes:
		r.readBytesRaw(w)
	case TagString:
		r.readStringRaw(w)
	case TagGUID:
		r.readGUIDRaw(w)
	case TagList, TagMap, TagObject:
		r.readComplexRaw(w)
	case TagClass:
		r.readComplexRaw(w)
		r.ReadRawTo(w)
	case TagError:
		r.ReadRawTo(w)
	default:
		unexpectedTag(tag, nil)
	}
	return
}

func (r *RawReader) readNumberRaw(w *ByteWriter) {
	for {
		tag := r.readByte()
		w.writeByte(tag)
		if tag == TagSemicolon {
			return
		}
	}
}

func (r *RawReader) readDateTimeRaw(w *ByteWriter) {
	for {
		tag := r.readByte()
		w.writeByte(tag)
		if tag == TagSemicolon || tag == TagUTC {
			return
		}
	}
}

func (r *RawReader) readUTF8CharRaw(w *ByteWriter) {
	w.write(r.readUTF8Slice(1))
}

func (r *RawReader) readBytesRaw(w *ByteWriter) {
	count := 0
	tag := byte('0')
	for {
		count *= 10
		count += int(tag - '0')
		tag = r.readByte()
		w.writeByte(tag)
		if tag == TagQuote {
			count++
			w.write(r.Next(count))
			return
		}
	}
}

func (r *RawReader) readStringRaw(w *ByteWriter) {
	count := 0
	tag := byte('0')
	for {
		count *= 10
		count += int(tag - '0')
		tag = r.readByte()
		w.writeByte(tag)
		if tag == TagQuote {
			w.write(r.readUTF8Slice(count+1))
			return
		}
	}
}

func (r *RawReader) readGUIDRaw(w *ByteWriter) {
	w.write(r.Next(38))
}

func (r *RawReader) readComplexRaw(w *ByteWriter) {
	var tag byte
	for tag != TagOpenbrace {
		tag = r.readByte()
		w.writeByte(tag)
	}
	tag = r.readByte()
	for tag != TagClosebrace {
		r.readRaw(w, tag)
		tag = r.readByte()
	}
	w.writeByte(tag)
}

// private functions

func unexpectedTag(tag byte, expectTags []byte) {
	if tag == 0 {
		panic(errors.New("No byte found in stream"))
	} else if expectTags == nil {
		panic(errors.New("Unexpected serialize tag '" + string(rune(tag)) + "' in stream"))
	} else {
		panic(errors.New("Tag '" + string(expectTags) + "' expected, but '" + string(rune(tag)) + "' found in stream"))
	}
}
<commit_msg>Update raw_reader.go<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/raw_reader.go                                       *
 *                                                        *
 * hprose raw reader for Go.                              *
 *                                                        *
 * LastModified: Oct 15, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import "errors"

// RawReader is the hprose raw reader
type RawReader struct {
	ByteReader
}

// NewRawReader is a constructor for RawReader
func NewRawReader(buf []byte) (reader *RawReader) {
	reader = new(RawReader)
	reader.buf = buf
	return
}

// ReadRaw from stream
func (r *RawReader) ReadRaw() (raw []byte) {
	w := new(ByteWriter)
	r.ReadRawTo(w)
	raw = w.Bytes()
	return
}

// ReadRawTo buffer from stream
func (r *RawReader) ReadRawTo(w *ByteWriter) {
	r.readRaw(w, r.readByte())
}

func (r *RawReader) readRaw(w *ByteWriter, tag byte) {
	w.writeByte(tag)
	switch tag {
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
		TagNull, TagEmpty, TagTrue, TagFalse, TagNaN:
	case TagInfinity:
		w.writeByte(r.readByte())
	case TagInteger, TagLong, TagDouble, TagRef:
		r.readNumberRaw(w)
	case TagDate, TagTime:
		r.readDateTimeRaw(w)
	case TagUTF8Char:
		r.readUTF8CharRaw(w)
	case TagBytes:
		r.readBytesRaw(w)
	case TagString:
		r.readStringRaw(w)
	case TagGUID:
		r.readGUIDRaw(w)
	case TagList, TagMap, TagObject:
		r.readComplexRaw(w)
	case TagClass:
		r.readComplexRaw(w)
		r.ReadRawTo(w)
	case TagError:
		r.ReadRawTo(w)
	default:
		unexpectedTag(tag, nil)
	}
	return
}

func (r *RawReader) readNumberRaw(w *ByteWriter) {
	for {
		tag := r.readByte()
		w.writeByte(tag)
		if tag == TagSemicolon {
			return
		}
	}
}

func (r *RawReader) readDateTimeRaw(w *ByteWriter) {
	for {
		tag := r.readByte()
		w.writeByte(tag)
		if tag == TagSemicolon || tag == TagUTC {
			return
		}
	}
}

func (r *RawReader) readUTF8CharRaw(w *ByteWriter) {
	w.write(r.readUTF8Slice(1))
}

func (r *RawReader) readBytesRaw(w *ByteWriter) {
	count := 0
	tag := byte('0')
	for {
		count *= 10
		count += int(tag - '0')
		tag = r.readByte()
		w.writeByte(tag)
		if tag == TagQuote {
			count++
			w.write(r.Next(count))
			return
		}
	}
}

func (r *RawReader) readStringRaw(w *ByteWriter) {
	count := 0
	tag := byte('0')
	for {
		count *= 10
		count += int(tag - '0')
		tag = r.readByte()
		w.writeByte(tag)
		if tag == TagQuote {
			w.write(r.readUTF8Slice(count + 1))
			return
		}
	}
}

func (r *RawReader) readGUIDRaw(w *ByteWriter) {
	w.write(r.Next(38))
}

func (r *RawReader) readComplexRaw(w *ByteWriter) {
	var tag byte
	for tag != TagOpenbrace {
		tag = r.readByte()
		w.writeByte(tag)
	}
	tag = r.readByte()
	for tag != TagClosebrace {
		r.readRaw(w, tag)
		tag = r.readByte()
	}
	w.writeByte(tag)
}

// private functions

func unexpectedTag(tag byte, expectTags []byte) {
	if tag == 0 {
		panic(errors.New("No byte found in stream"))
	} else if expectTags == nil {
		panic(errors.New("Unexpected serialize tag '" + string(rune(tag)) + "' in stream"))
	} else {
		panic(errors.New("Tag '" + string(expectTags) + "' expected, but '" + string(rune(tag)) + "' found in stream"))
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2016, 2017 Nicolas Lamirault <nicolas.lamirault@gmail.com>

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

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

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

package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"

	"github.com/zeiot/jarvis-bot/k8s"
	"github.com/zeiot/jarvis-bot/version"
)

var (
	botName = "Jarvis"

	messages = map[string]string{
		"Help": `You can use the following commands:
        /releases : Display last release of components
	/help     : Display help message
	/version  : Show bot version
	`,
	}
)

func route(bot *tgbotapi.BotAPI, update tgbotapi.Update, k8sclient *k8s.Client) {
	tokens := strings.Fields(update.Message.Text)
	command := tokens[0]
	switch command {
	case "/help":
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, messages["Help"])
		bot.Send(msg)
	case "/help@" + botName:
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, messages["Help"])
		bot.Send(msg)
	case "/releases":
		text := getReleases()
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, text)
		bot.Send(msg)
	case "/k8s-services":
		text := getKubernetesServices(k8sclient)
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, text)
		bot.Send(msg)
	case "/version":
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("v%s", version.Version))
		bot.Send(msg)
	}
}

func getKubernetesServices(k8sclient *k8s.Client) string {
	var buffer bytes.Buffer
	buffer.WriteString("Kubernetes Services:\n")
	services, err := k8sclient.GetServices()
	if err != nil {
		log.Printf("[ERROR] Kubernetes services: %s", err.Error())
		buffer.WriteString("Can't retrieve Kubernetes services")
		return buffer.String()
	}
	for _, service := range services.Items {
		buffer.WriteString(fmt.Sprintf("- %s\n", service.Name))
	}
	text := buffer.String()
	log.Printf("[INFO] Kubernetes services: %s", text)
	return text
}
<commit_msg>Add About command<commit_after>// Copyright (C) 2016, 2017 Nicolas Lamirault <nicolas.lamirault@gmail.com>

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

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

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

package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"

	"github.com/zeiot/jarvis-bot/k8s"
	"github.com/zeiot/jarvis-bot/version"
)

var (
	botName = "Jarvis"

	messages = map[string]string{
		"Help": `You can use the following commands:
/releases : Display last release of components
/help     : Display help message
/about    : About this bot
/version  : Show bot version
	`,
	}
)

func route(bot *tgbotapi.BotAPI, update tgbotapi.Update, k8sclient *k8s.Client) {
	tokens := strings.Fields(update.Message.Text)
	command := tokens[0]
	switch command {
	case "/help":
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, messages["Help"])
		bot.Send(msg)
	case "/help@" + botName:
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, messages["Help"])
		bot.Send(msg)
	case "/about":
		msg := getAboutMessage()
		bot.Send(msg)
	case "/releases":
		text := getReleases()
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, text)
		bot.Send(msg)
	case "/k8s-services":
		text := getKubernetesServices(k8sclient)
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, text)
		bot.Send(msg)
	case "/version":
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("v%s", version.Version))
		bot.Send(msg)
	}
}

func getKubernetesServices(k8sclient *k8s.Client) string {
	var buffer bytes.Buffer
	buffer.WriteString("Kubernetes Services:\n")
	services, err := k8sclient.GetServices()
	if err != nil {
		log.Printf("[ERROR] Kubernetes services: %s", err.Error())
		buffer.WriteString("Can't retrieve Kubernetes services")
		return buffer.String()
	}
	for _, service := range services.Items {
		buffer.WriteString(fmt.Sprintf("- %s\n", service.Name))
	}
	text := buffer.String()
	log.Printf("[INFO] Kubernetes services: %s", text)
	return text
}

func getAboutMessage() string {
	var buffer bytes.Buffer
	buffer.WriteString("Telegram bot for Jarvis platform.\n")
	buffer.WriteString("Homepage: https://github.com/zeiot/jarvis-bot\n")
	buffer.WriteString("Releases: https://github.com/zeiot/jarvis-bot/releases\n")
	buffer.WriteString("Issues: https://github.com/zeiot/jarvis-bot/issues\n")
	text := buffer.String()
	return text
}
<|endoftext|>


<commit_before>package rpc

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os/exec"
	"sync"
)

// Remote - holds a connection
type Remote struct {
	outgoing  chan<- []byte
	process   *exec.Cmd
	listeners map[string]RemoteListener
	sync.RWMutex
	conn net.Conn
}

// RemoteListener - function signature that allows things to listen to commands
// sent from the remote process.
type RemoteListener func([]byte)

// wrapper for the JSON commands that are sent over stdin/stdout.
type command struct {
	CommandID  string
	ComandBody string
}

// Command - queues a command to be sent to the remote.
func (r *Remote) Command(commandID string, commandBody []byte) error {
	fmt.Println(r)
	// take the whole command as a JSON string.
	data, err := json.Marshal(command{commandID, string(commandBody)})
	if nil != err {
		return err
	}

	// base64 encode the string.
	base64Data := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
	base64.StdEncoding.Encode(base64Data, data)

	// send the string to the Remote.
	r.outgoing <- base64Data
	return nil
}

// Listen - registers a callback to occur on a specified remote commad.
func (r *Remote) Listen(commandID string, listener RemoteListener) {
	// lock for systems that touch listeners map.
	// lock for reading and writing because this function writes.
	r.Lock()
	defer r.Unlock()

	r.listeners[commandID] = listener
}

// Handler - handles a callback from the remote process.
func (r *Remote) Handler(remoteData []byte) {
	// lock for functions touch the listeners map.
	// only lock for reading because this function only reads.
	r.RLock()
	defer r.RUnlock()

	// base64 decode the message
	data := make([]byte, base64.StdEncoding.DecodedLen(len(remoteData)))
	_, err := base64.StdEncoding.Decode(data, remoteData)
	if nil != err {
		return
	}

	// unpack the command + command body into the containing struct.
	cmd := command{}
	err = json.Unmarshal(data, cmd)
	if nil != err {
		return
	}

	// call the callback if it exists.
	if key, ok := r.listeners[cmd.CommandID]; ok {
		key([]byte(cmd.ComandBody))
	}
}

// RemoteWriter - writes to the stdIN of the process that was passed in.
func RemoteWriter(output <-chan []byte, remoteIn io.WriteCloser) {
	for {
		data := <-output

		_, err := remoteIn.Write(data)
		if nil != err {
			return
		}

		_, err = remoteIn.Write([]byte("\n"))
		if nil != err {
			return
		}
	}
}

// RemoteReader - reads from stdOUT of the process that was passed in.
func RemoteReader(callback func([]byte), remoteOut io.ReadCloser) {

	// make a new reader
	reader := bufio.NewReader(remoteOut)

	for {
		// read a line from the stdout of the remote program.
		line, err := reader.ReadBytes(byte('\n'))
		if err != nil {
			return
		}

		fmt.Println(line)

		// asyncronously send it to the client.
		go callback(line)
	}
}
<commit_msg>fixed json unmarshalling from remote proc<commit_after>package rpc

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"io"
	"net"
	"os/exec"
	"sync"
)

// Remote - holds a connection
type Remote struct {
	outgoing  chan<- []byte
	process   *exec.Cmd
	listeners map[string]RemoteListener
	sync.RWMutex
	conn net.Conn
}

// RemoteListener - function signature that allows things to listen to commands
// sent from the remote process.
type RemoteListener func([]byte)

// wrapper for the JSON commands that are sent over stdin/stdout.
type command struct {
	CommandID  string
	ComandBody string
}

// Command - queues a command to be sent to the remote.
func (r *Remote) Command(commandID string, commandBody []byte) error {
	// take the whole command as a JSON string.
	data, err := json.Marshal(command{commandID, string(commandBody)})
	if nil != err {
		return err
	}

	// base64 encode the string.
	base64Data := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
	base64.StdEncoding.Encode(base64Data, data)

	// send the string to the Remote.
	r.outgoing <- base64Data
	return nil
}

// Listen - registers a callback to occur on a specified remote command.
func (r *Remote) Listen(commandID string, listener RemoteListener) {
	// lock for systems that touch listeners map.
	// lock for reading and writing because this function writes.
	r.Lock()
	defer r.Unlock()

	r.listeners[commandID] = listener
}

// Handler - handles a callback from the remote process.
func (r *Remote) Handler(remoteData []byte) {
	// lock for functions touch the listeners map.
	// only lock for reading because this function only reads.
	r.RLock()
	defer r.RUnlock()

	// base64 decode the message
	data := make([]byte, base64.StdEncoding.DecodedLen(len(remoteData)))
	length, err := base64.StdEncoding.Decode(data, remoteData)
	if nil != err {
		return
	}

	// unpack the command + command body into the containing struct.
	// length is requred because DecodedLen() != Actual decoded len (pads with 0's)
	cmd := command{}
	err = json.Unmarshal(data[:length], &cmd)
	if nil != err {
		return
	}

	// call the callback if it exists.
	if key, ok := r.listeners[cmd.CommandID]; ok {
		key([]byte(cmd.ComandBody))
	}
}

// RemoteWriter - writes to the stdIN of the process that was passed in.
func RemoteWriter(output <-chan []byte, remoteIn io.WriteCloser) {
	for {
		data := <-output

		_, err := remoteIn.Write(data)
		if nil != err {
			return
		}

		_, err = remoteIn.Write([]byte("\n"))
		if nil != err {
			return
		}
	}
}

// RemoteReader - reads from stdOUT of the process that was passed in.
func RemoteReader(callback func([]byte), remoteOut io.ReadCloser) {

	// make a new reader
	reader := bufio.NewReader(remoteOut)

	for {
		// read a line from the stdout of the remote program.
		line, err := reader.ReadBytes(byte('\n'))
		if err != nil {
			return
		}

		// asyncronously send it to the client.
		go callback(line)
	}
}
<|endoftext|>


<commit_before>// Package rstats provides a simple and fast way to compute online statistics.
//
// Original C++ code from John D. Cook
//
// See more on: http://www.johndcook.com/blog/standard_deviation/
package rstats

import (
	"fmt"
	"math"
	"sync"
)

// Stats holds the minimal set of variables to calculate
// online statiscs
type Stats struct {
	// only private fields
	lock           sync.RWMutex
	count          uint64
	min, max       float64
	m1, m2, m3, m4 float64
}

// New get a new instance of Stats
func New() *Stats {
	stats := &Stats{}
	stats.Reset()
	return stats
}

// Add a data point to compute statistics
func (stats *Stats) Add(value float64) {
	stats.lock.Lock()
	defer stats.lock.Unlock()

	stats.min = math.Min(stats.min, value)
	stats.max = math.Max(stats.max, value)

	lastCount := stats.count
	stats.count++
	delta := value - stats.m1
	deltaCount := delta / float64(stats.count)
	deltaCountSquare := deltaCount * deltaCount
	termLast := delta * deltaCount * float64(lastCount)

	stats.m1 += deltaCount
	stats.m4 += termLast*deltaCountSquare*(float64(stats.count*stats.count)-3*float64(stats.count)+3) + 6*deltaCountSquare*stats.m2 - 4*deltaCount*stats.m3
	stats.m3 += termLast*deltaCount*float64(stats.count-2) - 3*deltaCount*stats.m2
	stats.m2 += termLast
}

// Reset all values
func (stats *Stats) Reset() {
	stats.lock.Lock()
	defer stats.lock.Unlock()

	stats.count = 0
	stats.min = math.Inf(0)
	stats.max = math.Inf(-1)
	stats.m1, stats.m2, stats.m3, stats.m4 = 0.0, 0.0, 0.0, 0.0
}

// Count returns the number of elements computed so far
func (stats *Stats) Count() uint64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.count
}

// Min returns the min value added so far
func (stats *Stats) Min() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.min
}

// Max returns the max value added so far
func (stats *Stats) Max() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.max
}

// Mean returns the mean of values added so far
func (stats *Stats) Mean() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.m1
}

// Variance returns the variance of values added so far
func (stats *Stats) Variance() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 1 {
		return stats.m2 / float64(stats.count-1.0)
	}
	return 0.0
}

// StandardDeviation returns the standard deviation of values added so far
func (stats *Stats) StandardDeviation() float64 {
	// no locks
	return math.Sqrt(stats.Variance())
}

// Skewness returns the skewness of values added so far
func (stats *Stats) Skewness() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 0 {
		return math.Sqrt(float64(stats.count)) * stats.m3 / math.Pow(stats.m2, 1.5)
	}
	return 0.0
}

// Kurtosis returns the kurtosis of values added so far
func (stats *Stats) Kurtosis() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 0 {
		return float64(stats.count)*stats.m4/(stats.m2*stats.m2) - 3.0
	}
	return 0.0
}

// String returns a printable string summary of stats
func (stats *Stats) String() string {
	return fmt.Sprintf("count %d min %.2f max %.2f mean %.2f (std dev %.3f variance %.2f) [skewness %.2f kurtosis %.2f]",
		stats.Count(), stats.Min(), stats.Max(), stats.Mean(), stats.StandardDeviation(), stats.Variance(), stats.Skewness(), stats.Kurtosis())
}

// TODO: Implement Linear Regression: http://www.johndcook.com/blog/running_regression/
<commit_msg>fixed corner case with sample count of 1<commit_after>// Package rstats provides a simple and fast way to compute online statistics.
//
// Original C++ code from John D. Cook
//
// See more on: http://www.johndcook.com/blog/standard_deviation/
package rstats

import (
	"fmt"
	"math"
	"sync"
)

// Stats holds the minimal set of variables to calculate
// online statiscs
type Stats struct {
	// only private fields
	lock           sync.RWMutex
	count          uint64
	min, max       float64
	m1, m2, m3, m4 float64
}

// New get a new instance of Stats
func New() *Stats {
	stats := &Stats{}
	stats.Reset()
	return stats
}

// Add a data point to compute statistics
func (stats *Stats) Add(value float64) {
	stats.lock.Lock()
	defer stats.lock.Unlock()

	stats.min = math.Min(stats.min, value)
	stats.max = math.Max(stats.max, value)

	lastCount := stats.count
	stats.count++
	delta := value - stats.m1
	deltaCount := delta / float64(stats.count)
	deltaCountSquare := deltaCount * deltaCount
	termLast := delta * deltaCount * float64(lastCount)

	stats.m1 += deltaCount
	stats.m4 += termLast*deltaCountSquare*(float64(stats.count*stats.count)-3*float64(stats.count)+3) + 6*deltaCountSquare*stats.m2 - 4*deltaCount*stats.m3
	stats.m3 += termLast*deltaCount*float64(stats.count-2) - 3*deltaCount*stats.m2
	stats.m2 += termLast
}

// Reset all values
func (stats *Stats) Reset() {
	stats.lock.Lock()
	defer stats.lock.Unlock()

	stats.count = 0
	stats.min = math.Inf(0)
	stats.max = math.Inf(-1)
	stats.m1, stats.m2, stats.m3, stats.m4 = 0.0, 0.0, 0.0, 0.0
}

// Count returns the number of elements computed so far
func (stats *Stats) Count() uint64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.count
}

// Min returns the min value added so far
func (stats *Stats) Min() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.min
}

// Max returns the max value added so far
func (stats *Stats) Max() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.max
}

// Mean returns the mean of values added so far
func (stats *Stats) Mean() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	return stats.m1
}

// Variance returns the variance of values added so far
func (stats *Stats) Variance() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 1 {
		return stats.m2 / float64(stats.count-1.0)
	}
	return 0.0
}

// StandardDeviation returns the standard deviation of values added so far
func (stats *Stats) StandardDeviation() float64 {
	// no locks
	return math.Sqrt(stats.Variance())
}

// Skewness returns the skewness of values added so far
func (stats *Stats) Skewness() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 1 {
		return math.Sqrt(float64(stats.count)) * stats.m3 / math.Pow(stats.m2, 1.5)
	}
	return 0.0
}

// Kurtosis returns the kurtosis of values added so far
func (stats *Stats) Kurtosis() float64 {
	stats.lock.RLock()
	defer stats.lock.RUnlock()

	if stats.count > 1 {
		return float64(stats.count)*stats.m4/(stats.m2*stats.m2) - 3.0
	}
	return 0.0
}

// String returns a printable string summary of stats
func (stats *Stats) String() string {
	return fmt.Sprintf("count %d min %.2f max %.2f mean %.2f (std dev %.3f variance %.2f) [skewness %.2f kurtosis %.2f]",
		stats.Count(), stats.Min(), stats.Max(), stats.Mean(), stats.StandardDeviation(), stats.Variance(), stats.Skewness(), stats.Kurtosis())
}

// TODO: Implement Linear Regression: http://www.johndcook.com/blog/running_regression/
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"

	"github.com/pkg/errors"
)

// Plugin defines the PyPi plugin parameters
type Plugin struct {
	Repository    string
	Username      string
	Password      string
	SetupFile     string
	Distributions []string
	SkipBuild     bool
}

func (p Plugin) buildCommand() *exec.Cmd {
	// Set the default of distributions in here
	// as CLI package still has issues with string slice defaults
	distributions := []string{"sdist"}
	if len(p.Distributions) > 0 {
		distributions = p.Distributions
	}
	args := []string{p.SetupFile}
	for i := range distributions {
		args = append(args, distributions[i])
	}
	return exec.Command("python3", args...)
}

func (p Plugin) uploadCommand() *exec.Cmd {
	args := []string{}
	args = append(args, "upload")
	args = append(args, "--repository-url")
	args = append(args, p.Repository)
	args = append(args, "--username")
	args = append(args, p.Username)
	args = append(args, "--password")
	args = append(args, p.Password)
	args = append(args, "dist/*")

	return exec.Command("twine", args...)
}

// Exec runs the plugin - doing the necessary setup.py modifications
func (p Plugin) Exec() error {
	if !p.SkipBuild {
		out, err := p.buildCommand().CombinedOutput()
		if err != nil {
			return errors.Wrap(err, string(out))
		}
		log.Printf("Output: %s", out)
	}

	out, err := p.uploadCommand().CombinedOutput()
	if err != nil {
		return errors.Wrap(err, string(out))
	}
	log.Printf("Output: %s", out)

	return nil
}
<commit_msg>fix build dependencies; look for dist in nested dir;<commit_after>package main

import (
	"log"
	"os/exec"
	"path/filepath"

	"github.com/pkg/errors"
)

// Plugin defines the PyPi plugin parameters
type Plugin struct {
	Repository    string
	Username      string
	Password      string
	SetupFile     string
	Distributions []string
	SkipBuild     bool
}

func (p Plugin) buildCommand() *exec.Cmd {
	// Set the default of distributions in here
	// as CLI package still has issues with string slice defaults
	distributions := []string{"sdist"}
	if len(p.Distributions) > 0 {
		distributions = p.Distributions
	}
	args := []string{p.SetupFile}
	for i := range distributions {
		args = append(args, distributions[i])
	}
	return exec.Command("python3", args...)
}

func (p Plugin) uploadCommand() *exec.Cmd {
	args := []string{}
	args = append(args, "upload")
	args = append(args, "--repository-url")
	args = append(args, p.Repository)
	args = append(args, "--username")
	args = append(args, p.Username)
	args = append(args, "--password")
	args = append(args, p.Password)
	args = append(args, filepath.Join(filepath.Dir(p.SetupFile), "dist/*"))

	return exec.Command("twine", args...)
}

// Exec runs the plugin - doing the necessary setup.py modifications
func (p Plugin) Exec() error {
	if !p.SkipBuild {
		out, err := p.buildCommand().CombinedOutput()
		if err != nil {
			return errors.Wrap(err, string(out))
		}
		log.Printf("Output: %s", out)
	}

	out, err := p.uploadCommand().CombinedOutput()
	if err != nil {
		return errors.Wrap(err, string(out))
	}
	log.Printf("Output: %s", out)

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/drone/drone-template-lib/template"
	"github.com/nlopes/slack"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type (
	// MessageOptions contains the slack message.
	MessageOptions struct {
		Icon             string
		Username         string
		Template         string
		ImageAttachments []string
	}

	// Repo information.
	Repo struct {
		FullName string
		Owner    string
		Name     string
		Link     string
	}

	// Build information.
	Build struct {
		Commit    string
		Branch    string
		Ref       string
		Link      string
		Message   string
		Author    string
		Email     string
		Number    int
		Status    string
		Event     string
		Deploy    string
		BuildLink string
	}

	// Config for the plugin.
	Config struct {
		Token   string
		Channel string
		Mapping string
		Success MessageOptions
		Failure MessageOptions
	}

	// Plugin values.
	Plugin struct {
		Repo      Repo
		Build     Build
		BuildLast Build
		Config    Config
		User      *slack.User
	}

	// searchFunc determines how to search for a slack user.
	searchFunc func(*slack.User, string) bool
)

// Exec executes the plugin.
func (p Plugin) Exec() error {
	// create the API
	api := slack.New(p.Config.Token)

	// verify the connection
	authResponse, err := api.AuthTest()

	if err != nil {
		return errors.Wrap(err, "failed to test auth")
	}

	logrus.WithFields(logrus.Fields{
		"team": authResponse.Team,
		"user": authResponse.User,
	}).Info("Successfully authenticated with Slack API")

	// get the user
	p.User, _ = p.findSlackUser(api)

	// get the associated @ string
	messageParams := p.createMessage()
	var userAt string

	if p.User != nil {
		userAt = fmt.Sprintf("@%s", p.User.Name)

		_, _, err := api.PostMessage(userAt, "", messageParams)

		if err == nil {
			logrus.WithFields(logrus.Fields{
				"username": p.User.Name,
			}).Info("Notified user")
		} else {
			logrus.WithFields(logrus.Fields{
				"username": p.User.Name,
			}).Error("Could not notify user")
		}
	} else {
		userAt = p.Build.Author
		logrus.WithFields(logrus.Fields{
			"author": userAt,
		}).Error("Could not find author")
	}

	if p.Config.Channel != "" {
		if !strings.HasPrefix(p.Config.Channel, "#") {
			p.Config.Channel = "#" + p.Config.Channel
		}
		_, _, err := api.PostMessage(p.Config.Channel, "", messageParams)

		if err == nil {
			logrus.WithFields(logrus.Fields{
				"channel": p.Config.Channel,
			}).Info("Channel notified")
		} else {
			logrus.WithFields(logrus.Fields{
				"channel": p.Config.Channel,
			}).Error("Unable to notify channel")
		}
	}

	return nil
}

// createMessage generates the message to post to Slack.
func (p Plugin) createMessage() slack.PostMessageParameters {
	var messageOptions MessageOptions
	var color string
	var messageTitle string

	// Determine if the build was a success
	if p.Build.Status == "success" {
		messageOptions = p.Config.Success
		color = "good"
		messageTitle = "Build succeeded"
	} else {
		messageOptions = p.Config.Failure
		color = "danger"
		messageTitle = "Build failed"
	}

	// setup the message
	messageParams := slack.PostMessageParameters{
		Username: messageOptions.Username,
	}

	if strings.HasPrefix(messageOptions.Icon, "http") {
		logrus.Info("Icon is a URL")
		messageParams.IconURL = messageOptions.Icon
	} else {
		logrus.Info("Icon is an emoji")
		messageParams.IconEmoji = messageOptions.Icon
	}

	messageText, err := template.Render(messageOptions.Template, &p)

	if err != nil {
		logrus.Error("Could not parse template")
	}

	// create the attachment
	attachment := slack.Attachment{
		Color:     color,
		Text:      messageText,
		Title:     messageTitle,
		TitleLink: p.Build.Link,
	}

	// Add image if any are provided
	imageCount := len(messageOptions.ImageAttachments)

	if imageCount > 0 {
		logrus.WithFields(logrus.Fields{
			"count": imageCount,
		}).Info("Choosing from images")
		rand.Seed(time.Now().UTC().UnixNano())
		attachment.ImageURL = messageOptions.ImageAttachments[rand.Intn(imageCount)]
	}

	messageParams.Attachments = []slack.Attachment{attachment}

	return messageParams
}

// findSlackUser uses the slack API to find the user who made the commit that
// is being built.
func (p Plugin) findSlackUser(api *slack.Client) (*slack.User, error) {
	// get the mapping
	mapping := userMapping(p.Config.Mapping)

	// determine the search function to use
	var search searchFunc
	var find string

	if val, ok := mapping[p.Build.Email]; ok {
		logrus.WithFields(logrus.Fields{
			"username": val,
		}).Info("Searching for user by name, using build.email as key")
		search = checkUsername
		find = val
	} else if val, ok := mapping[p.Build.Author]; ok {
		logrus.WithFields(logrus.Fields{
			"username": val,
		}).Info("Searching for user by name, using build.author as key")
		search = checkUsername
		find = val
	} else {
		logrus.WithFields(logrus.Fields{
			"email": p.Build.Email,
		}).Info("Searching for user by email")
		search = checkEmail
		find = p.Build.Email
	}

	if len(find) == 0 {
		return nil, errors.New("No user to search for")
	}

	// search for the user
	users, err := api.GetUsers()

	if err != nil {
		return nil, errors.Wrap(err, "failed to query users")
	}

	var blameUser *slack.User

	for _, user := range users {
		if search(&user, find) {
			logrus.WithFields(logrus.Fields{
				"username": user.Name,
				"email":    user.Profile.Email,
			}).Info("Found user")

			blameUser = &user
			break
		} else {
			logrus.WithFields(logrus.Fields{
				"username": user.Name,
				"email":    user.Profile.Email,
			}).Debug("User")
		}
	}

	return blameUser, nil
}

// userMapping gets the user mapping file.
func userMapping(value string) map[string]string {
	mapping := []byte(contents(value))

	// turn into a map
	values := map[string]string{}
	err := json.Unmarshal(mapping, &values)

	if err != nil {
		if len(mapping) != 0 {
			logrus.WithFields(logrus.Fields{
				"mapping": value,
				"error":   err,
			}).Error("Could not parse mapping")
		}

		values = make(map[string]string)
	}

	return values
}

// contents gets the value referenced either in a local filem, a URL or the
// string value itself.
func contents(s string) string {
	if _, err := os.Stat(s); err == nil {
		o, _ := ioutil.ReadFile(s)
		return string(o)
	}
	if _, err := url.Parse(s); err == nil {
		resp, err := http.Get(s)
		if err != nil {
			return s
		}
		defer resp.Body.Close()
		o, _ := ioutil.ReadAll(resp.Body)
		return string(o)
	}
	return s
}

// checkEmail sees if the email is used by the user.
func checkEmail(user *slack.User, email string) bool {
	return user.Profile.Email == email
}

// checkUsername sees if the username is the same as the user.
func checkUsername(user *slack.User, name string) bool {
	return user.Name == name
}
<commit_msg>Comparing email should be case insensitive (#34)<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/drone/drone-template-lib/template"
	"github.com/nlopes/slack"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type (
	// MessageOptions contains the slack message.
	MessageOptions struct {
		Icon             string
		Username         string
		Template         string
		ImageAttachments []string
	}

	// Repo information.
	Repo struct {
		FullName string
		Owner    string
		Name     string
		Link     string
	}

	// Build information.
	Build struct {
		Commit    string
		Branch    string
		Ref       string
		Link      string
		Message   string
		Author    string
		Email     string
		Number    int
		Status    string
		Event     string
		Deploy    string
		BuildLink string
	}

	// Config for the plugin.
	Config struct {
		Token   string
		Channel string
		Mapping string
		Success MessageOptions
		Failure MessageOptions
	}

	// Plugin values.
	Plugin struct {
		Repo      Repo
		Build     Build
		BuildLast Build
		Config    Config
		User      *slack.User
	}

	// searchFunc determines how to search for a slack user.
	searchFunc func(*slack.User, string) bool
)

// Exec executes the plugin.
func (p Plugin) Exec() error {
	// create the API
	api := slack.New(p.Config.Token)

	// verify the connection
	authResponse, err := api.AuthTest()

	if err != nil {
		return errors.Wrap(err, "failed to test auth")
	}

	logrus.WithFields(logrus.Fields{
		"team": authResponse.Team,
		"user": authResponse.User,
	}).Info("Successfully authenticated with Slack API")

	// get the user
	p.User, _ = p.findSlackUser(api)

	// get the associated @ string
	messageParams := p.createMessage()
	var userAt string

	if p.User != nil {
		userAt = fmt.Sprintf("@%s", p.User.Name)

		_, _, err := api.PostMessage(userAt, "", messageParams)

		if err == nil {
			logrus.WithFields(logrus.Fields{
				"username": p.User.Name,
			}).Info("Notified user")
		} else {
			logrus.WithFields(logrus.Fields{
				"username": p.User.Name,
			}).Error("Could not notify user")
		}
	} else {
		userAt = p.Build.Author
		logrus.WithFields(logrus.Fields{
			"author": userAt,
		}).Error("Could not find author")
	}

	if p.Config.Channel != "" {
		if !strings.HasPrefix(p.Config.Channel, "#") {
			p.Config.Channel = "#" + p.Config.Channel
		}
		_, _, err := api.PostMessage(p.Config.Channel, "", messageParams)

		if err == nil {
			logrus.WithFields(logrus.Fields{
				"channel": p.Config.Channel,
			}).Info("Channel notified")
		} else {
			logrus.WithFields(logrus.Fields{
				"channel": p.Config.Channel,
			}).Error("Unable to notify channel")
		}
	}

	return nil
}

// createMessage generates the message to post to Slack.
func (p Plugin) createMessage() slack.PostMessageParameters {
	var messageOptions MessageOptions
	var color string
	var messageTitle string

	// Determine if the build was a success
	if p.Build.Status == "success" {
		messageOptions = p.Config.Success
		color = "good"
		messageTitle = "Build succeeded"
	} else {
		messageOptions = p.Config.Failure
		color = "danger"
		messageTitle = "Build failed"
	}

	// setup the message
	messageParams := slack.PostMessageParameters{
		Username: messageOptions.Username,
	}

	if strings.HasPrefix(messageOptions.Icon, "http") {
		logrus.Info("Icon is a URL")
		messageParams.IconURL = messageOptions.Icon
	} else {
		logrus.Info("Icon is an emoji")
		messageParams.IconEmoji = messageOptions.Icon
	}

	messageText, err := template.Render(messageOptions.Template, &p)

	if err != nil {
		logrus.Error("Could not parse template")
	}

	// create the attachment
	attachment := slack.Attachment{
		Color:     color,
		Text:      messageText,
		Title:     messageTitle,
		TitleLink: p.Build.Link,
	}

	// Add image if any are provided
	imageCount := len(messageOptions.ImageAttachments)

	if imageCount > 0 {
		logrus.WithFields(logrus.Fields{
			"count": imageCount,
		}).Info("Choosing from images")
		rand.Seed(time.Now().UTC().UnixNano())
		attachment.ImageURL = messageOptions.ImageAttachments[rand.Intn(imageCount)]
	}

	messageParams.Attachments = []slack.Attachment{attachment}

	return messageParams
}

// findSlackUser uses the slack API to find the user who made the commit that
// is being built.
func (p Plugin) findSlackUser(api *slack.Client) (*slack.User, error) {
	// get the mapping
	mapping := userMapping(p.Config.Mapping)

	// determine the search function to use
	var search searchFunc
	var find string

	if val, ok := mapping[p.Build.Email]; ok {
		logrus.WithFields(logrus.Fields{
			"username": val,
		}).Info("Searching for user by name, using build.email as key")
		search = checkUsername
		find = val
	} else if val, ok := mapping[p.Build.Author]; ok {
		logrus.WithFields(logrus.Fields{
			"username": val,
		}).Info("Searching for user by name, using build.author as key")
		search = checkUsername
		find = val
	} else {
		logrus.WithFields(logrus.Fields{
			"email": p.Build.Email,
		}).Info("Searching for user by email")
		search = checkEmail
		find = p.Build.Email
	}

	if len(find) == 0 {
		return nil, errors.New("No user to search for")
	}

	// search for the user
	users, err := api.GetUsers()

	if err != nil {
		return nil, errors.Wrap(err, "failed to query users")
	}

	var blameUser *slack.User

	for _, user := range users {
		if search(&user, find) {
			logrus.WithFields(logrus.Fields{
				"username": user.Name,
				"email":    user.Profile.Email,
			}).Info("Found user")

			blameUser = &user
			break
		} else {
			logrus.WithFields(logrus.Fields{
				"username": user.Name,
				"email":    user.Profile.Email,
			}).Debug("User")
		}
	}

	return blameUser, nil
}

// userMapping gets the user mapping file.
func userMapping(value string) map[string]string {
	mapping := []byte(contents(value))

	// turn into a map
	values := map[string]string{}
	err := json.Unmarshal(mapping, &values)

	if err != nil {
		if len(mapping) != 0 {
			logrus.WithFields(logrus.Fields{
				"mapping": value,
				"error":   err,
			}).Error("Could not parse mapping")
		}

		values = make(map[string]string)
	}

	return values
}

// contents gets the value referenced either in a local filem, a URL or the
// string value itself.
func contents(s string) string {
	if _, err := os.Stat(s); err == nil {
		o, _ := ioutil.ReadFile(s)
		return string(o)
	}
	if _, err := url.Parse(s); err == nil {
		resp, err := http.Get(s)
		if err != nil {
			return s
		}
		defer resp.Body.Close()
		o, _ := ioutil.ReadAll(resp.Body)
		return string(o)
	}
	return s
}

// checkEmail sees if the email is used by the user.
func checkEmail(user *slack.User, email string) bool {
	return strings.EqualFold(user.Profile.Email, email)
}

// checkUsername sees if the username is the same as the user.
func checkUsername(user *slack.User, name string) bool {
	return user.Name == name
}
<|endoftext|>


<commit_before>//package Policy provides RBAC policy enforcement similar to the OpenStack oslo.policy library.
package policy

import (
	"fmt"
	"log"
)

//go:generate go tool yacc -v "" -o parser.go parser.y
//go:generate sed -i -e "s/yyEofCode/yyEOFCode/" parser.go
//go:generate sed -i -e 1d parser.go

type rule func(c Context) bool

//Check is the interface for checks
type Check func(c Context, key, match string) bool

//Enforcer is responsible for loading and enforcing rules.
type Enforcer struct {
	rules  map[string]rule
	checks map[string]Check
}

//Enforce checks authorization of a rule for the given Context
func (p *Enforcer) Enforce(rule string, c Context) bool {
	c.rules = &p.rules
	c.checks = p.checks
	r, ok := p.rules[rule]
	return ok && r(c)
}

//AddCheck registers a custom check for the given name.
//A custom check can by used by specifing the name as the left side of the check.
//E.g. mycheck:valueformycheck
func (p *Enforcer) AddCheck(name string, c Check) {
	p.checks[name] = c
}

//NewEnforcer parses the provided rule set and returns a policy enforcer
//By default the Enforcer registers the following checks
// "rule": RuleCheck
// "role": RoleCheck
// "http": HttpCheck
// "default": DefaultCheck
func NewEnforcer(rules map[string]string) (*Enforcer, error) {
	p := Enforcer{
		rules:  make(map[string]rule, len(rules)),
		checks: make(map[string]Check, 4),
	}
	p.AddCheck("rule", RuleCheck)
	p.AddCheck("role", RoleCheck)
	p.AddCheck("http", HTTPCheck)
	p.AddCheck("default", DefaultCheck)

	for name, str := range rules {
		lexer := newLexer(str)
		if yyParse(lexer) != 0 {
			return nil, fmt.Errorf("Failed to parse rule %s: %s", name, lexer.parseResult.(string))
		}
		p.rules[name] = lexer.parseResult.(rule)
	}
	return &p, nil
}

//Context encapsulates the external data required for enforcing a rules. Populating a Context object is left to the application using the policy engine.
type Context struct {
	//Authentication context information from the keystone token, e.g. user_id, user_domain_id...
	Auth map[string]string
	//Roles assigned to the user for the current scope
	Roles []string
	//Request variables that are referenced in policy rules
	Request map[string]string

	rules  *map[string]rule
	checks map[string]Check
	debug  bool
}

//RuleCheck provides the standard rule:... check
func RuleCheck(c Context, key, match string) bool {
	rule, ok := (*c.rules)[match]
	if !ok {
		return false
	}
	return rule(c)
}

//RoleCheck provides the standard role:... check.
func RoleCheck(c Context, key, match string) bool {
	for _, r := range c.Roles {
		if r == match {
			return true
		}
	}
	return false
}

//HTTPCheck implements the http:... check
func HTTPCheck(c Context, key, match string) bool {
	return false // not implemented yet
}

//DefaultCheck is used whenever there is no specific check registered for the left hand side.
//It simply tries to match the right side if the check to the authentication credential given by
//the left side. E.g. user_id:%(target.user_id)
func DefaultCheck(c Context, key, match string) bool {
	cred, ok := c.Auth[key]
	if !ok {
		return false
	}
	return cred == match
}

func (c Context) genericCheck(key, match string, isVariable bool) bool {
	if c.debug {
		log.Printf("executing %s:%s", key, match)
	}
	if isVariable {
		m, ok := c.Request[match]
		if !ok {
			if c.debug {
				log.Printf("request variable %s not present in context. failing\n", match)
			}
			return false
		}
		match = m
	}

	if check, ok := c.checks[key]; ok {
		result := check(c, key, match)
		if c.debug {
			log.Printf("check %s returned: %v\n", key, result)
		}
		return result
	}
	result := c.checks["default"](c, key, match)
	if c.debug {
		log.Printf("default check result: %s:%s = %v\n", key, match, result)
	}
	return result

}

func (c Context) checkVariable(variable string, match interface{}) bool {
	if c.debug {
		log.Printf("executing '%s':%s\n", match, variable)
	}
	val, ok := c.Request[variable]
	if !ok {
		if c.debug {
			log.Printf("variable %s not present in context. failing\n", variable)
		}
		return false
	}
	if c.debug {
		log.Printf("'%s':%s = %v\n", match, val, val == match)
	}
	return val == match
}
<commit_msg>golint fix<commit_after>//Package policy provides RBAC policy enforcement similar to the OpenStack oslo.policy library.
package policy

import (
	"fmt"
	"log"
)

//go:generate go tool yacc -v "" -o parser.go parser.y
//go:generate sed -i -e "s/yyEofCode/yyEOFCode/" parser.go
//go:generate sed -i -e 1d parser.go

type rule func(c Context) bool

//Check is the interface for checks
type Check func(c Context, key, match string) bool

//Enforcer is responsible for loading and enforcing rules.
type Enforcer struct {
	rules  map[string]rule
	checks map[string]Check
}

//Enforce checks authorization of a rule for the given Context
func (p *Enforcer) Enforce(rule string, c Context) bool {
	c.rules = &p.rules
	c.checks = p.checks
	r, ok := p.rules[rule]
	return ok && r(c)
}

//AddCheck registers a custom check for the given name.
//A custom check can by used by specifing the name as the left side of the check.
//E.g. mycheck:valueformycheck
func (p *Enforcer) AddCheck(name string, c Check) {
	p.checks[name] = c
}

//NewEnforcer parses the provided rule set and returns a policy enforcer
//By default the Enforcer registers the following checks
// "rule": RuleCheck
// "role": RoleCheck
// "http": HttpCheck
// "default": DefaultCheck
func NewEnforcer(rules map[string]string) (*Enforcer, error) {
	p := Enforcer{
		rules:  make(map[string]rule, len(rules)),
		checks: make(map[string]Check, 4),
	}
	p.AddCheck("rule", RuleCheck)
	p.AddCheck("role", RoleCheck)
	p.AddCheck("http", HTTPCheck)
	p.AddCheck("default", DefaultCheck)

	for name, str := range rules {
		lexer := newLexer(str)
		if yyParse(lexer) != 0 {
			return nil, fmt.Errorf("Failed to parse rule %s: %s", name, lexer.parseResult.(string))
		}
		p.rules[name] = lexer.parseResult.(rule)
	}
	return &p, nil
}

//Context encapsulates the external data required for enforcing a rules. Populating a Context object is left to the application using the policy engine.
type Context struct {
	//Authentication context information from the keystone token, e.g. user_id, user_domain_id...
	Auth map[string]string
	//Roles assigned to the user for the current scope
	Roles []string
	//Request variables that are referenced in policy rules
	Request map[string]string

	rules  *map[string]rule
	checks map[string]Check
	debug  bool
}

//RuleCheck provides the standard rule:... check
func RuleCheck(c Context, key, match string) bool {
	rule, ok := (*c.rules)[match]
	if !ok {
		return false
	}
	return rule(c)
}

//RoleCheck provides the standard role:... check.
func RoleCheck(c Context, key, match string) bool {
	for _, r := range c.Roles {
		if r == match {
			return true
		}
	}
	return false
}

//HTTPCheck implements the http:... check
func HTTPCheck(c Context, key, match string) bool {
	return false // not implemented yet
}

//DefaultCheck is used whenever there is no specific check registered for the left hand side.
//It simply tries to match the right side if the check to the authentication credential given by
//the left side. E.g. user_id:%(target.user_id)
func DefaultCheck(c Context, key, match string) bool {
	cred, ok := c.Auth[key]
	if !ok {
		return false
	}
	return cred == match
}

func (c Context) genericCheck(key, match string, isVariable bool) bool {
	if c.debug {
		log.Printf("executing %s:%s", key, match)
	}
	if isVariable {
		m, ok := c.Request[match]
		if !ok {
			if c.debug {
				log.Printf("request variable %s not present in context. failing\n", match)
			}
			return false
		}
		match = m
	}

	if check, ok := c.checks[key]; ok {
		result := check(c, key, match)
		if c.debug {
			log.Printf("check %s returned: %v\n", key, result)
		}
		return result
	}
	result := c.checks["default"](c, key, match)
	if c.debug {
		log.Printf("default check result: %s:%s = %v\n", key, match, result)
	}
	return result

}

func (c Context) checkVariable(variable string, match interface{}) bool {
	if c.debug {
		log.Printf("executing '%s':%s\n", match, variable)
	}
	val, ok := c.Request[variable]
	if !ok {
		if c.debug {
			log.Printf("variable %s not present in context. failing\n", variable)
		}
		return false
	}
	if c.debug {
		log.Printf("'%s':%s = %v\n", match, val, val == match)
	}
	return val == match
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"time"
)

func TimeoutDial(timeout time.Duration) func(netw, addr string) (net.Conn, error) {
	return func(netw, addr string) (net.Conn, error) {
		c, err := net.DialTimeout(netw, addr, timeout)
		if err != nil {
			return nil, err
		}

		return c, nil
	}
}

func main() {
	if len(os.Args) < 2 {
		log.Fatalf("Please provide, as a argument to this software, the path to the valid json configuration file")
	}
	config := &Configuration{}
	buffer, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	config.Load(buffer)

	pollChannel := make(chan Check)

	go func() {
		client := &http.Client{Transport: &http.Transport{Dial: TimeoutDial(config.Timeout)}}
		for {
			check := <-pollChannel
			// This go routine will exist for each check
			go func() {
				for {
					time.Sleep(check.Interval)
					statusCode, duration, err := check.Poll(client)
					for _, v := range config.Backends {
						if err != nil {
							v.LogTimeout(&check)
						} else if statusCode >= 200 && statusCode < 300 {
							v.LogSuccess(&check, statusCode, duration)
						} else {
							v.LogError(&check, statusCode, duration)
						}
					}
				}
			}()
		}
	}()

	for _, v := range config.Checks {
		pollChannel <- v
	}

	if config.Url != "" {
		http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {})
		err = http.ListenAndServe(config.Url, nil)
		if err != nil {
			log.Fatalln("Unable to start http server", err)
		}
	}

	select {}
}
<commit_msg>Got rid of the pollChannel chan. Thanks kisielk on #go-nuts<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"time"
)

func TimeoutDial(timeout time.Duration) func(netw, addr string) (net.Conn, error) {
	return func(netw, addr string) (net.Conn, error) {
		c, err := net.DialTimeout(netw, addr, timeout)
		if err != nil {
			return nil, err
		}

		return c, nil
	}
}

func main() {
	if len(os.Args) < 2 {
		log.Fatalf("Please provide, as a argument to this software, the path to the valid json configuration file")
	}
	config := &Configuration{}
	buffer, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	config.Load(buffer)

	client := &http.Client{Transport: &http.Transport{Dial: TimeoutDial(config.Timeout)}}
	for _, v := range config.Checks {
		go func(check Check) {
			for {
				time.Sleep(check.Interval)
				statusCode, duration, err := check.Poll(client)
				for _, v := range config.Backends {
					if err != nil {
						v.LogTimeout(&check)
					} else if statusCode >= 200 && statusCode < 300 {
						v.LogSuccess(&check, statusCode, duration)
					} else {
						v.LogError(&check, statusCode, duration)
					}
				}
			}
		}(v)
	}

	if config.Url != "" {
		http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {})
		err = http.ListenAndServe(config.Url, nil)
		if err != nil {
			log.Fatalln("Unable to start http server", err)
		}
	}

	select {}
}
<|endoftext|>


<commit_before>package telebot

import (
	"time"

	"github.com/pkg/errors"
)

// Poller is a provider of Updates.
//
// All pollers must implement Poll(), which accepts bot
// pointer and subscription channel and start polling
// synchronously straight away.
type Poller interface {
	// Poll is supposed to take the bot object
	// subscription channel and start polling
	// for Updates immediately.
	Poll(b *Bot, dest chan Update)
}

// LongPoller is a classic LongPoller with timeout.
type LongPoller struct {
	Timeout time.Duration
}

// Poll does long polling.
func (p *LongPoller) Poll(b *Bot, dest chan Update) {
	var latestUpd int

	for {
		updates, err := b.getUpdates(latestUpd+1, p.Timeout)

		if err != nil {
			b.debug(errors.Wrap(err, "getUpdates() failed"))
			continue
		}

		for _, update := range updates {
			latestUpd = update.ID
			dest <- update
		}
	}
}
<commit_msg>Middlware introduced, resolves #100.<commit_after>package telebot

import (
	"time"

	"github.com/pkg/errors"
)

// Poller is a provider of Updates.
//
// All pollers must implement Poll(), which accepts bot
// pointer and subscription channel and start polling
// synchronously straight away.
type Poller interface {
	// Poll is supposed to take the bot object
	// subscription channel and start polling
	// for Updates immediately.
	Poll(b *Bot, dest chan Update)
}

// MiddlewarePoller is a special kind of poller that acts
// like a filter for updates. It could be used for spam
// handling, banning or whatever.
//
// For heavy middleware, use increased capacity.
//
type MiddlewarePoller struct {
	Poller Poller
	filter func(*Update) bool

	Capacity int // Default: 1
}

// Middleware constructs a middleware poller.
func Middleware(p Poller, filter func(*Update) bool) *MiddlewarePoller {
	return &MiddlewarePoller{
		Poller: p,
		filter: filter,
	}
}

// Poll sieves updates through middleware filter.
func (p *MiddlewarePoller) Poll(b *Bot, dest chan Update) {
	cap := 1
	if p.Capacity > 1 {
		cap = p.Capacity
	}

	middle := make(chan Update, cap)

	go p.Poller.Poll(b, middle)

	for upd := range middle {
		if p.filter(&upd) {
			dest <- upd
		}
	}
}

// LongPoller is a classic LongPoller with timeout.
type LongPoller struct {
	Timeout time.Duration
}

// Poll does long polling.
func (p *LongPoller) Poll(b *Bot, dest chan Update) {
	var latestUpd int

	for {
		updates, err := b.getUpdates(latestUpd+1, p.Timeout)

		if err != nil {
			b.debug(errors.Wrap(err, "getUpdates() failed"))
			continue
		}

		for _, update := range updates {
			latestUpd = update.ID
			dest <- update
		}
	}
}
<|endoftext|>