<commit_before>package main

import (
	"crypto/rsa"
	"crypto/x509"
	"database/sql"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/auth0/go-jwt-middleware"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/mux"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"github.com/meatballhat/negroni-logrus"
	"github.com/patrickmn/go-cache"
	"github.com/pquerna/cachecontrol"
	"github.com/rs/cors"
	"github.com/urfave/negroni"
	"net/http"
	"os"
	"sort"
	"strconv"
	"time"
)

var myClient = &http.Client{Timeout: 10 * time.Second}
var myCache = cache.New(5*time.Hour, 10*time.Minute)

func getKey(kid string) (*rsa.PublicKey, error) {
	pemData, found := myCache.Get(kid)
	if found {
		log.WithFields(log.Fields{"id": kid}).Info("Public key found in cache")
	} else {
		log.WithFields(log.Fields{"id": kid}).Info("No public key found in cache")

		// Get the new public keys (pem data) from google
		req, _ := http.NewRequest("GET", "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com", nil)
		res, err := http.DefaultClient.Do(req)
		if err != nil {
			return nil, err
		}

		// The response contains multiple PEMs
		decoder := json.NewDecoder(res.Body)
		personMap := make(map[string]interface{})
		err = decoder.Decode(&personMap)
		if err != nil {
			return nil, err
		}

		// Try to cache the values for next requests
		reasons, expires, _ := cachecontrol.CachableResponse(req, res, cachecontrol.Options{})
		if len(reasons) == 0 {
			timeUntilExpiration := time.Until(expires)
			log.WithFields(log.Fields{"timeUntilExpiry": timeUntilExpiration}).Info("Caching publice keys")

			// Save all the identities
			for id, publicKeyData := range personMap {
				myCache.Set(id, publicKeyData, timeUntilExpiration)
			}
		} else {
			log.Println("Unable to cache public key:", reasons)
		}

		pemData = personMap[kid]
	}

	block, _ := pem.Decode([]byte(pemData.(string)))
	var cert *x509.Certificate
	cert, _ = x509.ParseCertificate(block.Bytes)
	rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
	return rsaPublicKey, nil
}

func parseMeasurements(r *http.Request) ([]Measurement, error) {
	decoder := json.NewDecoder(r.Body)
	var measurements []Measurement
	err := decoder.Decode(&measurements)
	if err != nil {
		return measurements, err
	}
	defer r.Body.Close()
	return measurements, nil
}

func mapMeasurements(measurements []Measurement) []PlotData {
	dates := make(map[time.Time]PlotData)
	for _, measurement := range measurements {
		_, ok := dates[measurement.Timestamp.Time]
		if !ok {
			values := make(map[string]float64)
			plot := PlotData{Date: measurement.Timestamp.Time, Values: values}
			dates[measurement.Timestamp.Time] = plot
		}
		plot, ok := dates[measurement.Timestamp.Time]
		plot.Values[measurement.Key] = measurement.Value
	}

	var plots = []PlotData{}
	for _, plot := range dates {
		plots = append(plots, plot)
	}

	sort.Slice(plots, func(i, j int) bool {
		return plots[i].Date.Sub(plots[j].Date) < 0
	})
	return plots
}

func getUser(r *http.Request) (string, error) {
	user, ok := r.Context().Value("user").(string)
	if !ok {
		return "", errors.New("user not found in context")
	}

	return user, nil
}

type Env struct {
	db *Database
}

func (env *Env) addMeasurements(w http.ResponseWriter, r *http.Request) {
	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	measurements, err := parseMeasurements(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	err = env.db.saveMeasurements(measurements, user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func (env *Env) getAllData(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readDataFromPlot(user, plotId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots := mapMeasurements(measurements)

	jsonData, err := json.Marshal(plots)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getHourlyData(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readHourlyDataFromPlot(user, plotId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots := mapMeasurements(measurements)
	jsonData, err := json.Marshal(plots)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getLatestData(w http.ResponseWriter, r *http.Request) {
	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readLatestDataFromPlot(user, plotId)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Color not found", http.StatusNotFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	plots := mapMeasurements(measurements)

	if len(plots) == 0 {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}

	jsonData, err := json.Marshal(plots[0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getPlots(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots, err := env.db.getPlots(user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonData, err := json.Marshal(plots)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getPlot(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	plot, err := env.db.getPlot(plotId, user)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Plot not found", http.StatusNotFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	instruments, err := env.db.getInstruments(plotId)
	plot.Instruments = instruments

	jsonData, err := json.Marshal(plot)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func parsePlot(r *http.Request) (Plot, error) {

	decoder := json.NewDecoder(r.Body)
	var plot Plot
	err := decoder.Decode(&plot)
	if err != nil {
		return Plot{}, err
	}
	defer r.Body.Close()
	return plot, nil
}

func (env *Env) addPlot(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plot, err := parsePlot(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	updated_plot, err := env.db.savePlot(plot, user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonData, _ := json.Marshal(updated_plot)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	w.Write(jsonData)

}

func (env *Env) getKey(w http.ResponseWriter, r *http.Request) {
	userId, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	key, err := env.db.getkeyForUser(userId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	user := User{Key: key}
	jsonData, _ := json.Marshal(user)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(jsonData)
}

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Pitilt :)\n")
}

func main() {

	var err error

	//setup database
	var dbUri = os.Getenv("DATABASE_URI")
	if dbUri == "" {
		dbUri = "postgres://tilt:password@localhost:15432/tilt"
	}

	db, err := sqlx.Open("postgres", dbUri)
	if err != nil {
		log.Fatalln(err)
	}
	database := &Database{db: db}
	env := &Env{db: database}

	//create middleware for authing on google jwt from firebase
	jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			key, err := getKey(token.Header["kid"].(string))
			return key, err
		},
		SigningMethod: jwt.SigningMethodRS256,
	})

	jwtCheckHandler := &JwtCheckHandler{db: database, jwtMiddleware: jwtMiddleware}
	keyCheckHandler := &KeyCheckHandler{db: database}

	//define routes
	router := mux.NewRouter()
	router.HandleFunc("/", hello).Methods("GET")

	measurementRouter := mux.NewRouter()
	measurementRouter.HandleFunc("/measurements/", env.addMeasurements).Methods("POST")
	router.PathPrefix("/measurements").Handler(negroni.New(
		keyCheckHandler,
		negroni.Wrap(measurementRouter),
	))

	plotsRouter := mux.NewRouter()
	plotsRouter.HandleFunc("/plots/{plotId}/data/all/", env.getAllData).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}/data/latest/", env.getLatestData).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}/data/hourly/", env.getHourlyData).Methods("GET")

	plotsRouter.HandleFunc("/plots/", env.getPlots).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}", env.getPlot).Methods("GET")
	plotsRouter.HandleFunc("/plots/", env.addPlot).Methods("POST")

	router.PathPrefix("/plots").Handler(negroni.New(
		jwtCheckHandler,
		negroni.Wrap(plotsRouter),
	))

	userRouter := mux.NewRouter()
	userRouter.HandleFunc("/user/key/", env.getKey).Methods("GET")

	router.PathPrefix("/user").Handler(negroni.New(
		jwtCheckHandler,
		negroni.Wrap(userRouter),
	))

	// Setup CORS-handling
	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedHeaders: []string{"Content-Type", "Authorization"},
		AllowedMethods: []string{"GET", "HEAD", "POST", "PUT", "OPTIONS"},
	})

	n := negroni.New()
	n.Use(negronilogrus.NewMiddleware())
	n.Use(c)
	n.UseHandler(router)

	http.ListenAndServe(":8080", n)
}
<commit_msg>Make sure plot start time is before end time.<commit_after>package main

import (
	"crypto/rsa"
	"crypto/x509"
	"database/sql"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/auth0/go-jwt-middleware"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/mux"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"github.com/meatballhat/negroni-logrus"
	"github.com/patrickmn/go-cache"
	"github.com/pquerna/cachecontrol"
	"github.com/rs/cors"
	"github.com/urfave/negroni"
	"net/http"
	"os"
	"sort"
	"strconv"
	"time"
)

var myClient = &http.Client{Timeout: 10 * time.Second}
var myCache = cache.New(5*time.Hour, 10*time.Minute)

func getKey(kid string) (*rsa.PublicKey, error) {
	pemData, found := myCache.Get(kid)
	if found {
		log.WithFields(log.Fields{"id": kid}).Info("Public key found in cache")
	} else {
		log.WithFields(log.Fields{"id": kid}).Info("No public key found in cache")

		// Get the new public keys (pem data) from google
		req, _ := http.NewRequest("GET", "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com", nil)
		res, err := http.DefaultClient.Do(req)
		if err != nil {
			return nil, err
		}

		// The response contains multiple PEMs
		decoder := json.NewDecoder(res.Body)
		personMap := make(map[string]interface{})
		err = decoder.Decode(&personMap)
		if err != nil {
			return nil, err
		}

		// Try to cache the values for next requests
		reasons, expires, _ := cachecontrol.CachableResponse(req, res, cachecontrol.Options{})
		if len(reasons) == 0 {
			timeUntilExpiration := time.Until(expires)
			log.WithFields(log.Fields{"timeUntilExpiry": timeUntilExpiration}).Info("Caching publice keys")

			// Save all the identities
			for id, publicKeyData := range personMap {
				myCache.Set(id, publicKeyData, timeUntilExpiration)
			}
		} else {
			log.Println("Unable to cache public key:", reasons)
		}

		pemData = personMap[kid]
	}

	block, _ := pem.Decode([]byte(pemData.(string)))
	var cert *x509.Certificate
	cert, _ = x509.ParseCertificate(block.Bytes)
	rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
	return rsaPublicKey, nil
}

func parseMeasurements(r *http.Request) ([]Measurement, error) {
	decoder := json.NewDecoder(r.Body)
	var measurements []Measurement
	err := decoder.Decode(&measurements)
	if err != nil {
		return measurements, err
	}
	defer r.Body.Close()
	return measurements, nil
}

func mapMeasurements(measurements []Measurement) []PlotData {
	dates := make(map[time.Time]PlotData)
	for _, measurement := range measurements {
		_, ok := dates[measurement.Timestamp.Time]
		if !ok {
			values := make(map[string]float64)
			plot := PlotData{Date: measurement.Timestamp.Time, Values: values}
			dates[measurement.Timestamp.Time] = plot
		}
		plot, ok := dates[measurement.Timestamp.Time]
		plot.Values[measurement.Key] = measurement.Value
	}

	var plots = []PlotData{}
	for _, plot := range dates {
		plots = append(plots, plot)
	}

	sort.Slice(plots, func(i, j int) bool {
		return plots[i].Date.Sub(plots[j].Date) < 0
	})
	return plots
}

func getUser(r *http.Request) (string, error) {
	user, ok := r.Context().Value("user").(string)
	if !ok {
		return "", errors.New("user not found in context")
	}

	return user, nil
}

type Env struct {
	db *Database
}

func (env *Env) addMeasurements(w http.ResponseWriter, r *http.Request) {
	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	measurements, err := parseMeasurements(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	err = env.db.saveMeasurements(measurements, user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func (env *Env) getAllData(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readDataFromPlot(user, plotId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots := mapMeasurements(measurements)

	jsonData, err := json.Marshal(plots)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getHourlyData(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readHourlyDataFromPlot(user, plotId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots := mapMeasurements(measurements)
	jsonData, err := json.Marshal(plots)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getLatestData(w http.ResponseWriter, r *http.Request) {
	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	measurements, err := env.db.readLatestDataFromPlot(user, plotId)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Color not found", http.StatusNotFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	plots := mapMeasurements(measurements)

	if len(plots) == 0 {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}

	jsonData, err := json.Marshal(plots[0])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getPlots(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plots, err := env.db.getPlots(user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonData, err := json.Marshal(plots)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func (env *Env) getPlot(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	vars := mux.Vars(r)
	plotId, err := strconv.Atoi(vars["plotId"])

	plot, err := env.db.getPlot(plotId, user)
	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Plot not found", http.StatusNotFound)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	instruments, err := env.db.getInstruments(plotId)
	plot.Instruments = instruments

	jsonData, err := json.Marshal(plot)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func parsePlot(r *http.Request) (Plot, error) {

	decoder := json.NewDecoder(r.Body)
	var plot Plot
	err := decoder.Decode(&plot)
	if err != nil {
		return Plot{}, err
	}
	defer r.Body.Close()

	if plot.EndTime != nil && !plot.StartTime.Before(*plot.EndTime) {
		return Plot{}, errors.New("Invalid plot: start time must be before end time.")
	}

	return plot, nil
}

func (env *Env) addPlot(w http.ResponseWriter, r *http.Request) {

	user, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	plot, err := parsePlot(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	updated_plot, err := env.db.savePlot(plot, user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonData, _ := json.Marshal(updated_plot)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	w.Write(jsonData)

}

func (env *Env) getKey(w http.ResponseWriter, r *http.Request) {
	userId, err := getUser(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	key, err := env.db.getkeyForUser(userId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	user := User{Key: key}
	jsonData, _ := json.Marshal(user)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(jsonData)
}

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Pitilt :)\n")
}

func main() {

	var err error

	//setup database
	var dbUri = os.Getenv("DATABASE_URI")
	if dbUri == "" {
		dbUri = "postgres://tilt:password@localhost:15432/tilt"
	}

	db, err := sqlx.Open("postgres", dbUri)
	if err != nil {
		log.Fatalln(err)
	}
	database := &Database{db: db}
	env := &Env{db: database}

	//create middleware for authing on google jwt from firebase
	jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			key, err := getKey(token.Header["kid"].(string))
			return key, err
		},
		SigningMethod: jwt.SigningMethodRS256,
	})

	jwtCheckHandler := &JwtCheckHandler{db: database, jwtMiddleware: jwtMiddleware}
	keyCheckHandler := &KeyCheckHandler{db: database}

	//define routes
	router := mux.NewRouter()
	router.HandleFunc("/", hello).Methods("GET")

	measurementRouter := mux.NewRouter()
	measurementRouter.HandleFunc("/measurements/", env.addMeasurements).Methods("POST")
	router.PathPrefix("/measurements").Handler(negroni.New(
		keyCheckHandler,
		negroni.Wrap(measurementRouter),
	))

	plotsRouter := mux.NewRouter()
	plotsRouter.HandleFunc("/plots/{plotId}/data/all/", env.getAllData).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}/data/latest/", env.getLatestData).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}/data/hourly/", env.getHourlyData).Methods("GET")

	plotsRouter.HandleFunc("/plots/", env.getPlots).Methods("GET")
	plotsRouter.HandleFunc("/plots/{plotId}", env.getPlot).Methods("GET")
	plotsRouter.HandleFunc("/plots/", env.addPlot).Methods("POST")

	router.PathPrefix("/plots").Handler(negroni.New(
		jwtCheckHandler,
		negroni.Wrap(plotsRouter),
	))

	userRouter := mux.NewRouter()
	userRouter.HandleFunc("/user/key/", env.getKey).Methods("GET")

	router.PathPrefix("/user").Handler(negroni.New(
		jwtCheckHandler,
		negroni.Wrap(userRouter),
	))

	// Setup CORS-handling
	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedHeaders: []string{"Content-Type", "Authorization"},
		AllowedMethods: []string{"GET", "HEAD", "POST", "PUT", "OPTIONS"},
	})

	n := negroni.New()
	n.Use(negronilogrus.NewMiddleware())
	n.Use(c)
	n.UseHandler(router)

	http.ListenAndServe(":8080", n)
}
<|endoftext|>


<commit_before>package komorebi

import (
	"log"
	"time"
)

type Column struct {
	Id        int    `json:"id"`
	Name      string `json:"name"`
	Position  int    `json:"position"`
	BoardId   int    `json:"boardId"`
	CreatedAt int64  `json:"created_at"`
}

type Columns []Column

func NewColumn(name string, position int, boardId int) Column {
	return Column{
		CreatedAt: time.Now().UnixNano(),
		Name:      name,
		Position:  position,
		BoardId:   boardId,
	}
}

func (c Column) Save() bool {
	if c.Id == 0 {
		if errInsert := dbMapper.Connection.Insert(&c); errInsert != nil {
			log.Fatalln("save of column failed", errInsert)
			return false
		}
	} else {
		if _, errUpdate := dbMapper.Connection.Update(&c); errUpdate != nil {
			log.Fatalln("save of column failed", errUpdate)
			return false
		}
	}
	reorderColumns(c.BoardId)
	return true
}

func (c Column) Destroy() bool {
	if c.Id == 0 {
		return true
	}
	// TODO: Destroy all stroys with columnId = c.Id
	if _, errDelete := dbMapper.Connection.Delete(&c); errDelete != nil {
		log.Println("delete of column failed.", errDelete)
		return false
	}
	reorderColumns(c.BoardId)
	return true
}

func reorderColumns(board_id int) {
	for index, column := range GetColumnsByBoardId(board_id) {
		column.Position = index
		if _, errUpdate := dbMapper.Connection.Update(&column); errUpdate != nil {
			log.Println("save of column failed", errUpdate)
		}
	}
}

func (c Column) Validate() (bool, string) {
	success, message := true, ""

	if len(c.Name) <= 0 {
		log.Println("Column validation failed. Name not present")
		success = false
		message += "Name not present.\n"
	}

	board := GetBoardColumnViewById(c.BoardId)
	if board.Id == 0 && board.CreatedAt == 0 {
		log.Println("Column validation failed. BoardId does not exist:", c.BoardId)
		success = false
		message += "Board does not exist.\n"
	}

	for _, column := range board.Columns {
		if column.Name == c.Name {
			log.Println("Column validation failed. Name not uniq")
			success = false
			message += "Name not uniq.\n"
		}
	}
	return success, message
}

func GetColumnsByBoardId(board_id int) Columns {
	var cols Columns
	_, err := dbMapper.Connection.Select(&cols,
		"select * from columns where BoardId=? order by Position, Id desc ", board_id)
	if err != nil {
		log.Println("Error while fetching columns", board_id)
	}
	return cols
}

func GetColumnById(id int) Column {
	var column Column
	err := dbMapper.Connection.SelectOne(&column, "select * from columns where Id=?", id)
	if err != nil {
		log.Println("Error while fetching column", id)
	}
	return column
}
<commit_msg>fix reorder columns<commit_after>package komorebi

import (
	"log"
	"time"
)

type Column struct {
	Id        int    `json:"id"`
	Name      string `json:"name"`
	Position  int    `json:"position"`
	BoardId   int    `json:"boardId"`
	CreatedAt int64  `json:"created_at"`
}

type Columns []Column

func NewColumn(name string, position int, boardId int) Column {
	return Column{
		CreatedAt: time.Now().UnixNano(),
		Name:      name,
		Position:  position,
		BoardId:   boardId,
	}
}

func (c Column) Save() bool {
	if c.Id == 0 {
		if c.Position == 0 {
			var max_pos int
			_, err := dbMapper.Connection.Select(&max_pos,
				"select Position from columns where BoardId=? order by Position Desc limit 1", c.BoardId)
			if err == nil {
				c.Position = max_pos + 1
			}
		}
		if errInsert := dbMapper.Connection.Insert(&c); errInsert != nil {
			log.Fatalln("save of column failed", errInsert)
			return false
		}
	} else {
		if _, errUpdate := dbMapper.Connection.Update(&c); errUpdate != nil {
			log.Fatalln("save of column failed", errUpdate)
			return false
		}
	}
	reorderColumns(c.BoardId)
	return true
}

func (c Column) Destroy() bool {
	if c.Id == 0 {
		return true
	}
	// TODO: Destroy all stroys with columnId = c.Id
	if _, errDelete := dbMapper.Connection.Delete(&c); errDelete != nil {
		log.Println("delete of column failed.", errDelete)
		return false
	}
	reorderColumns(c.BoardId)
	return true
}

func reorderColumns(board_id int) {
	for index, column := range GetColumnsByBoardId(board_id) {
		column.Position = index
		if _, errUpdate := dbMapper.Connection.Update(&column); errUpdate != nil {
			log.Println("save of column failed", errUpdate)
		}
	}
}

func (c Column) Validate() (bool, string) {
	success, message := true, ""

	if len(c.Name) <= 0 {
		log.Println("Column validation failed. Name not present")
		success = false
		message += "Name not present.\n"
	}

	board := GetBoardColumnViewById(c.BoardId)
	if board.Id == 0 && board.CreatedAt == 0 {
		log.Println("Column validation failed. BoardId does not exist:", c.BoardId)
		success = false
		message += "Board does not exist.\n"
	}

	for _, column := range board.Columns {
		if column.Name == c.Name {
			log.Println("Column validation failed. Name not uniq")
			success = false
			message += "Name not uniq.\n"
		}
	}
	return success, message
}

func GetColumnsByBoardId(board_id int) Columns {
	var cols Columns
	_, err := dbMapper.Connection.Select(&cols,
		"select * from columns where BoardId=? order by Position, Id desc ", board_id)
	if err != nil {
		log.Println("Error while fetching columns", board_id)
	}
	return cols
}

func GetColumnById(id int) Column {
	var column Column
	err := dbMapper.Connection.SelectOne(&column, "select * from columns where Id=?", id)
	if err != nil {
		log.Println("Error while fetching column", id)
	}
	return column
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"net/http"
)

var index = template.Must(template.ParseFiles(
	"templates/_base.html",
	"templates/index.html",
))

func hello(w http.ResponseWriter, req *http.Request) {
	if err := index.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	http.HandleFunc("/", hello)
	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	}
}

<commit_msg>Use port 5050<commit_after>package main

import (
	"html/template"
	"net/http"
)

var index = template.Must(template.ParseFiles(
	"templates/_base.html",
	"templates/index.html",
))

func hello(w http.ResponseWriter, req *http.Request) {
	if err := index.Execute(w, nil); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	http.HandleFunc("/", hello)
	if err := http.ListenAndServe(":5050", nil); err != nil {
		panic(err)
	}
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"gopkg.in/gomail.v1"
	"io/ioutil"
	"os"
)

type Configuration struct {
	Server struct {
		TLS      bool   `json:"tls"`
		Host     string `json:"host"`
		Port     int  `json:"port"`
		User     string `json:"user"`
		Password string `json:"password"`
	} `json:"server"`
	From struct {
		Name string `json:"name"`
		Address string `json:"address"`
	} `json:"from"`
	To []struct {
		Name string `json:"name"`
		Address string `json:"address"`
	} `json:"to"`
}

func main() {
	app := cli.NewApp()
	app.Name = "valiant"
	app.Usage = "A brave mail pigeon"
	app.Author = "Romain Baugue"
	app.Email = "romain.baugue@elwinar.com"
	app.Version = "1-dev"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "configuration,c",
			Value: "valiant.json",
			Usage: "configuration file",
		},
		cli.StringFlag{
			Name:  "body,b",
			Usage: "body file",
		},
		cli.StringFlag{
			Name: "subject,s",
			Usage: "message subject",
		},
	}
	app.Action = action

	app.Run(os.Args)
}

func action(ctx *cli.Context) {
	var cfg Configuration
	var err error

	_, _, error := Bootstrap(ctx, &cfg)

	message := gomail.NewMessage()
	message.SetHeader("From", fmt.Sprintf("%s <%s>", cfg.From.Name, cfg.From.Address))

	var to []string
	for _, t := range cfg.To {
		to = append(to, fmt.Sprintf("%s <%s>", t.Name, t.Address))
	}
	message.SetHeader("To", to...)
	message.SetHeader("Subject", ctx.String("subject"))

	body, err := ioutil.ReadFile(ctx.String("body"))
	if err != nil {
		error.Fatalln("Unable to read body file:", err)
	}
	message.SetBody("text/html", string(body))

	mailer := gomail.NewMailer(cfg.Server.Host, cfg.Server.User, cfg.Server.Password, cfg.Server.Port)
	if err := mailer.Send(message); err != nil {
		error.Fatalln("Unable to send message:", err)
	}
}
<commit_msg>Add TLS handling<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"github.com/codegangsta/cli"
	mail "gopkg.in/gomail.v1"
	"io/ioutil"
	"os"
)

type Configuration struct {
	Server struct {
		TLS      bool   `json:"tls"`
		Host     string `json:"host"`
		Port     int  `json:"port"`
		User     string `json:"user"`
		Password string `json:"password"`
	} `json:"server"`
	From struct {
		Name string `json:"name"`
		Address string `json:"address"`
	} `json:"from"`
	To []struct {
		Name string `json:"name"`
		Address string `json:"address"`
	} `json:"to"`
}

func main() {
	app := cli.NewApp()
	app.Name = "valiant"
	app.Usage = "A brave mail pigeon"
	app.Author = "Romain Baugue"
	app.Email = "romain.baugue@elwinar.com"
	app.Version = "1-dev"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "configuration,c",
			Value: "valiant.json",
			Usage: "configuration file",
		},
		cli.StringFlag{
			Name:  "body,b",
			Usage: "body file",
		},
		cli.StringFlag{
			Name: "subject,s",
			Usage: "message subject",
		},
	}
	app.Action = action

	app.Run(os.Args)
}

func action(ctx *cli.Context) {
	var cfg Configuration
	var err error

	_, _, error := Bootstrap(ctx, &cfg)

	message := mail.NewMessage()
	message.SetHeader("From", fmt.Sprintf("%s <%s>", cfg.From.Name, cfg.From.Address))

	var to []string
	for _, t := range cfg.To {
		to = append(to, fmt.Sprintf("%s <%s>", t.Name, t.Address))
	}
	message.SetHeader("To", to...)
	message.SetHeader("Subject", ctx.String("subject"))

	body, err := ioutil.ReadFile(ctx.String("body"))
	if err != nil {
		error.Fatalln("Unable to read body file:", err)
	}
	message.SetBody("text/html", string(body))

	var settings []mail.MailerSetting
	if cfg.Server.TLS {
		settings = append(settings, mail.SetTLSConfig(&tls.Config {
			InsecureSkipVerify: true,
			ServerName: cfg.Server.Host,
		}))
	}
	mailer := mail.NewMailer(cfg.Server.Host, cfg.Server.User, cfg.Server.Password, cfg.Server.Port, settings...)

	if err := mailer.Send(message); err != nil {
		error.Fatalln("Unable to send message:", err)
	}
}
<|endoftext|>


<commit_before>// Package geoloader provides the interface between manager and dataset handling
// packages (geolite2 and legacy). manager only depends on geoloader and api.
// geoloader only depends on geolite2, legacy and api.
package geoloader

import (
	"context"
	"errors"
	"flag"
	"log"
	"regexp"
	"runtime"
	"sync"
	"time"

	"cloud.google.com/go/storage"
	"github.com/m-lab/annotation-service/api"
	"github.com/m-lab/annotation-service/metrics"
	"google.golang.org/api/iterator"
)

var (
	// geoLite2StartDate is the date we have the first GeoLite2 dataset.
	// Any request earlier than this date using legacy binary datasets
	// later than this date using GeoLite2 datasets
	// TODO make this local
	geoLite2StartDate = time.Unix(1502755200, 0) //"August 15, 2017"

	// geoLite2Regex is used to filter which geolite2 dataset files we consider acceptable.
	geoLite2Regex = regexp.MustCompile(`Maxmind/\d{4}/\d{2}/\d{2}/\d{8}T\d{6}Z-GeoLite2-City-CSV\.zip`)

	// GeoLegacy??Regex are used to filter which legacy dataset files we consider acceptable.
	geoLegacyRegex   = regexp.MustCompile(`.*-GeoLiteCity.dat.*`)
	geoLegacyv6Regex = regexp.MustCompile(`.*-GeoLiteCityv6.dat.*`)

	// ErrNoLoader is returned if nil is passed for loader parameter.
	ErrNoLoader = errors.New("No loader provided")

	// ErrAfterLegacyCutoff is returned for legacy files beyond the cutoff date.
	errAfterLegacyCutoff = errors.New("After cutoff date")
	// ErrNoMatch is returned (internally) when filename does not match regexp.
	errNoMatch = errors.New("Doesn't match") // TODO
)

// TestingUseOnlyMarch hacks the regular expressions to reduce the number of datasets for testing.
func TestingUseOnlyMarch() {
	if flag.Lookup("test.v") == nil {
		log.Println("This should only be called in unit tests.")
		return
	}
	geoLite2Regex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T\d{6}Z-GeoLite2-City-CSV\.zip`)
	geoLegacyRegex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T.*-GeoLiteCity.dat.*`)
	geoLegacyv6Regex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T.*-GeoLiteCityv6.dat.*`)
}

/*****************************************************************************
*                          LoadAll... functions                              *
*****************************************************************************/

// Returns the normal iterator for objects in the appropriate GCS bucket.
func bucketIterator() (*storage.ObjectIterator, error) {
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return nil, err
	}
	prospectiveFiles := client.Bucket(api.MaxmindBucketName).Objects(ctx, &storage.Query{Prefix: api.MaxmindPrefix})
	return prospectiveFiles, nil
}

// LoadAll loads all datasets from the source that match the filter.
func LoadAll(
	filter func(file *storage.ObjectAttrs) error,
	loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	if loader == nil {
		return nil, ErrNoLoader
	}
	source, err := bucketIterator()
	if err != nil {
		return nil, err
	}

	// TODO - maybe use a channel and single threaded append instead.
	result := make([]api.Annotator, 0, 100)
	resultLock := sync.Mutex{}
	wg := sync.WaitGroup{}

	for file, err := source.Next(); err != iterator.Done; file, err = source.Next() {
		// TODO - should we retry here?
		if err != nil {
			return nil, err
		}
		if file == nil {
			log.Println("file is nil", err)
			continue
		}
		if filter != nil && filter(file) != nil {
			continue
		}
		_, _, callerLine, _ := runtime.Caller(1)
		log.Println("Loading", file.Name, "from line", callerLine)
		wg.Add(1)
		go func(file *storage.ObjectAttrs) {
			defer wg.Done()
			ann, err := loader(file)
			if err != nil {
				log.Println("Retrying", file.Name, "after", err)
				ann, err = loader(file)
				if err != nil {
					log.Println("Failed trying to load", file.Name, "with", err)
					return
				}
			}
			resultLock.Lock()
			result = append(result, ann)
			resultLock.Unlock()
			metrics.DatasetCount.Inc()
			log.Println("Loaded", file.Name)
		}(file)
	}
	wg.Wait()
	return result, nil
}

// filter is used to create filter functions for the loaders.
// The file date is checked against `before` and file name is matched against `r`
func filter(file *storage.ObjectAttrs, r *regexp.Regexp, before time.Time) error {
	if !before.Equal(time.Time{}) {
		fileDate, err := api.ExtractDateFromFilename(file.Name)
		if err != nil {
			return err
		}
		if !fileDate.Before(before) {
			return errAfterLegacyCutoff
		}
	}

	if !r.MatchString(file.Name) {
		return errNoMatch
	}

	return nil
}

// LoadAllLegacyV4 loads all v4 legacy datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllLegacyV4(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return LoadAll(
		func(file *storage.ObjectAttrs) error {
			// We archived but do not use legacy datasets after GeoLite2StartDate.
			return filter(file, geoLegacyRegex, geoLite2StartDate)
		},
		loader)
}

// LoadAllLegacyV6 loads all v6 legacy datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllLegacyV6(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return LoadAll(
		func(file *storage.ObjectAttrs) error {
			// We archived but do not use legacy datasets after GeoLite2StartDate.
			return filter(file, geoLegacyv6Regex, geoLite2StartDate)
		},
		loader)
}

// LoadAllGeolite2 loads all geolite2 datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllGeolite2(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return LoadAll(
		func(file *storage.ObjectAttrs) error {
			return filter(file, geoLite2Regex, time.Time{})
		},
		loader)
}
<commit_msg>make a function local<commit_after>// Package geoloader provides the interface between manager and dataset handling
// packages (geolite2 and legacy). manager only depends on geoloader and api.
// geoloader only depends on geolite2, legacy and api.
package geoloader

import (
	"context"
	"errors"
	"flag"
	"log"
	"regexp"
	"runtime"
	"sync"
	"time"

	"cloud.google.com/go/storage"
	"github.com/m-lab/annotation-service/api"
	"github.com/m-lab/annotation-service/metrics"
	"google.golang.org/api/iterator"
)

var (
	// geoLite2StartDate is the date we have the first GeoLite2 dataset.
	// Any request earlier than this date using legacy binary datasets
	// later than this date using GeoLite2 datasets
	// TODO make this local
	geoLite2StartDate = time.Unix(1502755200, 0) //"August 15, 2017"

	// geoLite2Regex is used to filter which geolite2 dataset files we consider acceptable.
	geoLite2Regex = regexp.MustCompile(`Maxmind/\d{4}/\d{2}/\d{2}/\d{8}T\d{6}Z-GeoLite2-City-CSV\.zip`)

	// GeoLegacy??Regex are used to filter which legacy dataset files we consider acceptable.
	geoLegacyRegex   = regexp.MustCompile(`.*-GeoLiteCity.dat.*`)
	geoLegacyv6Regex = regexp.MustCompile(`.*-GeoLiteCityv6.dat.*`)

	// ErrNoLoader is returned if nil is passed for loader parameter.
	ErrNoLoader = errors.New("No loader provided")

	// ErrAfterLegacyCutoff is returned for legacy files beyond the cutoff date.
	errAfterLegacyCutoff = errors.New("After cutoff date")
	// ErrNoMatch is returned (internally) when filename does not match regexp.
	errNoMatch = errors.New("Doesn't match") // TODO
)

// TestingUseOnlyMarch hacks the regular expressions to reduce the number of datasets for testing.
func TestingUseOnlyMarch() {
	if flag.Lookup("test.v") == nil {
		log.Println("This should only be called in unit tests.")
		return
	}
	geoLite2Regex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T\d{6}Z-GeoLite2-City-CSV\.zip`)
	geoLegacyRegex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T.*-GeoLiteCity.dat.*`)
	geoLegacyv6Regex = regexp.MustCompile(`Maxmind/\d{4}/03/\d{2}/\d{8}T.*-GeoLiteCityv6.dat.*`)
}

/*****************************************************************************
*                          LoadAll... functions                              *
*****************************************************************************/

// Returns the normal iterator for objects in the appropriate GCS bucket.
func bucketIterator() (*storage.ObjectIterator, error) {
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return nil, err
	}
	prospectiveFiles := client.Bucket(api.MaxmindBucketName).Objects(ctx, &storage.Query{Prefix: api.MaxmindPrefix})
	return prospectiveFiles, nil
}

// loadAll loads all datasets from the source that match the filter.
func loadAll(
	filter func(file *storage.ObjectAttrs) error,
	loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	if loader == nil {
		return nil, ErrNoLoader
	}
	source, err := bucketIterator()
	if err != nil {
		return nil, err
	}

	// TODO - maybe use a channel and single threaded append instead.
	result := make([]api.Annotator, 0, 100)
	resultLock := sync.Mutex{}
	wg := sync.WaitGroup{}

	for file, err := source.Next(); err != iterator.Done; file, err = source.Next() {
		// TODO - should we retry here?
		if err != nil {
			return nil, err
		}
		if file == nil {
			log.Println("file is nil", err)
			continue
		}
		if filter != nil && filter(file) != nil {
			continue
		}
		_, _, callerLine, _ := runtime.Caller(1)
		log.Println("Loading", file.Name, "from line", callerLine)
		wg.Add(1)
		go func(file *storage.ObjectAttrs) {
			defer wg.Done()
			ann, err := loader(file)
			if err != nil {
				log.Println("Retrying", file.Name, "after", err)
				ann, err = loader(file)
				if err != nil {
					log.Println("Failed trying to load", file.Name, "with", err)
					return
				}
			}
			resultLock.Lock()
			result = append(result, ann)
			resultLock.Unlock()
			metrics.DatasetCount.Inc()
			log.Println("Loaded", file.Name)
		}(file)
	}
	wg.Wait()
	return result, nil
}

// filter is used to create filter functions for the loaders.
// The file date is checked against `before` and file name is matched against `r`
func filter(file *storage.ObjectAttrs, r *regexp.Regexp, before time.Time) error {
	if !before.Equal(time.Time{}) {
		fileDate, err := api.ExtractDateFromFilename(file.Name)
		if err != nil {
			return err
		}
		if !fileDate.Before(before) {
			return errAfterLegacyCutoff
		}
	}

	if !r.MatchString(file.Name) {
		return errNoMatch
	}

	return nil
}

// LoadAllLegacyV4 loads all v4 legacy datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllLegacyV4(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return loadAll(
		func(file *storage.ObjectAttrs) error {
			// We archived but do not use legacy datasets after GeoLite2StartDate.
			return filter(file, geoLegacyRegex, geoLite2StartDate)
		},
		loader)
}

// LoadAllLegacyV6 loads all v6 legacy datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllLegacyV6(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return loadAll(
		func(file *storage.ObjectAttrs) error {
			// We archived but do not use legacy datasets after GeoLite2StartDate.
			return filter(file, geoLegacyv6Regex, geoLite2StartDate)
		},
		loader)
}

// LoadAllGeolite2 loads all geolite2 datasets from the appropriate GCS bucket.
// The loader is injected, to allow for efficient unit testing.
func LoadAllGeolite2(loader func(*storage.ObjectAttrs) (api.Annotator, error)) ([]api.Annotator, error) {
	return loadAll(
		func(file *storage.ObjectAttrs) error {
			return filter(file, geoLite2Regex, time.Time{})
		},
		loader)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

// Printed for -help, -h or with wrong number of arguments
var usage = `Usage: %s githubname backupdir

  githubname  github user or organization name to get the repositories from
  backupdir   directory path to save the repositories to

`

type Repo struct {
	Name   string
	GitUrl string `json:"git_url"`
}

var maxWorkers = 10
var githubApi = "https://api.github.com"

var verboseFlag = flag.Bool("verbose", false, "print progress information")

// Get command line arguments and start updating repositories
func main() {
	name, backupDir := parseArgs()

	category := getCategory(name)
	repos := getRepos(setMaxPageSize(strings.Join([]string{githubApi, category, name, "repos"}, "/")))

	verbose("Backup for", category[:len(category)-1], name, "with", len(repos), "repositories")

	jobs := make(chan Repo)
	var wg sync.WaitGroup

	workers := maxWorkers

	if len(repos) < maxWorkers {
		workers = len(repos)
	}

	for w := 0; w < workers; w++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for repo := range jobs {
				updateRepo(backupDir, repo)
			}
		}()
	}

	for _, repo := range repos {
		jobs <- repo
	}
	close(jobs)
	wg.Wait()
}

// Get the two positional arguments githubname and backupdir
func parseArgs() (string, string) {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		os.Exit(1)
	}
	return args[0], args[1]
}

// Returns "users" or "orgs" depending on type of account
func getCategory(name string) string {
	r, err := http.Get(strings.Join([]string{githubApi, "users", name}, "/"))
	if err != nil {
		panic(err)
	}
	defer r.Body.Close()
	if r.StatusCode >= 300 {
		panic(fmt.Sprint("Request to ", r.Request.URL, " with bad status code ", r.StatusCode))
	}

	var account struct {
		Type string
	}
	json.NewDecoder(r.Body).Decode(&account)

	if account.Type == "User" {
		return "users"
	}
	if account.Type == "Organization" {
		return "orgs"
	}
	panic(fmt.Sprint("Unknown type of account ", account.Type, " for name ", name))
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(u string) []Repo {
	r, err := http.Get(u)
	if err != nil {
		panic(err)
	}
	defer r.Body.Close()

	if r.StatusCode >= 300 {
		panic(fmt.Sprint("Request to ", u, " with bad status code ", r.StatusCode))
	}

	var repos []Repo
	json.NewDecoder(r.Body).Decode(&repos)

	linkHeader := r.Header["Link"]
	if len(linkHeader) > 0 {
		firstLink := strings.Split(linkHeader[0], ",")[0]
		if strings.Contains(firstLink, "rel=\"next\"") {
			urlInBrackets := strings.Split(firstLink, ";")[0]
			return append(repos, getRepos(urlInBrackets[1:len(urlInBrackets)-1])...)
		}
	}

	return repos
}

//  Adds per_page=100 to a URL
func setMaxPageSize(rawUrl string) string {
	u, err := url.Parse(rawUrl)
	if err != nil {
		panic(err)
	}
	q := u.Query()
	q.Set("per_page", "100")
	u.RawQuery = q.Encode()
	return u.String()
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, repo Repo) {
	repoDir := path.Join(backupDir, repo.Name)

	var cmd *exec.Cmd
	if exists(repoDir) {
		defer verbose("Updated repository:", repo.Name)

		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		defer verbose("Cloned  repository:", repo.Name)

		cmd = exec.Command("git", "clone", repo.GitUrl, repoDir)
	}

	err := cmd.Run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

// Check if a file or directory exists
func exists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		} else {
			panic(err)
		}
	}
	return true
}

func verbose(info ...interface{}) {
	if *verboseFlag {
		log.Println(info...)
	}
}
<commit_msg>trying to do proper error handling<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

// Printed for -help, -h or with wrong number of arguments
var usage = `Usage: %s githubname backupdir

  githubname  github user or organization name to get the repositories from
  backupdir   directory path to save the repositories to

`

type Repo struct {
	Name   string
	GitUrl string `json:"git_url"`
}

var maxWorkers = 10
var githubApi = "https://api.github.com"

var verboseFlag = flag.Bool("verbose", false, "print progress information")

// Get command line arguments and start updating repositories
func main() {
	name, backupDir := parseArgs()

	category, err := getCategory(name)
	if err != nil {
		log.Fatal(err)
	}
	url, err := setMaxPageSize(strings.Join([]string{githubApi, category, name, "repos"}, "/"))
	if err != nil {
		log.Fatal(err)
	}
	repos, err := getRepos(url)
	if err != nil {
		log.Fatal(err)
	}

	verbose("Backup for", category[:len(category)-1], name, "with", len(repos), "repositories")

	jobs := make(chan Repo)

	workers := maxWorkers
	if len(repos) < maxWorkers {
		workers = len(repos)
	}

	var wg sync.WaitGroup
	wg.Add(workers)

	for w := 0; w < workers; w++ {
		go func() {
			defer wg.Done()
			for repo := range jobs {
				err := updateRepo(backupDir, repo)
				if err != nil {
					log.Println(err)
				}
			}
		}()
	}

	for _, repo := range repos {
		jobs <- repo
	}
	close(jobs)
	wg.Wait()
}

// Get the two positional arguments githubname and backupdir
func parseArgs() (string, string) {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		os.Exit(1)
	}
	return args[0], args[1]
}

// Returns "users" or "orgs" depending on type of account
func getCategory(name string) (string, error) {
	res, err := http.Get(strings.Join([]string{githubApi, "users", name}, "/"))
	if err != nil {
		return "", fmt.Errorf("cannot get user info: %v", err)
	}
	defer res.Body.Close()
	if res.StatusCode >= 300 {
		return "", fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var account struct {
		Type string
	}
	json.NewDecoder(res.Body).Decode(&account)

	if account.Type == "User" {
		return "users", nil
	}
	if account.Type == "Organization" {
		return "orgs", nil
	}
	return "", fmt.Errorf("unknown type of account %s for name %s", account.Type)
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(u string) ([]Repo, error) {
	res, err := http.Get(u)
	if err != nil {
		return nil, fmt.Errorf("cannot get repos: %v", err)
	}
	defer res.Body.Close()
	if res.StatusCode >= 300 {
		return nil, fmt.Errorf("bad response from %s: %v", res.Request.URL, res.Status)
	}

	var repos []Repo
	json.NewDecoder(res.Body).Decode(&repos)

	linkHeader := res.Header["Link"]
	if len(linkHeader) > 0 {
		firstLink := strings.Split(linkHeader[0], ",")[0]
		if strings.Contains(firstLink, "rel=\"next\"") {
			urlInBrackets := strings.Split(firstLink, ";")[0]
			nextRepos, err := getRepos(urlInBrackets[1 : len(urlInBrackets)-1])
			return append(repos, nextRepos...), err
		}
	}

	return repos, nil
}

//  Adds per_page=100 to a URL
func setMaxPageSize(rawUrl string) (string, error) {
	u, err := url.Parse(rawUrl)
	if err != nil {
		fmt.Errorf("cannot parse url: %v", err)
	}
	q := u.Query()
	q.Set("per_page", "100")
	u.RawQuery = q.Encode()
	return u.String(), nil
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, repo Repo) error {
	repoDir := path.Join(backupDir, repo.Name)

	var cmd *exec.Cmd
	repoExists, err := exists(repoDir)
	if err != nil {
		return fmt.Errorf("cannot check if repo exists: %v", err)
	}
	if repoExists {
		verbose("Update repository:", repo.Name)
		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		verbose("Clone  repository:", repo.Name)
		cmd = exec.Command("git", "clone", repo.GitUrl, repoDir)
	}

	err = cmd.Run()
	if err != nil {
		// Give enough information to reproduce command
		return fmt.Errorf("error running command `%v` (`%v`) in dir `%v` with env `%v`: %v", cmd.Args, cmd.Path, cmd.Dir, cmd.Env, err)
	}
	return nil
}

// Check if a file or directory exists
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("cannot get stats for path `%s`: %v", path, err)
	}
	return true, nil
}

func verbose(info ...interface{}) {
	if *verboseFlag {
		log.Println(info...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/koding/klient/collaboration"
	"github.com/koding/klient/command"
	"github.com/koding/klient/docker"
	"github.com/koding/klient/fs"
	"github.com/koding/klient/protocol"
	"github.com/koding/klient/terminal"
	"github.com/koding/klient/usage"

	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update parameters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":    true,
		"fs.glob":             true,
		"fs.readFile":         true,
		"fs.writeFile":        true,
		"fs.uniquePath":       true,
		"fs.getInfo":          true,
		"fs.setPermissions":   true,
		"fs.remove":           true,
		"fs.rename":           true,
		"fs.createDirectory":  true,
		"fs.move":             true,
		"fs.copy":             true,
		"webterm.getSessions": true,
		"webterm.connect":     true,
		"webterm.killSession": true,
		"exec":                true,
		"klient.share":        true,
		"klient.unshare":      true,
		"klient.shared":       true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client.
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Docker
	dock := docker.New("unix:///var/run/docker.sock", k.Log)
	k.HandleFunc("docker.build", dock.Build)
	k.HandleFunc("docker.create", dock.Create)
	k.HandleFunc("webterm.connect", dock.Connect)
	k.HandleFunc("docker.stop", dock.Stop)
	k.HandleFunc("docker.start", dock.Start)
	k.HandleFunc("docker.removeContainer", dock.RemoveContainer)
	k.HandleFunc("docker.removeImage", dock.RemoveImage)
	k.HandleFunc("docker.list", dock.List)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	// k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	var disconnectTimer *time.Timer

	k.OnFirstRequest(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is connected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		// it's still not initialized, so don't do anything
		if disconnectTimer != nil {
			// stop previously started disconnect timer.
			k.Log.Info("Disconnection timer is cancelled.")
			disconnectTimer.Stop()
		}

	})

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		// if there is any previously created timers stop them so we don't leak
		// goroutines
		if disconnectTimer != nil {
			disconnectTimer.Stop()
		}

		k.Log.Info("Disconnection timer of 1 minutes is fired.")
		disconnectTimer = time.NewTimer(time.Minute * 1)

		// Close all active sessions of the current. Do not close it
		// immediately, instead of give some time so users can safely exit. If
		// the user reconnects again the timer will be stopped so we don't
		// unshare for network hiccups accidentally.
		go func() {
			select {
			case <-disconnectTimer.C:
				sharedUsers, err := collab.GetAll()
				if err != nil {
					k.Log.Warning("Couldn't unshare users: '%s'", err)
					return
				}

				if len(sharedUsers) == 0 {
					return // nothing to do ...
				}

				k.Log.Info("Unsharing users '%s'", sharedUsers)
				for _, user := range sharedUsers {
					if err := collab.Delete(user); err != nil {
						k.Log.Warning("Couldn't delete user from storage: '%s'", err)
					}
					term.CloseSessions(user)

				}
			}
		}()
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<commit_msg>docker: change back method name to the original one<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/koding/klient/collaboration"
	"github.com/koding/klient/command"
	"github.com/koding/klient/docker"
	"github.com/koding/klient/fs"
	"github.com/koding/klient/protocol"
	"github.com/koding/klient/terminal"
	"github.com/koding/klient/usage"

	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update parameters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":       true,
		"fs.glob":                true,
		"fs.readFile":            true,
		"fs.writeFile":           true,
		"fs.uniquePath":          true,
		"fs.getInfo":             true,
		"fs.setPermissions":      true,
		"fs.remove":              true,
		"fs.rename":              true,
		"fs.createDirectory":     true,
		"fs.move":                true,
		"fs.copy":                true,
		"webterm.getSessions":    true,
		"webterm.connect":        true,
		"webterm.killSession":    true,
		"exec":                   true,
		"klient.share":           true,
		"klient.unshare":         true,
		"klient.shared":          true,
		"docker.build":           true,
		"docker.create":          true,
		"docker.connect":         true,
		"docker.stop":            true,
		"docker.start":           true,
		"docker.removeContainer": true,
		"docker.removeImage":     true,
		"docker.list":            true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client.
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Docker
	dock := docker.New("unix:///var/run/docker.sock", k.Log)
	k.HandleFunc("docker.build", dock.Build)
	k.HandleFunc("docker.create", dock.Create)
	k.HandleFunc("docker.connect", dock.Connect)
	k.HandleFunc("docker.stop", dock.Stop)
	k.HandleFunc("docker.start", dock.Start)
	k.HandleFunc("docker.removeContainer", dock.RemoveContainer)
	k.HandleFunc("docker.removeImage", dock.RemoveImage)
	k.HandleFunc("docker.list", dock.List)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	var disconnectTimer *time.Timer

	k.OnFirstRequest(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is connected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		// it's still not initialized, so don't do anything
		if disconnectTimer != nil {
			// stop previously started disconnect timer.
			k.Log.Info("Disconnection timer is cancelled.")
			disconnectTimer.Stop()
		}

	})

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		// if there is any previously created timers stop them so we don't leak
		// goroutines
		if disconnectTimer != nil {
			disconnectTimer.Stop()
		}

		k.Log.Info("Disconnection timer of 1 minutes is fired.")
		disconnectTimer = time.NewTimer(time.Minute * 1)

		// Close all active sessions of the current. Do not close it
		// immediately, instead of give some time so users can safely exit. If
		// the user reconnects again the timer will be stopped so we don't
		// unshare for network hiccups accidentally.
		go func() {
			select {
			case <-disconnectTimer.C:
				sharedUsers, err := collab.GetAll()
				if err != nil {
					k.Log.Warning("Couldn't unshare users: '%s'", err)
					return
				}

				if len(sharedUsers) == 0 {
					return // nothing to do ...
				}

				k.Log.Info("Unsharing users '%s'", sharedUsers)
				for _, user := range sharedUsers {
					if err := collab.Delete(user); err != nil {
						k.Log.Warning("Couldn't delete user from storage: '%s'", err)
					}
					term.CloseSessions(user)

				}
			}
		}()
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	id := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			generateName()
		}
	}
	db.Close()

	return id

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)
	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			check(err)
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format("2006-01-02 15:04:05")
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format("2006-01-02 15:04:05")
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format("2006-01-02 15:04:05")
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format("2006-01-02 15:04:05")
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format("2006-01-02 15:04:05")
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format("2006-01-02 15:04:05")
		break

	case "forever":
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	default:
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	setup()
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Remove setup function call<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	id := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			generateName()
		}
	}
	db.Close()

	return id

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)
	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			check(err)
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format("2006-01-02 15:04:05")
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format("2006-01-02 15:04:05")
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format("2006-01-02 15:04:05")
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format("2006-01-02 15:04:05")
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format("2006-01-02 15:04:05")
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format("2006-01-02 15:04:05")
		break

	case "forever":
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	default:
		expiryTime = now.Add(time.Hour * 24 * (365 * 20)).Format("2006-01-02 15:04:05")
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

// Exit codes
const (
	ExitCodeOK int = iota
	ExitCodeError
)

var (
	version  string
	revision string
)

var app = App{}

func init() {
	var path, message string
	var printVersion bool

	flag.BoolVar(&printVersion, "v", false, "prints current sendslack version")
	flag.StringVar(&path, "c", "", "/path/to/config.json (default: $HOME/.config/sendslack/config.json)")
	flag.StringVar(&message, "m", "", "message")
	flag.Parse()

	if printVersion {
		fmt.Fprintln(os.Stdout, "Version:", version)
		fmt.Fprintln(os.Stdout, "Revision:", revision)
		os.Exit(ExitCodeOK)
	}

	config, err := NewConfig(path)
	if err != nil {
		fmt.Fprintln(os.Stderr, "error:", err)
		os.Exit(ExitCodeError)
	}

	if len(message) == 0 && len(os.Args) > 1 {
		message = os.Args[1]
	}

	if len(message) == 0 {

		fmt.Fprintln(os.Stderr, "Message is empty. To send a message, input a message.")
		os.Exit(ExitCodeError)
	}

	app.Message = message
	app.SlackConfig = config.SlackWebhook
}

func main() {
	os.Exit(app.Run())
}
<commit_msg>clean-up<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
)

// Exit codes
const (
	ExitCodeOK int = iota
	ExitCodeError
)

var (
	version  string
	revision string
)

var app = App{}

func init() {
	var path, message string
	var printVersion bool

	flag.BoolVar(&printVersion, "v", false, "prints current sendslack version")
	flag.StringVar(&path, "c", "", "/path/to/config.json (default: $HOME/.config/sendslack/config.json)")
	flag.StringVar(&message, "m", "", "message")
	flag.Parse()

	if printVersion {
		fmt.Fprintln(os.Stdout, "Version:", version)
		fmt.Fprintln(os.Stdout, "Revision:", revision)
		os.Exit(ExitCodeOK)
	}

	config, err := NewConfig(path)
	if err != nil {
		fmt.Fprintln(os.Stderr, "error:", err)
		os.Exit(ExitCodeError)
	}

	if len(message) == 0 && len(os.Args) > 1 {
		message = os.Args[1]
	}

	if len(message) == 0 {
		fmt.Fprintln(os.Stderr, "Message is empty. To send a message, input a message.")
		os.Exit(ExitCodeError)
	}

	app.Message = message
	app.SlackConfig = config.SlackWebhook
}

func main() {
	os.Exit(app.Run())
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
)

const BUFFERSIZE = 1024
const numberConnections = 4

// Build flags
var server, file string

// Global varaibles
var serverAddress, fileName, codePhraseFlag, connectionTypeFlag string
var runAsRelay, debugFlag bool

func main() {
	flag.BoolVar(&runAsRelay, "relay", false, "run as relay")
	flag.BoolVar(&debugFlag, "debug", false, "debug mode")
	flag.StringVar(&serverAddress, "server", "cowyo.com", "(run as client) server address to connect to")
	flag.StringVar(&fileName, "send", "", "file to send")
	flag.StringVar(&codePhraseFlag, "code", "", "(run as server) file to serve")
	flag.Parse()
	// Check build flags too, which take precedent
	if server != "" {
		serverAddress = server
	}
	if file != "" {
		fileName = file
	}

	if len(fileName) > 0 {
		_, err := os.Open(fileName)
		if err != nil {
			log.Fatal(err)
			return
		}
		connectionTypeFlag = "s" // sender
	} else {
		connectionTypeFlag = "r" //receiver
	}

	if !runAsRelay {
		if len(codePhraseFlag) == 0 {
			if connectionTypeFlag == "r" {
				codePhraseFlag = getInput("What is your code phrase? ")
			}
			if len(codePhraseFlag) < 5 {
				codePhraseFlag = GetRandomName()
				fmt.Println("Your code phrase is now " + codePhraseFlag)
			}
		}
	}

	log.SetFormatter(&log.TextFormatter{})
	if debugFlag {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.WarnLevel)
	}

	if runAsRelay {
		runServer()
	} else if len(serverAddress) != 0 {
		runClient(connectionTypeFlag, codePhraseFlag)
	} else {
		fmt.Println("You must specify either -file (for running as a server) or -server (for running as a client)")
	}
}

func getInput(prompt string) string {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print(prompt)
	text, _ := reader.ReadString('\n')
	return strings.TrimSpace(text)
}
<commit_msg>Update flags<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
)

const BUFFERSIZE = 1024
const numberConnections = 4

// Build flags
var server, file string

// Global varaibles
var serverAddress, fileName, codePhraseFlag, connectionTypeFlag string
var runAsRelay, debugFlag bool

func main() {
	flag.BoolVar(&runAsRelay, "relay", false, "run as relay")
	flag.BoolVar(&debugFlag, "debug", false, "debug mode")
	flag.StringVar(&serverAddress, "server", "cowyo.com", "address of relay server")
	flag.StringVar(&fileName, "send", "", "file to send")
	flag.StringVar(&codePhraseFlag, "code", "", "use your own code phrase")
	flag.Parse()
	// Check build flags too, which take precedent
	if server != "" {
		serverAddress = server
	}
	if file != "" {
		fileName = file
	}

	if len(fileName) > 0 {
		_, err := os.Open(fileName)
		if err != nil {
			log.Fatal(err)
			return
		}
		connectionTypeFlag = "s" // sender
	} else {
		connectionTypeFlag = "r" //receiver
	}

	if !runAsRelay {
		if len(codePhraseFlag) == 0 {
			if connectionTypeFlag == "r" {
				codePhraseFlag = getInput("What is your code phrase? ")
			}
			if len(codePhraseFlag) < 5 {
				codePhraseFlag = GetRandomName()
				fmt.Println("Your code phrase is now " + codePhraseFlag)
			}
		}
	}

	log.SetFormatter(&log.TextFormatter{})
	if debugFlag {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.WarnLevel)
	}

	if runAsRelay {
		runServer()
	} else if len(serverAddress) != 0 {
		runClient(connectionTypeFlag, codePhraseFlag)
	} else {
		fmt.Println("You must specify either -file (for running as a server) or -server (for running as a client)")
	}
}

func getInput(prompt string) string {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print(prompt)
	text, _ := reader.ReadString('\n')
	return strings.TrimSpace(text)
}
<|endoftext|>