<commit_before>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/mux"
	"github.com/teambrookie/showrss/betaseries"
	"github.com/teambrookie/showrss/dao"
	"github.com/teambrookie/showrss/handlers"
	"github.com/teambrookie/showrss/torrent"
	"golang.org/x/oauth2"

	"flag"

	"syscall"

	"strconv"
)

const version = "1.0.0"

func handleNewAuth(newAuth <-chan string, users map[string]bool, refreshLimiter chan<- time.Time) {
	for token := range newAuth {
		if exists := users[token]; !exists {
			users[token] = true
			log.Printf("New user token : %s\n", token)
			refreshLimiter <- time.Now()
		}
	}
}

func searchWorker(jobs <-chan dao.Episode, store dao.EpisodeStore, quality string) {
	for episode := range jobs {
		time.Sleep(2 * time.Second)
		log.Println("Processing : " + episode.Name)
		torrentLink, err := torrent.Search(strconv.Itoa(episode.ShowID), episode.Code, quality)
		log.Println("Result : " + torrentLink)
		if err != nil {
			log.Printf("Error processing %s : %s ...\n", episode.Name, err)
			continue
		}
		if torrentLink == "" {
			continue
		}
		episode.MagnetLink = torrentLink
		episode.LastModified = time.Now()
		err = store.UpdateEpisode(episode)
		if err != nil {
			log.Printf("Error saving %s to DB ...\n", episode.Name)
		}

	}
}

func refresh(limiter <-chan time.Time, users map[string]bool, db dao.EpisodeStore, betaseries betaseries.EpisodeProvider, episodeToSearch chan<- dao.Episode) {
	for {
		<-limiter
		log.Println("Refresh started")
		for user := range users {
			log.Printf("Refresing for user %s\n", user)
			episodes, err := betaseries.Episodes(user)
			if err != nil {
				log.Printf("Error retriving episodes for user %s : %s\n", user, err)
			}
			for _, ep := range episodes {
				err := db.AddEpisode(ep)
				if err != nil {
					log.Printf("Error adding episodes to database: %s", err)
				}
			}
		}
		log.Println("Passing not found episodes to the search worker")
		notFounds, err := db.GetAllNotFoundEpisode()
		if err != nil {
			log.Printf("Error retriving unfound episodes from db : %s\n", err)
		}
		for _, episode := range notFounds {
			episodeToSearch <- episode
		}

	}
}

func main() {

	//Opitional flag for passing the http server address and the db name
	var dbAddr = flag.String("db", "showrss.db", "DB address")
	flag.Parse()

	//API key and secret for Betaseries are retrieve from the environnement variables
	apiKey := os.Getenv("BETASERIES_KEY")
	if apiKey == "" {
		log.Fatalln("BETASERIES_KEY must be set in env")
	}

	apiSecret := os.Getenv("BETASERIES_SECRET")
	if apiSecret == "" {
		log.Fatalln("BETASERIES_SECRET must be set in env")
	}

	// The quality can be specified using an environnement variable
	quality := os.Getenv("SHOWRSS_QUALITY")
	if quality == "" {
		quality = "720p"
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "7777"
	}

	//workaround for Heroku
	// must enable runtime-dyno-metadata
	//with heroku labs:enable runtime-dyno-metadata -a <app name>
	hostname := os.Getenv("HEROKU_APP_NAME")
	host := fmt.Sprintf("http://%s.herokuapp.com", hostname)

	if hostname == "" {
		hostname, _ = os.Hostname()
		host = fmt.Sprintf("http://%s:%s", hostname, port)
	}
	redirectURL := fmt.Sprintf("%s/auth_callback", host)

	// Configuration for the Oauth authentification with Betaseries
	conf := &oauth2.Config{
		ClientID:     apiKey,
		ClientSecret: apiSecret,
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://www.betaseries.com/authorize",
			TokenURL: "https://api.betaseries.com/oauth/access_token",
		},
		RedirectURL: redirectURL,
	}

	episodeProvider := betaseries.Betaseries{APIKey: apiKey}

	log.Println("Starting server ...")
	log.Println("Connecting to db ...")

	//DB stuff
	store, err := dao.InitDB(*dbAddr)
	if err != nil {
		log.Fatalln("Error connecting to DB")
	}

	err = store.CreateBucket("episodes")
	if err != nil {
		log.Fatalln("Error when creating bucket")
	}

	// Worker stuff
	// A channel is used to pass the episode that we need to search
	episodeToSearch := make(chan dao.Episode, 1000)
	//searchWorker read the episode to search from the channel and if it found them save them in the db
	go searchWorker(episodeToSearch, store, quality)

	refreshLimiter := make(chan time.Time, 10)
	go func() {
		for t := range time.Tick(time.Hour * 1) {
			refreshLimiter <- t
		}
	}()

	// we use a map to store the users because why not (we only store the token for each user si that we can refresh the unseen episodes from Betaseries)
	users := make(map[string]bool)
	newAuthChan := make(chan string, 10)
	go handleNewAuth(newAuthChan, users, refreshLimiter)

	go refresh(refreshLimiter, users, store, episodeProvider, episodeToSearch)

	errChan := make(chan error, 10)

	mux := mux.NewRouter()
	mux.HandleFunc("/", handlers.HelloHandler)
	mux.Handle("/auth", handlers.OauthHandler(conf))
	mux.Handle("/auth_callback", handlers.AuthCallbackHandler(conf, newAuthChan, host))
	mux.Handle("/episodes", handlers.EpisodeHandler(store))
	mux.Handle("/rss/{user}", handlers.RSSHandler(store, episodeProvider))

	httpServer := http.Server{}
	httpServer.Addr = ":" + port
	httpServer.Handler = handlers.LoggingHandler(mux)

	log.Printf("HTTP service listening on %s", host)

	go func() {
		errChan <- httpServer.ListenAndServe()
	}()

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Fatal(err)
			}
		case s := <-signalChan:
			log.Println(fmt.Sprintf("Captured %v. Exiting...", s))
			httpServer.Shutdown(context.Background())
			os.Exit(0)
		}
	}

}
<commit_msg>show me the money<commit_after>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/mux"
	"github.com/teambrookie/showrss/betaseries"
	"github.com/teambrookie/showrss/dao"
	"github.com/teambrookie/showrss/handlers"
	"github.com/teambrookie/showrss/torrent"
	"golang.org/x/oauth2"

	"flag"

	"syscall"

	"strconv"
)

const version = "1.0.0"

func handleNewAuth(newAuth <-chan string, users map[string]bool, refreshLimiter chan<- time.Time) {
	for token := range newAuth {
		if exists := users[token]; !exists {
			users[token] = true
			log.Printf("New user token : %s\n", token)
			refreshLimiter <- time.Now()
		}
	}
}

func searchWorker(jobs <-chan dao.Episode, store dao.EpisodeStore, quality string) {
	for episode := range jobs {
		time.Sleep(2 * time.Second)
		log.Println("Processing : " + episode.Name)
		torrentLink, err := torrent.Search(strconv.Itoa(episode.ShowID), episode.Code, quality)
		log.Println("Result : " + torrentLink)
		if err != nil {
			log.Printf("Error processing %s : %s ...\n", episode.Name, err)
			continue
		}
		if torrentLink == "" {
			continue
		}
		episode.MagnetLink = torrentLink
		episode.LastModified = time.Now()
		err = store.UpdateEpisode(episode)
		if err != nil {
			log.Printf("Error saving %s to DB ...\n", episode.Name)
		}

	}
}

func refresh(limiter <-chan time.Time, users map[string]bool, db dao.EpisodeStore, betaseries betaseries.EpisodeProvider, episodeToSearch chan<- dao.Episode) {
	for {
		<-limiter
		log.Println("Refresh started")
		for user := range users {
			log.Printf("Refresing for user %s\n", user)
			episodes, err := betaseries.Episodes(user)
			if err != nil {
				log.Printf("Error retriving episodes for user %s : %s\n", user, err)
			}
			for _, ep := range episodes {
				err := db.AddEpisode(ep)
				if err != nil {
					log.Printf("Error adding episodes to database: %s", err)
				}
			}
		}
		log.Println("Passing not found episodes to the search worker")
		notFounds, err := db.GetAllNotFoundEpisode()
		if err != nil {
			log.Printf("Error retriving unfound episodes from db : %s\n", err)
		}
		for _, episode := range notFounds {
			episodeToSearch <- episode
		}

	}
}

func main() {

	//Opitional flag for passing the http server address and the db name
	var dbAddr = flag.String("db", "showrss.db", "DB address")
	flag.Parse()

	//API key and secret for Betaseries are retrieve from the environnement variables
	apiKey := os.Getenv("BETASERIES_KEY")
	if apiKey == "" {
		log.Fatalln("BETASERIES_KEY must be set in env")
	}

	apiSecret := os.Getenv("BETASERIES_SECRET")
	if apiSecret == "" {
		log.Fatalln("BETASERIES_SECRET must be set in env")
	}

	// The quality can be specified using an environnement variable
	quality := os.Getenv("SHOWRSS_QUALITY")
	if quality == "" {
		quality = "720p"
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "7777"
	}

	//workaround for Heroku
	// must enable runtime-dyno-metadata
	//with heroku labs:enable runtime-dyno-metadata -a <app name>
	hostname := os.Getenv("HEROKU_APP_NAME")
	host := fmt.Sprintf("http://%s.herokuapp.com", hostname)

	if hostname == "" {
		hostname, _ = os.Hostname()
		host = fmt.Sprintf("http://%s:%s", hostname, port)
	}
	redirectURL := fmt.Sprintf("%s/auth_callback", host)

	log.Println(redirectURL)

	// Configuration for the Oauth authentification with Betaseries
	conf := &oauth2.Config{
		ClientID:     apiKey,
		ClientSecret: apiSecret,
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://www.betaseries.com/authorize",
			TokenURL: "https://api.betaseries.com/oauth/access_token",
		},
		RedirectURL: redirectURL,
	}

	episodeProvider := betaseries.Betaseries{APIKey: apiKey}

	log.Println("Starting server ...")
	log.Println("Connecting to db ...")

	//DB stuff
	store, err := dao.InitDB(*dbAddr)
	if err != nil {
		log.Fatalln("Error connecting to DB")
	}

	err = store.CreateBucket("episodes")
	if err != nil {
		log.Fatalln("Error when creating bucket")
	}

	// Worker stuff
	// A channel is used to pass the episode that we need to search
	episodeToSearch := make(chan dao.Episode, 1000)
	//searchWorker read the episode to search from the channel and if it found them save them in the db
	go searchWorker(episodeToSearch, store, quality)

	refreshLimiter := make(chan time.Time, 10)
	go func() {
		for t := range time.Tick(time.Hour * 1) {
			refreshLimiter <- t
		}
	}()

	// we use a map to store the users because why not (we only store the token for each user si that we can refresh the unseen episodes from Betaseries)
	users := make(map[string]bool)
	newAuthChan := make(chan string, 10)
	go handleNewAuth(newAuthChan, users, refreshLimiter)

	go refresh(refreshLimiter, users, store, episodeProvider, episodeToSearch)

	errChan := make(chan error, 10)

	mux := mux.NewRouter()
	mux.HandleFunc("/", handlers.HelloHandler)
	mux.Handle("/auth", handlers.OauthHandler(conf))
	mux.Handle("/auth_callback", handlers.AuthCallbackHandler(conf, newAuthChan, host))
	mux.Handle("/episodes", handlers.EpisodeHandler(store))
	mux.Handle("/rss/{user}", handlers.RSSHandler(store, episodeProvider))

	httpServer := http.Server{}
	httpServer.Addr = ":" + port
	httpServer.Handler = handlers.LoggingHandler(mux)

	log.Printf("HTTP service listening on %s", host)

	go func() {
		errChan <- httpServer.ListenAndServe()
	}()

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Fatal(err)
			}
		case s := <-signalChan:
			log.Println(fmt.Sprintf("Captured %v. Exiting...", s))
			httpServer.Shutdown(context.Background())
			os.Exit(0)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"fmt"

	"github.com/phrase/phraseapp-client/Godeps/_workspace/src/github.com/dynport/dgtk/cli"
	"github.com/phrase/phraseapp-client/Godeps/_workspace/src/github.com/phrase/phraseapp-go/phraseapp"
)

func main() {
	Run()
}

func Run() {
	var cfg *phraseapp.Config
	defer func() {
		if recovery := recover(); recovery != nil {
			ReportError("PhraseApp Client Error", recovery, cfg)
			printErr(fmt.Errorf("This should not have happened: %s - Contact support: support@phraseapp.com", recovery))
			os.Exit(1)
		}
	}()

	phraseapp.ClientVersion = PHRASEAPP_CLIENT_VERSION
	ValidateVersion()

	cfg, err := phraseapp.ReadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(2)
	}

	r, err := router(cfg)
	if err != nil {
		printErr(err)
		os.Exit(3)
	}

	switch err := r.RunWithArgs(); err {
	case cli.ErrorHelpRequested, cli.ErrorNoRoute:
		os.Exit(1)
	case nil:
		os.Exit(0)
	default:
		printErr(err)
		os.Exit(1)
	}
}
<commit_msg>errors/bugsnag: testing for dev version before reporting error<commit_after>package main

import (
	"os"

	"fmt"

	"github.com/phrase/phraseapp-client/Godeps/_workspace/src/github.com/dynport/dgtk/cli"
	"github.com/phrase/phraseapp-client/Godeps/_workspace/src/github.com/phrase/phraseapp-go/phraseapp"
)

func main() {
	Run()
}

func Run() {
	var cfg *phraseapp.Config
	defer func() {
		if recovery := recover(); recovery != nil {
			if PHRASEAPP_CLIENT_VERSION != "DEV" {
				ReportError("PhraseApp Client Error", recovery, cfg)
			}
			printErr(fmt.Errorf("This should not have happened: %s - Contact support: support@phraseapp.com", recovery))
			os.Exit(1)
		}
	}()

	phraseapp.ClientVersion = PHRASEAPP_CLIENT_VERSION
	ValidateVersion()

	cfg, err := phraseapp.ReadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(2)
	}

	r, err := router(cfg)
	if err != nil {
		printErr(err)
		os.Exit(3)
	}

	switch err := r.RunWithArgs(); err {
	case cli.ErrorHelpRequested, cli.ErrorNoRoute:
		os.Exit(1)
	case nil:
		os.Exit(0)
	default:
		printErr(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/tls"
	"database/sql"
	"fmt"
	"html/template"
	"log"
	mathRand "math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/NYTimes/gziphandler"
	"golang.org/x/crypto/acme/autocert"
)

//go:generate esc -private -o bindata.go -prefix static ./views ./static/
var templates = template.New("").Funcs(template.FuncMap{"add": func(a, b int) int { return a + b }})
var templateSources = []string{
	"/views/main.tmpl",
	"/views/_util.tmpl",
	"/views/geekhack.tmpl",
}

var hostname_whitelist = []string{
	"www.sadbox.org", "sadbox.org", "mail.sadbox.org",
	"www.sadbox.es", "sadbox.es",
	"www.geekwhack.org", "geekwhack.org",
	"www.sadbox.xyz", "sadbox.xyz",
}

var sadboxDB *sql.DB

var channels []channel

type channel struct {
	LinkName    string
	ChannelName string
}

type WebsiteName struct {
	Title, Brand string
}

type Main struct {
	Channels []channel
}

type TemplateContext struct {
	Geekhack *Geekhack
	Webname  *WebsiteName
	Main     *Main
}

func NewContext(r *http.Request, appendToTitle string) *TemplateContext {
	title := "sadbox \u00B7 org"
	host := "sadbox.org"
	for _, v := range hostname_whitelist {
		if v == r.Host {
			trimmed := strings.TrimPrefix(r.Host, "www.")
			title = strings.Replace(trimmed, ".", " \u00B7 ", -1)
			host = trimmed
			break
		}
	}
	return &TemplateContext{
		Webname: &WebsiteName{
			title + " - " + appendToTitle,
			host,
		},
	}
}

func CatchPanic(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Recovered from panic: %v", r)
				http.Error(w, "Something went wrong!", http.StatusInternalServerError)
			}
		}()

		handler.ServeHTTP(w, r)
	})
}

func SendToHTTPS(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Connection", "close")
	http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
}

func RedirectToHTTPS(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.Host)

		// Don't bother sending IPs to https
		ip := net.ParseIP(r.Host)
		if ip != nil {
			handler.ServeHTTP(w, r)
			return
		}

		// If r.Host isn't an ip, maybe it's an ip:port?
		host, _, err := net.SplitHostPort(r.Host)
		if err != nil {
			SendToHTTPS(w, r)
			return
		}
		if ip = net.ParseIP(host); ip == nil { // Couldn't parse the split ip
			SendToHTTPS(w, r)
			return
		}

		handler.ServeHTTP(w, r)
	})
}

func AddHeaders(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=120")
		if r.URL.Scheme == "https" {
			w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
		}
		w.Header().Set("Content-Security-Policy", "default-src 'self'; object-src 'none'; frame-ancestors 'none'")
		w.Header().Set("X-Frame-Options", "DENY")
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("Referrer-Policy", "no-referrer, same-origin")
		w.Header().Set("X-XSS-Protection", "1; mode=block")
		handler.ServeHTTP(w, r)
	})
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteHost := r.Header.Get("X-Forwarded-For")
		if remoteHost == "" {
			remoteHost = r.RemoteAddr
		}
		log.Printf("%s %s %s", remoteHost, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

type sessionKeys struct {
	keys [][32]byte
	buf  []byte
	tls  *tls.Config
}

func NewSessionKeys(tls *tls.Config) *sessionKeys {
	sk := &sessionKeys{
		buf: make([]byte, 32),
		tls: tls,
	}
	sk.addNewKey()
	return sk
}

func (sk *sessionKeys) addNewKey() {
	rand.Read(sk.buf)
	newKey := [32]byte{}
	copy(newKey[:], sk.buf)
	sk.keys = append([][32]byte{newKey}, sk.keys...)
	if len(sk.keys) > 4 {
		sk.keys = sk.keys[:5]
	}
	log.Println("Rotating Session Keys")
	sk.tls.SetSessionTicketKeys(sk.keys)
}

func (sk *sessionKeys) Spin() {
	for range time.Tick(24 * time.Hour) {
		sk.addNewKey()
	}
}

func main() {
	log.Println("Starting sadbox.org")

	for _, filename := range templateSources {
		template.Must(templates.Parse(_escFSMustString(false, filename)))
	}

	var err error
	sadboxDB, err = sql.Open("mysql", os.Getenv("GEEKHACK_DB"))
	if err != nil {
		log.Fatal(err)
	}
	defer sadboxDB.Close()

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

	staticFileServer := http.FileServer(_escFS(false))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			ctx := NewContext(r, "home")
			ctx.Main = &Main{channels}
			if err := templates.ExecuteTemplate(w, "main", ctx); err != nil {
				log.Println(err)
			}
		} else {
			staticFileServer.ServeHTTP(w, r)
		}
	})

	mathRand.Seed(time.Now().UnixNano())

	rows, err := sadboxDB.Query(`SELECT Channel from Channels;`)
	if err != nil {
		log.Fatal(err)
	}
	for rows.Next() {
		var channelName string
		err := rows.Scan(&channelName)
		if err != nil {
			log.Fatal(err)
		}

		chanInfo := channel{fmt.Sprintf("/%s/", strings.Trim(channelName, "#")), channelName}

		ircChanHandler, err := NewIRCChannel(chanInfo)
		if err != nil {
			log.Fatal(err)
		}
		http.Handle(chanInfo.LinkName, ircChanHandler)

		channels = append(channels, chanInfo)
	}

	// Redirects to the right URL so I don't break old links
	http.Handle("/ghstats", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))
	http.Handle("/geekhack", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))

	// This will redirect people to the gmail page
	http.Handle("mail.sadbox.org/", http.RedirectHandler("https://mail.google.com/a/sadbox.org", http.StatusFound))

	localhost_znc, err := url.Parse("http://127.0.0.1:6698")
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/znc/", httputil.NewSingleHostReverseProxy(localhost_znc))
	http.Handle("/znc", http.RedirectHandler("/znc/", http.StatusMovedPermanently))

	servemux := gziphandler.GzipHandler(
		CatchPanic(
			Log(
				AddHeaders(http.DefaultServeMux))))

	m := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		Cache:      autocert.DirCache("/home/sadbox-web/cert-cache"),
		HostPolicy: autocert.HostWhitelist(hostname_whitelist...),
		Email:      "blue6249@gmail.com",
		ForceRSA:   true,
	}

	var certs []tls.Certificate
	sadboxCert, err := tls.LoadX509KeyPair("/home/sadbox-web/cert-cache/sadbox.org",
		"/home/sadbox-web/cert-cache/sadbox.org")

	if err == nil {
		certs = append(certs, sadboxCert)
	}

	tlsconfig := &tls.Config{
		PreferServerCipherSuites: true,
		GetCertificate:           m.GetCertificate,
		Certificates:             certs,
	}

	go NewSessionKeys(tlsconfig).Spin()

	httpSrv := &http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
		Handler:      m.HTTPHandler(RedirectToHTTPS(servemux)),
	}
	go func() { log.Fatal(httpSrv.ListenAndServe()) }()

	server := &http.Server{
		Addr:         ":https",
		Handler:      servemux,
		TLSConfig:    tlsconfig,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}
	log.Fatal(server.ListenAndServeTLS("", ""))
}
<commit_msg>fix for ipv6 + correctly detect https<commit_after>package main

import (
	"crypto/rand"
	"crypto/tls"
	"database/sql"
	"fmt"
	"html/template"
	"log"
	mathRand "math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/NYTimes/gziphandler"
	"golang.org/x/crypto/acme/autocert"
)

//go:generate esc -private -o bindata.go -prefix static ./views ./static/
var templates = template.New("").Funcs(template.FuncMap{"add": func(a, b int) int { return a + b }})
var templateSources = []string{
	"/views/main.tmpl",
	"/views/_util.tmpl",
	"/views/geekhack.tmpl",
}

var hostname_whitelist = []string{
	"www.sadbox.org", "sadbox.org", "mail.sadbox.org",
	"www.sadbox.es", "sadbox.es",
	"www.geekwhack.org", "geekwhack.org",
	"www.sadbox.xyz", "sadbox.xyz",
}

var sadboxDB *sql.DB

var channels []channel

type channel struct {
	LinkName    string
	ChannelName string
}

type WebsiteName struct {
	Title, Brand string
}

type Main struct {
	Channels []channel
}

type TemplateContext struct {
	Geekhack *Geekhack
	Webname  *WebsiteName
	Main     *Main
}

func NewContext(r *http.Request, appendToTitle string) *TemplateContext {
	title := "sadbox \u00B7 org"
	host := "sadbox.org"
	for _, v := range hostname_whitelist {
		if v == r.Host {
			trimmed := strings.TrimPrefix(r.Host, "www.")
			title = strings.Replace(trimmed, ".", " \u00B7 ", -1)
			host = trimmed
			break
		}
	}
	return &TemplateContext{
		Webname: &WebsiteName{
			title + " - " + appendToTitle,
			host,
		},
	}
}

func CatchPanic(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Recovered from panic: %v", r)
				http.Error(w, "Something went wrong!", http.StatusInternalServerError)
			}
		}()

		handler.ServeHTTP(w, r)
	})
}

func SendToHTTPS(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Connection", "close")
	http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
}

func RedirectToHTTPS(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.Host)

		// Don't bother sending IPs to https
		ip := net.ParseIP(strings.Trim(r.Host, "[]"))
		if ip != nil {
			handler.ServeHTTP(w, r)
			return
		}

		// If r.Host isn't an ip, maybe it's an ip:port?
		host, _, err := net.SplitHostPort(r.Host)
		if err != nil {
			SendToHTTPS(w, r)
			return
		}
		if ip = net.ParseIP(host); ip == nil { // Couldn't parse the split ip
			SendToHTTPS(w, r)
			return
		}

		handler.ServeHTTP(w, r)
	})
}

func AddHeaders(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=120")
		if r.TLS != nil {
			w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
		}
		w.Header().Set("Content-Security-Policy", "default-src 'self'; object-src 'none'; frame-ancestors 'none'")
		w.Header().Set("X-Frame-Options", "DENY")
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("Referrer-Policy", "no-referrer, same-origin")
		w.Header().Set("X-XSS-Protection", "1; mode=block")
		handler.ServeHTTP(w, r)
	})
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteHost := r.Header.Get("X-Forwarded-For")
		if remoteHost == "" {
			remoteHost = r.RemoteAddr
		}
		log.Printf("%s %s %s", remoteHost, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

type sessionKeys struct {
	keys [][32]byte
	buf  []byte
	tls  *tls.Config
}

func NewSessionKeys(tls *tls.Config) *sessionKeys {
	sk := &sessionKeys{
		buf: make([]byte, 32),
		tls: tls,
	}
	sk.addNewKey()
	return sk
}

func (sk *sessionKeys) addNewKey() {
	rand.Read(sk.buf)
	newKey := [32]byte{}
	copy(newKey[:], sk.buf)
	sk.keys = append([][32]byte{newKey}, sk.keys...)
	if len(sk.keys) > 4 {
		sk.keys = sk.keys[:5]
	}
	log.Println("Rotating Session Keys")
	sk.tls.SetSessionTicketKeys(sk.keys)
}

func (sk *sessionKeys) Spin() {
	for range time.Tick(24 * time.Hour) {
		sk.addNewKey()
	}
}

func main() {
	log.Println("Starting sadbox.org")

	for _, filename := range templateSources {
		template.Must(templates.Parse(_escFSMustString(false, filename)))
	}

	var err error
	sadboxDB, err = sql.Open("mysql", os.Getenv("GEEKHACK_DB"))
	if err != nil {
		log.Fatal(err)
	}
	defer sadboxDB.Close()

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

	staticFileServer := http.FileServer(_escFS(false))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			ctx := NewContext(r, "home")
			ctx.Main = &Main{channels}
			if err := templates.ExecuteTemplate(w, "main", ctx); err != nil {
				log.Println(err)
			}
		} else {
			staticFileServer.ServeHTTP(w, r)
		}
	})

	mathRand.Seed(time.Now().UnixNano())

	rows, err := sadboxDB.Query(`SELECT Channel from Channels;`)
	if err != nil {
		log.Fatal(err)
	}
	for rows.Next() {
		var channelName string
		err := rows.Scan(&channelName)
		if err != nil {
			log.Fatal(err)
		}

		chanInfo := channel{fmt.Sprintf("/%s/", strings.Trim(channelName, "#")), channelName}

		ircChanHandler, err := NewIRCChannel(chanInfo)
		if err != nil {
			log.Fatal(err)
		}
		http.Handle(chanInfo.LinkName, ircChanHandler)

		channels = append(channels, chanInfo)
	}

	// Redirects to the right URL so I don't break old links
	http.Handle("/ghstats", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))
	http.Handle("/geekhack", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))

	// This will redirect people to the gmail page
	http.Handle("mail.sadbox.org/", http.RedirectHandler("https://mail.google.com/a/sadbox.org", http.StatusFound))

	localhost_znc, err := url.Parse("http://127.0.0.1:6698")
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/znc/", httputil.NewSingleHostReverseProxy(localhost_znc))
	http.Handle("/znc", http.RedirectHandler("/znc/", http.StatusMovedPermanently))

	servemux := gziphandler.GzipHandler(
		CatchPanic(
			Log(
				AddHeaders(http.DefaultServeMux))))

	m := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		Cache:      autocert.DirCache("/home/sadbox-web/cert-cache"),
		HostPolicy: autocert.HostWhitelist(hostname_whitelist...),
		Email:      "blue6249@gmail.com",
		ForceRSA:   true,
	}

	var certs []tls.Certificate
	sadboxCert, err := tls.LoadX509KeyPair("/home/sadbox-web/cert-cache/sadbox.org",
		"/home/sadbox-web/cert-cache/sadbox.org")

	if err == nil {
		certs = append(certs, sadboxCert)
	}

	tlsconfig := &tls.Config{
		PreferServerCipherSuites: true,
		GetCertificate:           m.GetCertificate,
		Certificates:             certs,
	}

	go NewSessionKeys(tlsconfig).Spin()

	httpSrv := &http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
		Handler:      m.HTTPHandler(RedirectToHTTPS(servemux)),
	}
	go func() { log.Fatal(httpSrv.ListenAndServe()) }()

	server := &http.Server{
		Addr:         ":https",
		Handler:      servemux,
		TLSConfig:    tlsconfig,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}
	log.Fatal(server.ListenAndServeTLS("", ""))
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/gorilla/mux"
)

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteAddr := r.RemoteAddr
		if len(remoteAddr) == 0 {
			remoteAddr = r.Header.Get("x-forwarded-for")
		}
		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

var db SparkleDatabase

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/sparkles", addSparkle).Methods("POST")
	r.HandleFunc("/sparkles", getSparkles).Methods("GET")
	r.HandleFunc("/top/giver", topGiven).Methods("GET")
	r.HandleFunc("/top/receiver", topReceived).Methods("GET")
	r.HandleFunc("/sparkles/{recipient}", getSparklesForRecipient).Methods("GET")
	r.HandleFunc("/migrate/{from}/{to}", migrateSparkles)
	r.HandleFunc("/graph", getSparkleGraph).Methods("GET")
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))
	// Load the database from file
	db = LoadDB()

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "8080"
	}

	http.Handle("/", r)
	log.Printf("[+] Starting the sparkles app on port %s", port)
	http.ListenAndServe(":"+port, Log(http.DefaultServeMux))
}
<commit_msg>Fixed commenting<commit_after>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/gorilla/mux"
)

// Log what's up
func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteAddr := r.RemoteAddr
		if len(remoteAddr) == 0 {
			remoteAddr = r.Header.Get("x-forwarded-for")
		}
		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

var db SparkleDatabase

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/sparkles", addSparkle).Methods("POST")
	r.HandleFunc("/sparkles", getSparkles).Methods("GET")
	r.HandleFunc("/top/giver", topGiven).Methods("GET")
	r.HandleFunc("/top/receiver", topReceived).Methods("GET")
	r.HandleFunc("/sparkles/{recipient}", getSparklesForRecipient).Methods("GET")
	r.HandleFunc("/migrate/{from}/{to}", migrateSparkles)
	r.HandleFunc("/graph", getSparkleGraph).Methods("GET")
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))
	// Load the database from file
	db = LoadDB()

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "8080"
	}

	http.Handle("/", r)
	log.Printf("[+] Starting the sparkles app on port %s", port)
	http.ListenAndServe(":"+port, Log(http.DefaultServeMux))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/aodin/date"
	"net/http"
	"trello-bot/slack"
	"trello-bot/trello"
)

var globalConfig Config

func main() {

	globalConfig = LoadConfig("config.json")

	trello.Authenticate(trello.TrelloConfig{
		Key:              globalConfig.TrelloKey,
		Token:            globalConfig.TrelloToken,
		User:             globalConfig.TrelloUser,
		Board:            globalConfig.BoardName,
		StartingListName: globalConfig.StartListName,
		FinishedListName: globalConfig.FinishedListName,
		NotifyChannel:    globalConfig.NotifyChannel})

	slack.Authenticate(globalConfig.SlackToken)

	go trello.SetupWebhooks(globalConfig.ListenURL)
	http.HandleFunc("/trello_webhook", trello.WebhookHandler)
	listen := fmt.Sprintf(":%v", globalConfig.Port)
	fmt.Println("Starting server...")
	http.ListenAndServe(listen, nil)
}

func reportHandler(w http.ResponseWriter, r *http.Request) {

	fmt.Println("Loading Report")
	report, err := trello.CompletedReport(date.NewRange(date.Today().AddDays(globalConfig.ReportDays), date.Today()), globalConfig.ReportLists)
	if err != nil {
		fmt.Fprintln(w, "Error loading report")
		return
	}
	fmt.Fprintln(w, report)
}
<commit_msg>Serve report endpoint at random path<commit_after>package main

import (
	"fmt"
	"github.com/aodin/date"
	"net/http"
	"trello-bot/slack"
	"trello-bot/trello"
)

var globalConfig Config

func main() {

	globalConfig = LoadConfig("config.json")

	trello.Authenticate(trello.TrelloConfig{
		Key:              globalConfig.TrelloKey,
		Token:            globalConfig.TrelloToken,
		User:             globalConfig.TrelloUser,
		Board:            globalConfig.BoardName,
		StartingListName: globalConfig.StartListName,
		FinishedListName: globalConfig.FinishedListName,
		NotifyChannel:    globalConfig.NotifyChannel})

	slack.Authenticate(globalConfig.SlackToken)

	go trello.SetupWebhooks(globalConfig.ListenURL)
	http.HandleFunc("/trello_webhook", trello.WebhookHandler)
	uid := RandomizeUID()
	err := slack.TryMessageChannelName(globalConfig.InfoChannel, fmt.Sprint("Trellobot report URL is ", globalConfig.ListenURL+"/"+uid))
	fmt.Println("Error sending report URL:", err)
	http.HandleFunc("/"+uid, reportHandler)
	listen := fmt.Sprintf(":%v", globalConfig.Port)
	fmt.Println("Starting server...")
	http.ListenAndServe(listen, nil)
}

func reportHandler(w http.ResponseWriter, r *http.Request) {

	fmt.Println("Loading Report")
	report, err := trello.CompletedReport(date.NewRange(date.Today().AddDays(globalConfig.ReportDays), date.Today()), globalConfig.ReportLists)
	if err != nil {
		fmt.Fprintln(w, "Error loading report")
		return
	}
	fmt.Fprintln(w, report)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/voxelbrain/goptions"
	"labix.org/v2/mgo"
	"log"
	"net"
	"net/http"
	"net/url"
)

var options = struct {
	MongoURL         *url.URL     `goptions:"-m, --mongodb, description='MongoDB URL to connect to (example: mongodb://localhost/db)', obligatory"`
	CollectionPrefix string       `goptions:"-c, --collection, description='Prefix of GridFS collection name'"`
	PathPrefix       string       `goptions:"-p, --prefix, description='Prefix applied to all request paths'"`
	Address          *net.TCPAddr `goptions:"-a, --address, description='Address to bind webserver to'"`
	Verbosity        []bool       `goptions:"-v, --verbose, description='Increase verbosity'"`
	goptions.Help    `goptions:"-h, --help, description='Show this help'"`
}{
	CollectionPrefix: "fs",
	Address: &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: 8080,
	},
}

func init() {
	goptions.ParseAndFail(&options)
}

func main() {
	session, err := mgo.Dial(options.MongoURL.String())
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}

	db := session.DB("") // Use DB name from the URL
	gd := &GridDir{
		PathPrefix: options.PathPrefix,
		GridFS:     db.GridFS(options.CollectionPrefix),
	}
	levelLogf(LOG_INFO, "Starting server...")
	http.Handle("/", http.FileServer(gd))

	log.Fatalf("ListenAndServe: %s", http.ListenAndServe(options.Address.String(), nil))
}
<commit_msg>Add copyright note<commit_after>// gridfsd - GridFS HTTP Server
//
// Copyright (c) 2011-2012 voxelbrain UG (haftungsbeschränkt)
// Authors:
//     Sebastian Friedel <sef@voxelbrain.com>
//     David Lehmann <dtl@voxelbrain.com>
//     Alexander Surma <asu@voxelbrain.com>
//
// All rights reserved.
package main

import (
	"github.com/voxelbrain/goptions"
	"labix.org/v2/mgo"
	"log"
	"net"
	"net/http"
	"net/url"
)

var options = struct {
	MongoURL         *url.URL     `goptions:"-m, --mongodb, description='MongoDB URL to connect to (example: mongodb://localhost/db)', obligatory"`
	CollectionPrefix string       `goptions:"-c, --collection, description='Prefix of GridFS collection name'"`
	PathPrefix       string       `goptions:"-p, --prefix, description='Prefix applied to all request paths'"`
	Address          *net.TCPAddr `goptions:"-a, --address, description='Address to bind webserver to'"`
	Verbosity        []bool       `goptions:"-v, --verbose, description='Increase verbosity'"`
	goptions.Help    `goptions:"-h, --help, description='Show this help'"`
}{
	CollectionPrefix: "fs",
	Address: &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: 8080,
	},
}

func init() {
	goptions.ParseAndFail(&options)
}

func main() {
	session, err := mgo.Dial(options.MongoURL.String())
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}

	db := session.DB("") // Use DB name from the URL
	gd := &GridDir{
		PathPrefix: options.PathPrefix,
		GridFS:     db.GridFS(options.CollectionPrefix),
	}
	levelLogf(LOG_INFO, "Starting server...")
	http.Handle("/", http.FileServer(gd))

	log.Fatalf("ListenAndServe: %s", http.ListenAndServe(options.Address.String(), nil))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	version   = "0.5.2"
	github    = "https://github.com/ekalinin/awsping"
	useragent = fmt.Sprintf("AwsPing/%s (+%s)", version, github)
)

var (
	repeats = flag.Int("repeats", 1, "Number of repeats")
	useHTTP = flag.Bool("http", false, "Use http transport (default is tcp)")
	showVer = flag.Bool("v", false, "Show version")
	verbose = flag.Int("verbose", 0, "Verbosity level")
	service = flag.String("service", "dynamodb", "AWS Service: ec2, sdb, sns, sqs, ...")
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// Duration2ms converts time.Duration to ms (float64)
func Duration2ms(d time.Duration) float64 {
	return float64(d.Nanoseconds()) / 1000 / 1000
}

func mkRandoString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

// AWSRegion description of the AWS EC2 region
type AWSRegion struct {
	Name      string
	Code      string
	Service   string
	Latencies []time.Duration
	Error     error
}

// CheckLatencyHTTP Test Latency via HTTP
func (r *AWSRegion) CheckLatencyHTTP(wg *sync.WaitGroup) {
	defer wg.Done()
	url := fmt.Sprintf("http://%s.%s.amazonaws.com/ping?x=%s", r.Service,
		r.Code, mkRandoString(13))
	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("User-Agent", useragent)

	start := time.Now()
	resp, err := client.Do(req)
	r.Latencies = append(r.Latencies, time.Since(start))
	defer resp.Body.Close()

	r.Error = err
}

// CheckLatencyTCP Test Latency via TCP
func (r *AWSRegion) CheckLatencyTCP(wg *sync.WaitGroup) {
	defer wg.Done()
	tcpURI := fmt.Sprintf("%s.%s.amazonaws.com:80", r.Service, r.Code)
	tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpURI)
	if err != nil {
		r.Error = err
		return
	}
	start := time.Now()
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		r.Error = err
		return
	}
	r.Latencies = append(r.Latencies, time.Since(start))
	defer conn.Close()

	r.Error = err
}

// GetLatency returns Latency in ms
func (r *AWSRegion) GetLatency() float64 {
	sum := float64(0)
	for _, l := range r.Latencies {
		sum += Duration2ms(l)
	}
	return sum / float64(len(r.Latencies))
}

// GetLatencyStr returns Latency in string
func (r *AWSRegion) GetLatencyStr() string {
	if r.Error != nil {
		return r.Error.Error()
	}
	return fmt.Sprintf("%.2f ms", r.GetLatency())
}

// AWSRegions slice of the AWSRegion
type AWSRegions []AWSRegion

func (rs AWSRegions) Len() int {
	return len(rs)
}

func (rs AWSRegions) Less(i, j int) bool {
	return rs[i].GetLatency() < rs[j].GetLatency()
}

func (rs AWSRegions) Swap(i, j int) {
	rs[i], rs[j] = rs[j], rs[i]
}

// CalcLatency returns list of aws regions sorted by Latency
func CalcLatency(repeats int, useHTTP bool, service string) *AWSRegions {
	regions := AWSRegions{
		{Service: service, Name: "US-East (Virginia)", Code: "us-east-1"},
		{Service: service, Name: "US-East (Ohio)", Code: "us-east-2"},
		{Service: service, Name: "US-West (California)", Code: "us-west-1"},
		{Service: service, Name: "US-West (Oregon)", Code: "us-west-2"},
		{Service: service, Name: "Canada (Central)", Code: "ca-central-1"},
		{Service: service, Name: "Europe (Ireland)", Code: "eu-west-1"},
		{Service: service, Name: "Europe (Frankfurt)", Code: "eu-central-1"},
		{Service: service, Name: "Europe (London)", Code: "eu-west-2"},
		{Service: service, Name: "Europe (Milan)", Code: "eu-south-1"},
		{Service: service, Name: "Europe (Paris)", Code: "eu-west-3"},
		{Service: service, Name: "Europe (Stockholm)", Code: "eu-north-1"},
		{Service: service, Name: "Africa (Cape Town)", Code: "af-south-1"},
		{Service: service, Name: "Asia Pacific (Osaka-Local)", Code: "ap-northeast-3"},
		{Service: service, Name: "Asia Pacific (Hong Kong)", Code: "ap-east-1"},
		{Service: service, Name: "Asia Pacific (Tokyo)", Code: "ap-northeast-1"},
		{Service: service, Name: "Asia Pacific (Seoul)", Code: "ap-northeast-2"},
		{Service: service, Name: "Asia Pacific (Singapore)", Code: "ap-southeast-1"},
		{Service: service, Name: "Asia Pacific (Mumbai)", Code: "ap-south-1"},
		{Service: service, Name: "Asia Pacific (Sydney)", Code: "ap-southeast-2"},
		{Service: service, Name: "South America (São Paulo)", Code: "sa-east-1"},
		{Service: service, Name: "Middle East (Bahrain)", Code: "me-south-1"},
		{Service: service, Name: "South America (São Paulo)", Code: "sa-east-1"},
	}
	var wg sync.WaitGroup

	for n := 1; n <= repeats; n++ {
		wg.Add(len(regions))
		for i := range regions {
			if useHTTP {
				go regions[i].CheckLatencyHTTP(&wg)
			} else {
				go regions[i].CheckLatencyTCP(&wg)
			}
		}
		wg.Wait()
	}

	sort.Sort(regions)
	return &regions
}

// LatencyOutput prints data into console
type LatencyOutput struct {
	Level int
}

func (lo *LatencyOutput) show0(regions *AWSRegions) {
	for _, r := range *regions {
		fmt.Printf("%-25s %20s\n", r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show1(regions *AWSRegions) {
	outFmt := "%5v %-15s %-30s %20s\n"
	fmt.Printf(outFmt, "", "Code", "Region", "Latency")
	for i, r := range *regions {
		fmt.Printf(outFmt, i, r.Code, r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show2(regions *AWSRegions) {
	// format
	outFmt := "%5v %-15s %-25s"
	outFmt += strings.Repeat(" %15s", *repeats) + " %15s\n"
	// header
	outStr := []interface{}{"", "Code", "Region"}
	for i := 0; i < *repeats; i++ {
		outStr = append(outStr, "Try #"+strconv.Itoa(i+1))
	}
	outStr = append(outStr, "Avg Latency")

	// show header
	fmt.Printf(outFmt, outStr...)

	// each region stats
	for i, r := range *regions {
		outData := []interface{}{strconv.Itoa(i), r.Code, r.Name}
		for n := 0; n < *repeats; n++ {
			outData = append(outData, fmt.Sprintf("%.2f ms",
				Duration2ms(r.Latencies[n])))
		}
		outData = append(outData, fmt.Sprintf("%.2f ms", r.GetLatency()))
		fmt.Printf(outFmt, outData...)
	}
}

// Show print data
func (lo *LatencyOutput) Show(regions *AWSRegions) {
	switch lo.Level {
	case 0:
		lo.show0(regions)
	case 1:
		lo.show1(regions)
	case 2:
		lo.show2(regions)
	}
}

func main() {

	flag.Parse()

	if *showVer {
		fmt.Println(version)
		os.Exit(0)
	}

	regions := CalcLatency(*repeats, *useHTTP, *service)
	lo := LatencyOutput{*verbose}
	lo.Show(regions)
}

func init() {
	rand.Seed(time.Now().UnixNano())
}
<commit_msg>0.6.0<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	version   = "0.6.0"
	github    = "https://github.com/ekalinin/awsping"
	useragent = fmt.Sprintf("AwsPing/%s (+%s)", version, github)
)

var (
	repeats = flag.Int("repeats", 1, "Number of repeats")
	useHTTP = flag.Bool("http", false, "Use http transport (default is tcp)")
	showVer = flag.Bool("v", false, "Show version")
	verbose = flag.Int("verbose", 0, "Verbosity level")
	service = flag.String("service", "dynamodb", "AWS Service: ec2, sdb, sns, sqs, ...")
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// Duration2ms converts time.Duration to ms (float64)
func Duration2ms(d time.Duration) float64 {
	return float64(d.Nanoseconds()) / 1000 / 1000
}

func mkRandoString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

// AWSRegion description of the AWS EC2 region
type AWSRegion struct {
	Name      string
	Code      string
	Service   string
	Latencies []time.Duration
	Error     error
}

// CheckLatencyHTTP Test Latency via HTTP
func (r *AWSRegion) CheckLatencyHTTP(wg *sync.WaitGroup) {
	defer wg.Done()
	url := fmt.Sprintf("http://%s.%s.amazonaws.com/ping?x=%s", r.Service,
		r.Code, mkRandoString(13))
	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("User-Agent", useragent)

	start := time.Now()
	resp, err := client.Do(req)
	r.Latencies = append(r.Latencies, time.Since(start))
	defer resp.Body.Close()

	r.Error = err
}

// CheckLatencyTCP Test Latency via TCP
func (r *AWSRegion) CheckLatencyTCP(wg *sync.WaitGroup) {
	defer wg.Done()
	tcpURI := fmt.Sprintf("%s.%s.amazonaws.com:80", r.Service, r.Code)
	tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpURI)
	if err != nil {
		r.Error = err
		return
	}
	start := time.Now()
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		r.Error = err
		return
	}
	r.Latencies = append(r.Latencies, time.Since(start))
	defer conn.Close()

	r.Error = err
}

// GetLatency returns Latency in ms
func (r *AWSRegion) GetLatency() float64 {
	sum := float64(0)
	for _, l := range r.Latencies {
		sum += Duration2ms(l)
	}
	return sum / float64(len(r.Latencies))
}

// GetLatencyStr returns Latency in string
func (r *AWSRegion) GetLatencyStr() string {
	if r.Error != nil {
		return r.Error.Error()
	}
	return fmt.Sprintf("%.2f ms", r.GetLatency())
}

// AWSRegions slice of the AWSRegion
type AWSRegions []AWSRegion

func (rs AWSRegions) Len() int {
	return len(rs)
}

func (rs AWSRegions) Less(i, j int) bool {
	return rs[i].GetLatency() < rs[j].GetLatency()
}

func (rs AWSRegions) Swap(i, j int) {
	rs[i], rs[j] = rs[j], rs[i]
}

// CalcLatency returns list of aws regions sorted by Latency
func CalcLatency(repeats int, useHTTP bool, service string) *AWSRegions {
	regions := AWSRegions{
		{Service: service, Name: "US-East (Virginia)", Code: "us-east-1"},
		{Service: service, Name: "US-East (Ohio)", Code: "us-east-2"},
		{Service: service, Name: "US-West (California)", Code: "us-west-1"},
		{Service: service, Name: "US-West (Oregon)", Code: "us-west-2"},
		{Service: service, Name: "Canada (Central)", Code: "ca-central-1"},
		{Service: service, Name: "Europe (Ireland)", Code: "eu-west-1"},
		{Service: service, Name: "Europe (Frankfurt)", Code: "eu-central-1"},
		{Service: service, Name: "Europe (London)", Code: "eu-west-2"},
		{Service: service, Name: "Europe (Milan)", Code: "eu-south-1"},
		{Service: service, Name: "Europe (Paris)", Code: "eu-west-3"},
		{Service: service, Name: "Europe (Stockholm)", Code: "eu-north-1"},
		{Service: service, Name: "Africa (Cape Town)", Code: "af-south-1"},
		{Service: service, Name: "Asia Pacific (Osaka-Local)", Code: "ap-northeast-3"},
		{Service: service, Name: "Asia Pacific (Hong Kong)", Code: "ap-east-1"},
		{Service: service, Name: "Asia Pacific (Tokyo)", Code: "ap-northeast-1"},
		{Service: service, Name: "Asia Pacific (Seoul)", Code: "ap-northeast-2"},
		{Service: service, Name: "Asia Pacific (Singapore)", Code: "ap-southeast-1"},
		{Service: service, Name: "Asia Pacific (Mumbai)", Code: "ap-south-1"},
		{Service: service, Name: "Asia Pacific (Sydney)", Code: "ap-southeast-2"},
		{Service: service, Name: "South America (São Paulo)", Code: "sa-east-1"},
		{Service: service, Name: "Middle East (Bahrain)", Code: "me-south-1"},
		{Service: service, Name: "South America (São Paulo)", Code: "sa-east-1"},
	}
	var wg sync.WaitGroup

	for n := 1; n <= repeats; n++ {
		wg.Add(len(regions))
		for i := range regions {
			if useHTTP {
				go regions[i].CheckLatencyHTTP(&wg)
			} else {
				go regions[i].CheckLatencyTCP(&wg)
			}
		}
		wg.Wait()
	}

	sort.Sort(regions)
	return &regions
}

// LatencyOutput prints data into console
type LatencyOutput struct {
	Level int
}

func (lo *LatencyOutput) show0(regions *AWSRegions) {
	for _, r := range *regions {
		fmt.Printf("%-25s %20s\n", r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show1(regions *AWSRegions) {
	outFmt := "%5v %-15s %-30s %20s\n"
	fmt.Printf(outFmt, "", "Code", "Region", "Latency")
	for i, r := range *regions {
		fmt.Printf(outFmt, i, r.Code, r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show2(regions *AWSRegions) {
	// format
	outFmt := "%5v %-15s %-25s"
	outFmt += strings.Repeat(" %15s", *repeats) + " %15s\n"
	// header
	outStr := []interface{}{"", "Code", "Region"}
	for i := 0; i < *repeats; i++ {
		outStr = append(outStr, "Try #"+strconv.Itoa(i+1))
	}
	outStr = append(outStr, "Avg Latency")

	// show header
	fmt.Printf(outFmt, outStr...)

	// each region stats
	for i, r := range *regions {
		outData := []interface{}{strconv.Itoa(i), r.Code, r.Name}
		for n := 0; n < *repeats; n++ {
			outData = append(outData, fmt.Sprintf("%.2f ms",
				Duration2ms(r.Latencies[n])))
		}
		outData = append(outData, fmt.Sprintf("%.2f ms", r.GetLatency()))
		fmt.Printf(outFmt, outData...)
	}
}

// Show print data
func (lo *LatencyOutput) Show(regions *AWSRegions) {
	switch lo.Level {
	case 0:
		lo.show0(regions)
	case 1:
		lo.show1(regions)
	case 2:
		lo.show2(regions)
	}
}

func main() {

	flag.Parse()

	if *showVer {
		fmt.Println(version)
		os.Exit(0)
	}

	regions := CalcLatency(*repeats, *useHTTP, *service)
	lo := LatencyOutput{*verbose}
	lo.Show(regions)
}

func init() {
	rand.Seed(time.Now().UnixNano())
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"net/http"
	"os"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

var (
	db  *sql.DB
	err error
)

type Cost struct {
	Id             int64   `json:"id"`
	ElectricAmount int64   `json:"electric_amount"`
	ElectricPrice  float64 `json:"electric_price"`
	WaterAmount    int64   `json:"water_amount"`
	WaterPrice     float64 `json:"water_price"`
	CheckedDate    string  `json:"checked_date"`
}

func main() {
	db, err = sql.Open("sqlite3", "db.sqlite3")
	if err != nil {
		panic(err)
	}
	defer db.Close()
	// test connection
	err = db.Ping()
	if err != nil {
		panic(err)
	}
	os.Setenv("PORT", "8898")
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	// route
	http.HandleFunc("/", listHandler)
	http.HandleFunc("/list", listHandler)
	http.HandleFunc("/create", createHandler)
	http.HandleFunc("/update", updateHandler)
	http.HandleFunc("/delete", deleteHandler)
	http.Handle("/statics/",
		http.StripPrefix("/statics/", http.FileServer(http.Dir("./statics"))),
	)
	http.ListenAndServe(":" + port, nil)
}
<commit_msg>comment port to run local<commit_after>package main

import (
	"database/sql"
	"net/http"
	"os"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

var (
	db  *sql.DB
	err error
)

type Cost struct {
	Id             int64   `json:"id"`
	ElectricAmount int64   `json:"electric_amount"`
	ElectricPrice  float64 `json:"electric_price"`
	WaterAmount    int64   `json:"water_amount"`
	WaterPrice     float64 `json:"water_price"`
	CheckedDate    string  `json:"checked_date"`
}

func main() {
	db, err = sql.Open("sqlite3", "db.sqlite3")
	if err != nil {
		panic(err)
	}
	defer db.Close()
	// test connection
	err = db.Ping()
	if err != nil {
		panic(err)
	}
	//os.Setenv("PORT", "8898")
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	// route
	http.HandleFunc("/", listHandler)
	http.HandleFunc("/list", listHandler)
	http.HandleFunc("/create", createHandler)
	http.HandleFunc("/update", updateHandler)
	http.HandleFunc("/delete", deleteHandler)
	http.Handle("/statics/",
		http.StripPrefix("/statics/", http.FileServer(http.Dir("./statics"))),
	)
	http.ListenAndServe(":" + port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"fmt"
	"log"
	"net/url"
	"strconv"
)

func main() {

	http.HandleFunc("/api/v1/pledge", handler)
	http.ListenAndServe("localhost:8080", nil)

}

type MethodHandler func(http.ResponseWriter, *http.Request)

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

	handlerMaps := map[string]MethodHandler{
		http.MethodPost: handlePost,
		http.MethodGet:  handleGet,
	}

	fmt.Printf("%v", request)
	v, ok := handlerMaps[request.Method]
	if ! ok {
		unsupportedMethod(writer)
		return
	}
	v(writer, request)
}

func handlePost(writer http.ResponseWriter, request *http.Request) {
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}
	pledge, err := parseRequest(request.Form)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
		return
	}
	fmt.Fprintf(writer, "%v", pledge)
}

func handleGet(writer http.ResponseWriter, request *http.Request) {
	const message = "Welcome"
	fmt.Fprintf(writer, message)
}

type CompanyId string

type ItemId string

type Pledge struct {
	Email     string
	ItemId    ItemId
	CompanyId CompanyId
	Value     int
}

func parseRequest(values url.Values) (Pledge, error) {
	const (
		Type    = "type"
		Company = "company"
		Value   = "value"
		Email   = "email"
	)

	params, ok := extractFormParams(values, Type, Company, Value, Email)
	if ! ok {
		return Pledge{}, fmt.Errorf("missing values, only got %v", params)
	}

	value, err := strconv.Atoi(params[Value])
	if err != nil {
		return Pledge{}, err
	}
	return Pledge{params[Email], ItemId(params[Type]), CompanyId(params[Company]), value}, nil
}

func extractFormParams(values url.Values, params ...string) (map[string]string, bool) {
	results := map[string]string{}
	for _, p := range (params) {
		v, ok := values[p]
		if ! ok {
			return results, false
		}
		results[p] = v[0]
	}
	return results, true
}

func unableToParseForm(err error, writer http.ResponseWriter) {
	fmt.Fprintf(writer, "error in form data")
	log.Print(err)
}

func unsupportedMethod(writer http.ResponseWriter) {
	fmt.Fprintf(writer, "unsupported method")
}
<commit_msg>Holding point<commit_after>package main

import (
	"net/http"
	"fmt"
	"log"
	"net/url"
	"strconv"
	"github.com/satori/go.uuid"
	"time"
)

type CompanyId string

type ItemId string

type CountryId string

type UserId string

type PledgeId string

type Pledge struct {
	Id        PledgeId
	UserId    UserId
	ItemId    ItemId
	Timestamp time.Time
}

type PublicUser struct {
	Id        UserId
	Country   CountryId
	FirstName string
}

type PrivateUser struct {
	Id       UserId
	Email    string
	FullName string
	AuthMethod string
	AuthSecret string
}

type MethodHandler func(http.ResponseWriter, *http.Request)

type HandlerMap struct {
	PathExpr string
	Method   string
	Handler  MethodHandler
}

type PledgeRepo interface {
	Save(pledge Pledge) (bool)
	GetByUserId(id UserId) []Pledge
}

type PublicUserRepo interface {
	CreateUser(user PublicUser) (bool)
	GetById(id UserId) (PublicUser)
}

type PrivateUserRepo interface {
	CreateUser(user PrivateUser) (bool)
	GetByEmail(email string) (PublicUser)
	GetById(id UserId) (PublicUser)
}

func main() {
	http.HandleFunc("/api/v1/pledge", pledgeHandler)
	http.ListenAndServe("localhost:8080", nil)
}

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

	handlerMaps := map[string]MethodHandler{
		http.MethodPost: handlePost,
		http.MethodGet:  handleGet,
	}

	fmt.Printf("%v", request)
	v, ok := handlerMaps[request.Method]
	if ! ok {
		unsupportedMethod(writer)
		return
	}
	v(writer, request)
}

func handlePost(writer http.ResponseWriter, request *http.Request) {
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}
	pledge, err := parseRequest(request.Form)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
		return
	}

	//savePledge()
	fmt.Fprintf(writer, "%v", pledge)
}

func handleGet(writer http.ResponseWriter, request *http.Request) {
	const message = "Welcome"
	fmt.Fprintf(writer, message)
}

func parseRequest(values url.Values) (Pledge, error) {
	const (
		Item    = "item"
		Company = "company"
		Value   = "value"
		Email   = "email"
		Country = "country"
	)

	params, ok := extractFormParams(values, Item, Company, Value, Email)
	if ! ok {
		return Pledge{}, fmt.Errorf("missing values, only got %v", params)
	}

	value, err := strconv.Atoi(params[Value])
	if err != nil {
		return Pledge{}, err
	}
	newId := uuid.NewV4().String()
	return Pledge{PledgeId(newId), params[Email], ItemId(params[Item]), CompanyId(params[Company]), value}, nil
}

func extractFormParams(values url.Values, params ...string) (map[string]string, bool) {
	results := map[string]string{}
	for _, p := range (params) {
		v, ok := values[p]
		if ! ok {
			return results, false
		}
		results[p] = v[0]
	}
	return results, true
}

func unableToParseForm(err error, writer http.ResponseWriter) {
	fmt.Fprintf(writer, "error in form data")
	log.Print(err)
}

func unsupportedMethod(writer http.ResponseWriter) {
	fmt.Fprintf(writer, "unsupported method")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"
)

var (
	keyFile  = flag.String("key", "", "Key file")
	certFile = flag.String("cert", "", "Certificate file")
	dbDir    = flag.String("db", "", "Database directory")
	port     = flag.Int("port", 8443, "Listen port")
	tpl      *template.Template
)

var funcs = map[string]interface{}{
	"commatize": commatize,
	"number":    number,
}

func main() {
	log.SetFlags(log.Lshortfile)
	log.SetOutput(os.Stdout)
	flag.Parse()

	fd, err := os.Open("static/index.html")
	if err != nil {
		log.Fatal(err)
	}
	bs, err := ioutil.ReadAll(fd)
	if err != nil {
		log.Fatal(err)
	}
	fd.Close()
	tpl = template.Must(template.New("index.html").Funcs(funcs).Parse(string(bs)))

	http.HandleFunc("/", rootHandler)
	http.HandleFunc("/newdata", newDataHandler)
	http.HandleFunc("/report", reportHandler)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
	if err != nil {
		log.Fatal(err)
	}

	cfg := &tls.Config{
		Certificates:           []tls.Certificate{cert},
		SessionTicketsDisabled: true,
	}

	listener, err := tls.Listen("tcp", fmt.Sprintf(":%d", *port), cfg)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Listening on", listener.Addr())

	srv := http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

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

func rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" || r.URL.Path == "/index.html" {
		k := timestamp()
		rep := getReport(k)

		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		err := tpl.Execute(w, rep)
		if err != nil {
			log.Println(err)
		}
	} else {
		http.Error(w, "Not found", 404)
	}
}

func reportHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	k := timestamp()
	rep := getReport(k)
	json.NewEncoder(w).Encode(rep)
}

func newDataHandler(w http.ResponseWriter, r *http.Request) {
	today := time.Now().Format("20060102")
	dir := filepath.Join(*dbDir, today)
	ensureDir(dir, 0700)

	var m map[string]interface{}
	lr := &io.LimitedReader{R: r.Body, N: 10240}
	err := json.NewDecoder(lr).Decode(&m)

	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), 500)
		return
	}

	id, ok := m["uniqueID"]
	if ok {
		idStr, ok := id.(string)
		if !ok {
			if err != nil {
				log.Printf("No ID (type was %T)", id)
				http.Error(w, "No ID", 500)
				return
			}
		}
		if idStr == "" {
			log.Println("No ID (empty)")
			http.Error(w, "No ID", 500)
			return
		}

		// The ID is base64 encoded, so can contain slashes. Replace those with dots instead.
		idStr = strings.Replace(idStr, "/", ".", -1)

		f, err := os.Create(path.Join(dir, idStr+".json"))
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}
		err = json.NewEncoder(f).Encode(m)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}
		err = f.Close()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}

		log.Printf("Report from %q", id)
	} else {
		log.Println("No ID (missing)")
		http.Error(w, "No ID", 500)
		return
	}
}

type report struct {
	UniqueID       string
	Version        string
	Platform       string
	NumRepos       int
	NumNodes       int
	TotFiles       int
	RepoMaxFiles   int
	TotMiB         int
	RepoMaxMiB     int
	MemoryUsageMiB int
	SHA256Perf     float64
	MemorySize     int
}

func fileList() ([]string, error) {
	files := make(map[string]string)
	t0 := time.Now().Add(-24 * time.Hour).Format("20060102")
	t1 := time.Now().Format("20060102")

	dir := filepath.Join(*dbDir, t0)
	gr, err := filepath.Glob(filepath.Join(dir, "*.json"))
	if err != nil {
		return nil, err
	}
	for _, f := range gr {
		bn := filepath.Base(f)
		files[bn] = f
	}

	dir = filepath.Join(*dbDir, t1)
	gr, err = filepath.Glob(filepath.Join(dir, "*.json"))
	if err != nil {
		return nil, err
	}
	for _, f := range gr {
		bn := filepath.Base(f)
		files[bn] = f
	}

	l := make([]string, 0, len(files))
	for _, f := range files {
		si, err := os.Stat(f)
		if err != nil {
			continue
		}
		if time.Since(si.ModTime()) < 24*time.Hour {
			l = append(l, f)
		}
	}

	return l, nil
}

type category struct {
	Values [4]float64
	Key    string
	Descr  string
	Unit   string
	Binary bool
}

var reportCache map[string]interface{}
var reportMutex sync.Mutex

func getReport(key string) map[string]interface{} {
	reportMutex.Lock()
	defer reportMutex.Unlock()

	if k := reportCache["key"]; k == key {
		return reportCache
	}

	files, err := fileList()
	if err != nil {
		return nil
	}

	nodes := 0
	var versions []string
	var platforms []string
	var oses []string
	var numRepos []int
	var numNodes []int
	var totFiles []int
	var maxFiles []int
	var totMiB []int
	var maxMiB []int
	var memoryUsage []int
	var sha256Perf []float64
	var memorySize []int

	for _, fn := range files {
		f, err := os.Open(fn)
		if err != nil {
			continue
		}

		var rep report
		err = json.NewDecoder(f).Decode(&rep)
		if err != nil {
			continue
		}
		f.Close()

		nodes++
		versions = append(versions, transformVersion(rep.Version))
		platforms = append(platforms, rep.Platform)
		ps := strings.Split(rep.Platform, "-")
		oses = append(oses, ps[0])
		if rep.NumRepos > 0 {
			numRepos = append(numRepos, rep.NumRepos)
		}
		if rep.NumNodes > 0 {
			numNodes = append(numNodes, rep.NumNodes)
		}
		if rep.TotFiles > 0 {
			totFiles = append(totFiles, rep.TotFiles)
		}
		if rep.RepoMaxFiles > 0 {
			maxFiles = append(maxFiles, rep.RepoMaxFiles)
		}
		if rep.TotMiB > 0 {
			totMiB = append(totMiB, rep.TotMiB*(1<<20))
		}
		if rep.RepoMaxMiB > 0 {
			maxMiB = append(maxMiB, rep.RepoMaxMiB*(1<<20))
		}
		if rep.MemoryUsageMiB > 0 {
			memoryUsage = append(memoryUsage, rep.MemoryUsageMiB*(1<<20))
		}
		if rep.SHA256Perf > 0 {
			sha256Perf = append(sha256Perf, rep.SHA256Perf*(1<<20))
		}
		if rep.MemorySize > 0 {
			memorySize = append(memorySize, rep.MemorySize*(1<<20))
		}
	}

	var categories []category
	categories = append(categories, category{
		Values: statsForInts(totFiles),
		Descr:  "Files Managed per Node",
	})

	categories = append(categories, category{
		Values: statsForInts(maxFiles),
		Descr:  "Files in Largest Repo",
	})

	categories = append(categories, category{
		Values: statsForInts(totMiB),
		Descr:  "Data Managed per Node",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(maxMiB),
		Descr:  "Data in Largest Repo",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(numNodes),
		Descr:  "Number of Nodes in Cluster",
	})

	categories = append(categories, category{
		Values: statsForInts(numRepos),
		Descr:  "Number of Repositories Configured",
	})

	categories = append(categories, category{
		Values: statsForInts(memoryUsage),
		Descr:  "Memory Usage",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(memorySize),
		Descr:  "System Memory",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForFloats(sha256Perf),
		Descr:  "SHA-256 Hashing Performance",
		Unit:   "B/s",
		Binary: true,
	})

	r := make(map[string]interface{})
	r["key"] = key
	r["nodes"] = nodes
	r["categories"] = categories
	r["versions"] = analyticsFor(versions, 10)
	r["platforms"] = analyticsFor(platforms, 0)
	r["os"] = analyticsFor(oses, 0)

	reportCache = r

	return r
}

func ensureDir(dir string, mode int) {
	fi, err := os.Stat(dir)
	if os.IsNotExist(err) {
		os.MkdirAll(dir, 0700)
	} else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
		os.Chmod(dir, os.FileMode(mode))
	}
}

var vRe = regexp.MustCompile(`^(v\d+\.\d+\.\d+(?:-[a-z]\w+)?)[+\.-]`)

// transformVersion returns a version number formatted correctly, with all
// development versions aggregated into one.
func transformVersion(v string) string {
	if v == "unknown-dev" {
		return v
	}
	if !strings.HasPrefix(v, "v") {
		v = "v" + v
	}
	if m := vRe.FindStringSubmatch(v); len(m) > 0 {
		return m[1] + " (+dev)"
	}
	return v
}

// timestamp returns a time stamp for the current hour, to be used as a cache key
func timestamp() string {
	return time.Now().Format("20060102T15")
}
<commit_msg>Summarize old versions<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"
)

var (
	keyFile  = flag.String("key", "", "Key file")
	certFile = flag.String("cert", "", "Certificate file")
	dbDir    = flag.String("db", "", "Database directory")
	port     = flag.Int("port", 8443, "Listen port")
	tpl      *template.Template
)

var funcs = map[string]interface{}{
	"commatize": commatize,
	"number":    number,
}

func main() {
	log.SetFlags(log.Lshortfile)
	log.SetOutput(os.Stdout)
	flag.Parse()

	fd, err := os.Open("static/index.html")
	if err != nil {
		log.Fatal(err)
	}
	bs, err := ioutil.ReadAll(fd)
	if err != nil {
		log.Fatal(err)
	}
	fd.Close()
	tpl = template.Must(template.New("index.html").Funcs(funcs).Parse(string(bs)))

	http.HandleFunc("/", rootHandler)
	http.HandleFunc("/newdata", newDataHandler)
	http.HandleFunc("/report", reportHandler)
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
	if err != nil {
		log.Fatal(err)
	}

	cfg := &tls.Config{
		Certificates:           []tls.Certificate{cert},
		SessionTicketsDisabled: true,
	}

	listener, err := tls.Listen("tcp", fmt.Sprintf(":%d", *port), cfg)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Listening on", listener.Addr())

	srv := http.Server{
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

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

func rootHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" || r.URL.Path == "/index.html" {
		k := timestamp()
		rep := getReport(k)

		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		err := tpl.Execute(w, rep)
		if err != nil {
			log.Println(err)
		}
	} else {
		http.Error(w, "Not found", 404)
	}
}

func reportHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	k := timestamp()
	rep := getReport(k)
	json.NewEncoder(w).Encode(rep)
}

func newDataHandler(w http.ResponseWriter, r *http.Request) {
	today := time.Now().Format("20060102")
	dir := filepath.Join(*dbDir, today)
	ensureDir(dir, 0700)

	var m map[string]interface{}
	lr := &io.LimitedReader{R: r.Body, N: 10240}
	err := json.NewDecoder(lr).Decode(&m)

	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), 500)
		return
	}

	id, ok := m["uniqueID"]
	if ok {
		idStr, ok := id.(string)
		if !ok {
			if err != nil {
				log.Printf("No ID (type was %T)", id)
				http.Error(w, "No ID", 500)
				return
			}
		}
		if idStr == "" {
			log.Println("No ID (empty)")
			http.Error(w, "No ID", 500)
			return
		}

		// The ID is base64 encoded, so can contain slashes. Replace those with dots instead.
		idStr = strings.Replace(idStr, "/", ".", -1)

		f, err := os.Create(path.Join(dir, idStr+".json"))
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}
		err = json.NewEncoder(f).Encode(m)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}
		err = f.Close()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}

		log.Printf("Report from %q", id)
	} else {
		log.Println("No ID (missing)")
		http.Error(w, "No ID", 500)
		return
	}
}

type report struct {
	UniqueID       string
	Version        string
	Platform       string
	NumRepos       int
	NumNodes       int
	TotFiles       int
	RepoMaxFiles   int
	TotMiB         int
	RepoMaxMiB     int
	MemoryUsageMiB int
	SHA256Perf     float64
	MemorySize     int
}

func fileList() ([]string, error) {
	files := make(map[string]string)
	t0 := time.Now().Add(-24 * time.Hour).Format("20060102")
	t1 := time.Now().Format("20060102")

	dir := filepath.Join(*dbDir, t0)
	gr, err := filepath.Glob(filepath.Join(dir, "*.json"))
	if err != nil {
		return nil, err
	}
	for _, f := range gr {
		bn := filepath.Base(f)
		files[bn] = f
	}

	dir = filepath.Join(*dbDir, t1)
	gr, err = filepath.Glob(filepath.Join(dir, "*.json"))
	if err != nil {
		return nil, err
	}
	for _, f := range gr {
		bn := filepath.Base(f)
		files[bn] = f
	}

	l := make([]string, 0, len(files))
	for _, f := range files {
		si, err := os.Stat(f)
		if err != nil {
			continue
		}
		if time.Since(si.ModTime()) < 24*time.Hour {
			l = append(l, f)
		}
	}

	return l, nil
}

type category struct {
	Values [4]float64
	Key    string
	Descr  string
	Unit   string
	Binary bool
}

var reportCache map[string]interface{}
var reportMutex sync.Mutex

func getReport(key string) map[string]interface{} {
	reportMutex.Lock()
	defer reportMutex.Unlock()

	if k := reportCache["key"]; k == key {
		return reportCache
	}

	files, err := fileList()
	if err != nil {
		return nil
	}

	nodes := 0
	var versions []string
	var platforms []string
	var oses []string
	var numRepos []int
	var numNodes []int
	var totFiles []int
	var maxFiles []int
	var totMiB []int
	var maxMiB []int
	var memoryUsage []int
	var sha256Perf []float64
	var memorySize []int

	for _, fn := range files {
		f, err := os.Open(fn)
		if err != nil {
			continue
		}

		var rep report
		err = json.NewDecoder(f).Decode(&rep)
		if err != nil {
			continue
		}
		f.Close()

		nodes++
		versions = append(versions, transformVersion(rep.Version))
		platforms = append(platforms, rep.Platform)
		ps := strings.Split(rep.Platform, "-")
		oses = append(oses, ps[0])
		if rep.NumRepos > 0 {
			numRepos = append(numRepos, rep.NumRepos)
		}
		if rep.NumNodes > 0 {
			numNodes = append(numNodes, rep.NumNodes)
		}
		if rep.TotFiles > 0 {
			totFiles = append(totFiles, rep.TotFiles)
		}
		if rep.RepoMaxFiles > 0 {
			maxFiles = append(maxFiles, rep.RepoMaxFiles)
		}
		if rep.TotMiB > 0 {
			totMiB = append(totMiB, rep.TotMiB*(1<<20))
		}
		if rep.RepoMaxMiB > 0 {
			maxMiB = append(maxMiB, rep.RepoMaxMiB*(1<<20))
		}
		if rep.MemoryUsageMiB > 0 {
			memoryUsage = append(memoryUsage, rep.MemoryUsageMiB*(1<<20))
		}
		if rep.SHA256Perf > 0 {
			sha256Perf = append(sha256Perf, rep.SHA256Perf*(1<<20))
		}
		if rep.MemorySize > 0 {
			memorySize = append(memorySize, rep.MemorySize*(1<<20))
		}
	}

	var categories []category
	categories = append(categories, category{
		Values: statsForInts(totFiles),
		Descr:  "Files Managed per Node",
	})

	categories = append(categories, category{
		Values: statsForInts(maxFiles),
		Descr:  "Files in Largest Repo",
	})

	categories = append(categories, category{
		Values: statsForInts(totMiB),
		Descr:  "Data Managed per Node",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(maxMiB),
		Descr:  "Data in Largest Repo",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(numNodes),
		Descr:  "Number of Nodes in Cluster",
	})

	categories = append(categories, category{
		Values: statsForInts(numRepos),
		Descr:  "Number of Repositories Configured",
	})

	categories = append(categories, category{
		Values: statsForInts(memoryUsage),
		Descr:  "Memory Usage",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForInts(memorySize),
		Descr:  "System Memory",
		Unit:   "B",
		Binary: true,
	})

	categories = append(categories, category{
		Values: statsForFloats(sha256Perf),
		Descr:  "SHA-256 Hashing Performance",
		Unit:   "B/s",
		Binary: true,
	})

	r := make(map[string]interface{})
	r["key"] = key
	r["nodes"] = nodes
	r["categories"] = categories
	r["versions"] = analyticsFor(versions, 10)
	r["platforms"] = analyticsFor(platforms, 0)
	r["os"] = analyticsFor(oses, 0)

	reportCache = r

	return r
}

func ensureDir(dir string, mode int) {
	fi, err := os.Stat(dir)
	if os.IsNotExist(err) {
		os.MkdirAll(dir, 0700)
	} else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
		os.Chmod(dir, os.FileMode(mode))
	}
}

var vRe = regexp.MustCompile(`^(v\d+\.\d+\.\d+(?:-[a-z]\w+)?)[+\.-]`)

// transformVersion returns a version number formatted correctly, with all
// development versions aggregated into one.
func transformVersion(v string) string {
	if v == "unknown-dev" {
		return v
	}
	if !strings.HasPrefix(v, "v") {
		v = "v" + v
	}
	if m := vRe.FindStringSubmatch(v); len(m) > 0 {
		return m[1] + " (+dev)"
	}

	// Truncate old versions to just the generation part
	if strings.HasPrefix(v, "v0.7") {
		return "v0.7.x"
	}
	if strings.HasPrefix(v, "v0.8") {
		return "v0.8.x"
	}
	if strings.HasPrefix(v, "v0.9") {
		return "v0.9.x"
	}

	return v
}

// timestamp returns a time stamp for the current hour, to be used as a cache key
func timestamp() string {
	return time.Now().Format("20060102T15")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/gorilla/mux"
	"gitlab.com/iarenzana/urbanobot/objects"
	"golang.org/x/crypto/acme/autocert"
)

const version = "1.1"

func main() {

	//Check for the domain
	domain := os.Getenv("URBANO_DOMAIN")
	if domain == "" {
		log.Fatal("$URBANO_DOMAIN must be set")
	}

	//Get certificate and store it under /usr/local/etc. Auto-renewed.
	certManager := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(domain),
		Cache:      autocert.DirCache("/usr/local/etc/urbanobot/urbanocerts"),
	}

	router := mux.NewRouter().StrictSlash(true)

	router.HandleFunc("/urbano/v1/word", getWord)
	router.HandleFunc("/urbano/v1/random", getRandomWord)

	log.Printf("Starting up urbanobot %v...\n", version)

	//Start server on the https port
	server := &http.Server{
		Addr:    ":443",
		Handler: router,
		TLSConfig: &tls.Config{
			GetCertificate: certManager.GetCertificate,
		},
	}
	log.Fatal(server.ListenAndServeTLS("", ""))

	log.Print("Server started")
}

//GetWord
func getWord(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	word := r.URL.Query().Get("text")

	slackUser := r.URL.Query().Get("user_name")
	slackChannel := r.URL.Query().Get("channel_name")
	slackTeam := r.URL.Query().Get("team_id")
	log.Print("Request received for " + word + " from " + slackUser + ", from team " + slackTeam + ", on channel " + slackChannel)

	if word == "" {
		w.WriteHeader(http.StatusOK)
		response := objects.SlackResponse{}
		response.Text = "Screw you, @barnes. Happy now?"
		response.ResponseType = "in_channel"
		response.BotVersion = version

		resp, err := json.Marshal(response)
		if err != nil {
			resp, err := json.Marshal(response)
			if err != nil {
				log.Println("Error Marshalling response!")
				w.WriteHeader(http.StatusInternalServerError)
				return
			}

			w.Write(resp)
			return

		}
		w.Write(resp)

	}
	wordDefinition, err := getWordDefinition(word)
	if fmt.Sprintf("%s", err) == "NOTFOUND" {
		log.Println("Word " + word + " not found.")
		w.WriteHeader(http.StatusNotFound)

		response := objects.Response{Response: "Word not Found", BotVersion: version}
		resp, err := json.Marshal(response)
		if err != nil {
			log.Println("Error Marshalling response!")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		w.Write(resp)
		return
	}

	if err != nil {
		log.Print("Error - %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Print("Returning definition of " + word + " to " + slackUser + " from team " + slackTeam + " on channel " + slackChannel)

	w.WriteHeader(http.StatusOK)
	response := objects.SlackResponse{}
	response.Text = wordDefinition.Definition
	response.ResponseType = "in_channel"
	response.BotVersion = version

	resp, err := json.Marshal(response)
	if err != nil {
		resp, err := json.Marshal(response)
		if err != nil {
			log.Println("Error Marshalling response!")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		w.Write(resp)
		return

	}
	w.Write(resp)
}

func getWordDefinition(wordToDefine string) (objects.WordData, error) {
	var UDURL = "http://api.urbandictionary.com/v0/define?term=" + strings.Replace(wordToDefine, " ", "", -1)
	wd := objects.WordDataSlice{}
	var word objects.WordData

	resp, err := http.Get(UDURL)
	if err != nil {
		return word, err
	}

	defer resp.Body.Close()

	data, _ := ioutil.ReadAll(resp.Body)
	if err != nil {
		return word, err
	}

	err = json.Unmarshal([]byte(string(data)), &wd)
	if err != nil {
		return word, err
	}

	for _, element := range wd.List {
		if element.ThumbsUp > word.ThumbsUp {
			word = element
		}
	}
	if word.Definition == "" {
		return word, errors.New("NOTFOUND")
	}
	return word, nil
}

//GetWord
func getRandomWord(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	slackUser := r.URL.Query().Get("user_name")
	slackChannel := r.URL.Query().Get("channel_name")
	slackTeam := r.URL.Query().Get("team_id")
	log.Print("Request for random word received from " + slackUser + ", from team " + slackTeam + ", on channel " + slackChannel)

	wordDefinition, err := getNewWord()
	if err != nil {
		log.Print("Error - %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Print("Returning random to " + slackUser + " from team " + slackTeam + " on channel " + slackChannel)

	w.WriteHeader(http.StatusOK)
	response := objects.SlackResponse{}
	response.Text = fmt.Sprintf("%s --> %s", wordDefinition.Word, wordDefinition.Definition)
	response.ResponseType = "in_channel"
	response.BotVersion = version

	resp, err := json.Marshal(response)
	if err != nil {
		log.Println("Error Marshalling response!")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(resp)
}

//getNewWord gets a random UD word
func getNewWord() (objects.WordData, error) {
	var UDURL = "http://api.urbandictionary.com/v0/random"
	wd := objects.WordDataSlice{}
	var word objects.WordData
	var good = false
	tu := 13000

	for good == false {
		resp, err := http.Get(UDURL)
		if err != nil {
			return word, err
		}
		defer resp.Body.Close()

		data, _ := ioutil.ReadAll(resp.Body)
		if err != nil {
			return word, err
		}

		err = json.Unmarshal([]byte(string(data)), &wd)
		if err != nil {
			return word, err
		}

		for _, element := range wd.List {
			if element.ThumbsUp > tu {
				word = element
				good = true
			}
		}
	}
	return word, nil
}
<commit_msg>support for mattermost<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/gorilla/mux"
	"gitlab.com/iarenzana/urbanobot/objects"
	"golang.org/x/crypto/acme/autocert"
)

const version = "1.2"

func main() {

	//Check for the domain
	domain := os.Getenv("URBANO_DOMAIN")
	if domain == "" {
		log.Fatal("$URBANO_DOMAIN must be set")
	}

	//Get certificate and store it under /usr/local/etc. Auto-renewed.
	certManager := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		HostPolicy: autocert.HostWhitelist(domain),
		Cache:      autocert.DirCache("/usr/local/etc/urbanobot/urbanocerts"),
	}

	router := mux.NewRouter().StrictSlash(true)

	router.HandleFunc("/urbano/v1/word", getWord)
	router.HandleFunc("/urbano/v1/random", getRandomWord)

	log.Printf("Starting up urbanobot %v...\n", version)

	//Start server on the https port
	server := &http.Server{
		Addr:    ":443",
		Handler: router,
		TLSConfig: &tls.Config{
			GetCertificate: certManager.GetCertificate,
		},
	}
	log.Fatal(server.ListenAndServeTLS("", ""))

	log.Print("Server started")
}

//GetWord
func getWord(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	var word, slackUser, slackChannel, slackTeam string

	if strings.Contains(r.Header.Get("User-Agent"), "Slackbot") {

		word = r.URL.Query().Get("text")

		slackUser = r.URL.Query().Get("user_name")
		slackChannel = r.URL.Query().Get("channel_name")
		slackTeam = r.URL.Query().Get("team_id")
		log.Print("Slack request received for " + word + " from " + slackUser + ", from team " + slackTeam + ", on channel " + slackChannel)
	} else {

		word = r.FormValue("text")
		slackUser = r.FormValue("user_name")
		slackChannel = r.FormValue("channel_name")
		slackTeam = r.FormValue("team_id")
		log.Print("Other request received for " + word + " from " + slackUser + ", from team " + slackTeam + ", on channel " + slackChannel)
	}

	if word == "" {
		w.WriteHeader(http.StatusOK)
		response := objects.SlackResponse{}
		response.Text = "Screw you, @barnes. Happy now?"
		response.ResponseType = "in_channel"
		response.BotVersion = version

		resp, err := json.Marshal(response)
		if err != nil {
			resp, err := json.Marshal(response)
			if err != nil {
				log.Println("Error Marshalling response!")
				w.WriteHeader(http.StatusInternalServerError)
				return
			}

			w.Write(resp)
			return

		}
		w.Write(resp)

	}
	wordDefinition, err := getWordDefinition(word)
	if fmt.Sprintf("%s", err) == "NOTFOUND" {
		log.Println("Word " + word + " not found.")
		w.WriteHeader(http.StatusNotFound)

		response := objects.Response{Response: "Word not Found", BotVersion: version}
		resp, err := json.Marshal(response)
		if err != nil {
			log.Println("Error Marshalling response!")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		w.Write(resp)
		return
	}

	if err != nil {
		log.Print("Error - %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Print("Returning definition of " + word + " to " + slackUser + " from team " + slackTeam + " on channel " + slackChannel)

	w.WriteHeader(http.StatusOK)
	response := objects.SlackResponse{}
	response.Text = wordDefinition.Definition
	response.ResponseType = "in_channel"
	response.BotVersion = version

	resp, err := json.Marshal(response)
	if err != nil {
		resp, err := json.Marshal(response)
		if err != nil {
			log.Println("Error Marshalling response!")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		w.Write(resp)
		return

	}
	w.Write(resp)
}

func getWordDefinition(wordToDefine string) (objects.WordData, error) {
	var UDURL = "http://api.urbandictionary.com/v0/define?term=" + strings.Replace(wordToDefine, " ", "", -1)
	wd := objects.WordDataSlice{}
	var word objects.WordData

	resp, err := http.Get(UDURL)
	if err != nil {
		return word, err
	}

	defer resp.Body.Close()

	data, _ := ioutil.ReadAll(resp.Body)
	if err != nil {
		return word, err
	}

	err = json.Unmarshal([]byte(string(data)), &wd)
	if err != nil {
		return word, err
	}

	for _, element := range wd.List {
		if element.ThumbsUp > word.ThumbsUp {
			word = element
		}
	}
	if word.Definition == "" {
		return word, errors.New("NOTFOUND")
	}
	return word, nil
}

//GetWord
func getRandomWord(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	slackUser := r.URL.Query().Get("user_name")
	slackChannel := r.URL.Query().Get("channel_name")
	slackTeam := r.URL.Query().Get("team_id")
	log.Print("Request for random word received from " + slackUser + ", from team " + slackTeam + ", on channel " + slackChannel)

	wordDefinition, err := getNewWord()
	if err != nil {
		log.Print("Error - %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Print("Returning random to " + slackUser + " from team " + slackTeam + " on channel " + slackChannel)

	w.WriteHeader(http.StatusOK)
	response := objects.SlackResponse{}
	response.Text = fmt.Sprintf("%s --> %s", wordDefinition.Word, wordDefinition.Definition)
	response.ResponseType = "in_channel"
	response.BotVersion = version

	resp, err := json.Marshal(response)
	if err != nil {
		log.Println("Error Marshalling response!")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(resp)
}

//getNewWord gets a random UD word
func getNewWord() (objects.WordData, error) {
	var UDURL = "http://api.urbandictionary.com/v0/random"
	wd := objects.WordDataSlice{}
	var word objects.WordData
	var good = false
	tu := 13000

	for good == false {
		resp, err := http.Get(UDURL)
		if err != nil {
			return word, err
		}
		defer resp.Body.Close()

		data, _ := ioutil.ReadAll(resp.Body)
		if err != nil {
			return word, err
		}

		err = json.Unmarshal([]byte(string(data)), &wd)
		if err != nil {
			return word, err
		}

		for _, element := range wd.List {
			if element.ThumbsUp > tu {
				word = element
				good = true
			}
		}
	}
	return word, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"strconv"
	"syscall"
	"time"

	"path/filepath"

	"github.com/mitchellh/go-homedir"
)

const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

var (
	connectionName   string
	connectionServer string
	connectionPort   uint
	useSSL           bool
	debugMode        bool
)

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Println(log)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Println("fatal error", err.Error())
		os.Exit(3162)
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initVars() {
	flag.BoolVar(&useSSL, "ssl", false, "Enable ssl")
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	connectionName = args[0]
	connectionServer = args[1]
	p, err := strconv.Atoi(args[2])
	checkError(err)
	connectionPort = uint(p)

	debugLog("Name:", connectionName)
	debugLog("Server:", connectionServer)
	debugLog("Port:", connectionPort)
	debugLog("SSL?:", useSSL)
}

func getWorkingDir(main string, sub string) string {
	h, err := homedir.Dir()
	checkError(err)
	debugLog("Home directory", h)

	w := filepath.Join(h, main, sub)
	return w
}

func setupConnection(s string) *net.TCPConn {
	tcpAddr, err := net.ResolveTCPAddr("tcp4", s)
	checkError(err)
	debugLog("server resolves to", tcpAddr)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	fmt.Println("~Connected at", getTimestamp())

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	var keepalive time.Duration = 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)
	return connection
}

func closeConnection(c *net.TCPConn) {
	fmt.Println("~Closing connection at", getTimestamp())
	c.Close()
}

func makeFIFO(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("if you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES\n" {
			fmt.Println("Canceling. Please remove FIFO before running")
			os.Exit(1)
		}
		syscall.Unlink(file)
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	f, err := os.Open(file)
	checkError(err)
	return f
}

func closeFIFO(f *os.File) {
	n := f.Name()
	f.Close()
	syscall.Unlink(n)
}

func closeLog(f *os.File) {
	f.Close()
	err := os.Rename(outFile, getTimestamp())
	checkError(err)
}

func readtoConn(f *os.File, c *net.TCPConn) {
	for {
		buf := make([]byte, 512)
		bi, err := f.Read(buf)
		checkError(err)
		debugLog(bi, "bytes read from FIFO")
		bo, err := c.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func readToFile(c *net.TCPConn, f *os.File) {
	for {
		buf := make([]byte, 512)
		bi, err := c.Read(buf)
		if err != nil {
			continue
		}
		debugLog(bi, "bytes read from connection")

		bo, err := f.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func main() {
	fmt.Println("~Started at", getTimestamp())
	initVars()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, connectionName)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	//create connection
	server := fmt.Sprintf("%s:%d", connectionServer, connectionPort)
	connection := setupConnection(server)
	defer closeConnection(connection)

	// Make the in FIFO
	in := makeFIFO(inFile)
	defer closeFIFO(in)

	// Make the out file
	out, err := os.Create(outFile)
	checkError(err)
	defer closeLog(out)

	go readtoConn(in, connection)
	readToFile(connection, out)
}
<commit_msg>Way more debug and checks<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"strconv"
	"syscall"
	"time"

	"path/filepath"

	"github.com/mitchellh/go-homedir"
)

const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

var (
	connectionName   string
	connectionServer string
	connectionPort   uint
	useSSL           bool
	debugMode        bool
)

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Println(log)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Println("fatal error", err.Error())
		os.Exit(3162)
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initVars() {
	flag.BoolVar(&useSSL, "ssl", false, "Enable ssl")
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	connectionName = args[0]
	connectionServer = args[1]
	p, err := strconv.Atoi(args[2])
	checkError(err)
	connectionPort = uint(p)

	debugLog("Name:", connectionName)
	debugLog("Server:", connectionServer)
	debugLog("Port:", connectionPort)
	debugLog("SSL?:", useSSL)
}

func getWorkingDir(main string, sub string) string {
	h, err := homedir.Dir()
	checkError(err)
	debugLog("Home directory", h)

	w := filepath.Join(h, main, sub)
	return w
}

func setupConnection(s string) *net.TCPConn {
	tcpAddr, err := net.ResolveTCPAddr("tcp4", s)
	checkError(err)
	debugLog("server resolves to", tcpAddr)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	fmt.Println("~Connected at", getTimestamp())

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	var keepalive time.Duration = 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)
	return connection
}

func makeFIFO(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("if you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES\n" {
			fmt.Println("Canceling. Please remove FIFO before running")
			os.Exit(1)
		}
		errUn := syscall.Unlink(file)
		checkError(errUn)
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	f, err := os.Open(file)
	checkError(err)
	return f
}
func readtoConn(f *os.File, c *net.TCPConn) {
	for {
		buf := make([]byte, 512)
		bi, err := f.Read(buf)
		checkError(err)
		debugLog(bi, "bytes read from FIFO")
		bo, err := c.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func readToFile(c *net.TCPConn, f *os.File) {
	for {
		buf := make([]byte, 512)
		bi, err := c.Read(buf)
		if err != nil {
			continue
		}
		debugLog(bi, "bytes read from connection")

		bo, err := f.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func closeConnection(c *net.TCPConn) {
	fmt.Println("~Closing connection at", getTimestamp())
	err := c.Close()
	if err != nil {
		debugLog(err.Error())
	}
	debugLog("Connection closed")
}

func closeFIFO(f *os.File) {
	n := f.Name()
	debugLog("closing and deleting FIFO", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	errU := syscall.Unlink(n)
	if errU != nil {
		debugLog(errU.Error())
	}
	debugLog(n, "closed and deleted")
}

func closeLog(f *os.File) {
	n := f.Name()
	debugLog("closing and rotating file", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	errR := os.Rename(outFile, getTimestamp())
	if errR != nil {
		debugLog(errR.Error())
	}
	debugLog(n, "closed and rotated")
}

func main() {
	fmt.Println("~Started at", getTimestamp())
	initVars()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, connectionName)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	//create connection
	server := fmt.Sprintf("%s:%d", connectionServer, connectionPort)
	connection := setupConnection(server)
	defer closeConnection(connection)

	// Make the in FIFO
	in := makeFIFO(inFile)
	defer closeFIFO(in)

	// Make the out file
	out, err := os.Create(outFile)
	checkError(err)
	defer closeLog(out)

	go readtoConn(in, connection)
	readToFile(connection, out)
}
<|endoftext|>