<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

// hardcoded program settings
const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"
const timeString string = "2006-01-02T150405"
const bufferSize int = 1024

// Program level switches set from command line
var debugMode bool
var disableLogRotate bool

// MuckServer stores all connection settings
type MuckServer struct {
	name     string
	host     string
	port     uint
	ssl      bool
	insecure bool
}

// Simplify returning connection strings by making it the String method
func (m *MuckServer) String() string {
	s := fmt.Sprintf("%s:%d", m.host, m.port)
	return s
}

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Print("DEBUG: ")
		fmt.Println(log...)
	}
}

func checkError(err error) {
	if err != nil {
		debugLog("checkError caught", err.Error())
		panic(err.Error())
	}
}

func getTimestamp() string {
	return time.Now().Format(timeString)
}

func initArgs() MuckServer {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "    %v [<flags>] <name> <server> <port>\n", os.Args[0])
		flag.PrintDefaults()
	}

	// Global program flags
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.BoolVar(&disableLogRotate, "nolog", false, "Disable log rotation on quit")
	// Connection flags
	ssl := flag.Bool("ssl", false, "Enable ssl")
	insecure := flag.Bool("insecure", false, "Disable strict SSL checking")
	flag.Parse()

	if flag.NArg() != 3 {
		flag.Usage()
		os.Exit(1)
	}

	args := flag.Args()
	p, err := strconv.Atoi(args[2])
	checkError(err)
	s := MuckServer{name: args[0], host: args[1], port: uint(p), ssl: *ssl, insecure: *insecure}

	debugLog("rotate log disabled?:", disableLogRotate)
	debugLog("name:", s.name)
	debugLog("host:", s.host)
	debugLog("port:", s.port)
	debugLog("SSL?:", s.ssl)
	debugLog("insecure ssl check?:", s.insecure)

	return s
}

func getWorkingDir(main string, sub string) string {
	u, err := user.Current()
	checkError(err)
	h := u.HomeDir
	debugLog("home directory", h)

	w := filepath.Join(h, main, sub)
	debugLog("working directory", w)
	return w
}

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")
			panic("User Canceled at FIFO removal prompt")
		}
		errUn := syscall.Unlink(file)
		checkError(errUn)
		debugLog(file, "unlinked")
	}
	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	debugLog("FIFO created as", file)
	f, err := os.OpenFile(file, os.O_RDONLY|syscall.O_NONBLOCK, 0666)
	checkError(err)
	debugLog("FIFO opened as", f.Name())
	return f
}

func makeOut(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Printf("Warning: %v already exists; appending.\n", file)
	}
	out, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	checkError(err)
	debugLog("logfile created as", out.Name())
	return out
}

func lookupHostname(s string) *net.TCPAddr {
	a, err := net.ResolveTCPAddr("tcp", s)
	checkError(err)
	debugLog("server resolves to", a)
	return a
}

func setupConnection(s *MuckServer) net.Conn {
	tcpAddr := lookupHostname(s.String())
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	debugLog("connected to Server")

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

func setupTLSConnextion(s *MuckServer) net.Conn {
	var conf *tls.Config
	if s.insecure {
		conf = &tls.Config{InsecureSkipVerify: true}
	} else {
		conf = &tls.Config{ServerName: s.host}
	}
	tcpAddr := lookupHostname(s.String())
	connection, err := tls.Dial("tcp", tcpAddr.String(), conf)
	checkError(err)
	return connection
}

func readToConn(f *os.File, c net.Conn, quit chan bool) {
	tmpError := fmt.Sprintf("read %v: resource temporarily unavailable", f.Name())
	for {
		select {
		case <-quit:
			debugLog("readtoConn recieved quit; returning")
			return
		default:
			// This pause between reads from the FIFO. This is the difference between
			// 0.1% and 100% cpu usage. Also without this you will get excessive "read
			// %v: resource temporarily unavailable" errors.
			time.Sleep(time.Second / 10)
			buf := make([]byte, bufferSize)
			bi, err := f.Read(buf)
			if err != nil && err.Error() != "EOF" && err.Error() != tmpError {
				checkError(err)
			} else if bi == 0 {
				time.Sleep(time.Second)
				continue
			}
			debugLog(bi, "bytes read from FIFO")
			bo, err := c.Write(buf[:bi])
			checkError(err)
			debugLog(bo, "bytes written to file")
		}
	}
}

func readToFile(c net.Conn, f *os.File, quit chan bool) {
	_, err := f.WriteString(fmt.Sprintf("~Connected at %v\n", getTimestamp()))
	checkError(err)
	for {
		buf := make([]byte, bufferSize)
		bi, err := c.Read(buf)
		if err != nil {
			fmt.Println("Server disconnected with", err.Error())
			_, err := f.WriteString(fmt.Sprintf("\n~Connection lost at %v\n", getTimestamp()))
			checkError(err)
			quit <- true
			return
		}
		debugLog(bi, "bytes read from connection")

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

func closeConnection(c net.Conn) {
	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())
	}
	debugLog(n, "closed")
	if disableLogRotate {
		debugLog("log rotation is disabled")
		return
	}
	errR := os.Rename(outFile, getTimestamp())
	if errR != nil {
		debugLog(errR.Error())
	}
	debugLog(n, "rotated")
}

func main() {
	// checkError throws a panic, catch it at the end and return error to user
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("FATAL ERROR", r)
		}
	}()

	fmt.Println("Started at", getTimestamp())
	server := initArgs()

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

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

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

	// Make the out file
	out := makeOut(outFile)
	defer closeLog(out)

	//create connection
	var connection net.Conn
	if server.ssl {
		connection = setupTLSConnextion(&server)
	} else {
		connection = setupConnection(&server)
	}
	defer closeConnection(connection)

	quit := make(chan bool)
	go readToFile(connection, out, quit)
	readToConn(in, connection, quit)

	fmt.Println("Quit at", getTimestamp())
	fmt.Println("Thanks for playing!")
	debugLog("end of main hit")
}
<commit_msg>Reduce delay to a Millisecond to minimize type lag<commit_after>package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

// hardcoded program settings
const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"
const timeString string = "2006-01-02T150405"
const bufferSize int = 1024

// Program level switches set from command line
var debugMode bool
var disableLogRotate bool

// MuckServer stores all connection settings
type MuckServer struct {
	name     string
	host     string
	port     uint
	ssl      bool
	insecure bool
}

// Simplify returning connection strings by making it the String method
func (m *MuckServer) String() string {
	s := fmt.Sprintf("%s:%d", m.host, m.port)
	return s
}

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Print("DEBUG: ")
		fmt.Println(log...)
	}
}

func checkError(err error) {
	if err != nil {
		debugLog("checkError caught", err.Error())
		panic(err.Error())
	}
}

func getTimestamp() string {
	return time.Now().Format(timeString)
}

func initArgs() MuckServer {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "    %v [<flags>] <name> <server> <port>\n", os.Args[0])
		flag.PrintDefaults()
	}

	// Global program flags
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.BoolVar(&disableLogRotate, "nolog", false, "Disable log rotation on quit")
	// Connection flags
	ssl := flag.Bool("ssl", false, "Enable ssl")
	insecure := flag.Bool("insecure", false, "Disable strict SSL checking")
	flag.Parse()

	if flag.NArg() != 3 {
		flag.Usage()
		os.Exit(1)
	}

	args := flag.Args()
	p, err := strconv.Atoi(args[2])
	checkError(err)
	s := MuckServer{name: args[0], host: args[1], port: uint(p), ssl: *ssl, insecure: *insecure}

	debugLog("rotate log disabled?:", disableLogRotate)
	debugLog("name:", s.name)
	debugLog("host:", s.host)
	debugLog("port:", s.port)
	debugLog("SSL?:", s.ssl)
	debugLog("insecure ssl check?:", s.insecure)

	return s
}

func getWorkingDir(main string, sub string) string {
	u, err := user.Current()
	checkError(err)
	h := u.HomeDir
	debugLog("home directory", h)

	w := filepath.Join(h, main, sub)
	debugLog("working directory", w)
	return w
}

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")
			panic("User Canceled at FIFO removal prompt")
		}
		errUn := syscall.Unlink(file)
		checkError(errUn)
		debugLog(file, "unlinked")
	}
	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	debugLog("FIFO created as", file)
	f, err := os.OpenFile(file, os.O_RDONLY|syscall.O_NONBLOCK, 0666)
	checkError(err)
	debugLog("FIFO opened as", f.Name())
	return f
}

func makeOut(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Printf("Warning: %v already exists; appending.\n", file)
	}
	out, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	checkError(err)
	debugLog("logfile created as", out.Name())
	return out
}

func lookupHostname(s string) *net.TCPAddr {
	a, err := net.ResolveTCPAddr("tcp", s)
	checkError(err)
	debugLog("server resolves to", a)
	return a
}

func setupConnection(s *MuckServer) net.Conn {
	tcpAddr := lookupHostname(s.String())
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	debugLog("connected to Server")

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

func setupTLSConnextion(s *MuckServer) net.Conn {
	var conf *tls.Config
	if s.insecure {
		conf = &tls.Config{InsecureSkipVerify: true}
	} else {
		conf = &tls.Config{ServerName: s.host}
	}
	tcpAddr := lookupHostname(s.String())
	connection, err := tls.Dial("tcp", tcpAddr.String(), conf)
	checkError(err)
	return connection
}

func readToConn(f *os.File, c net.Conn, quit chan bool) {
	tmpError := fmt.Sprintf("read %v: resource temporarily unavailable", f.Name())
	for {
		select {
		case <-quit:
			debugLog("readtoConn recieved quit; returning")
			return
		default:
			// This pause between reads from the FIFO. This is the difference between
			// 0.1% and 100% cpu usage. Also without this you will get excessive "read
			// %v: resource temporarily unavailable" errors.
			time.Sleep(time.Millisecond)
			buf := make([]byte, bufferSize)
			bi, err := f.Read(buf)
			if err != nil && err.Error() != "EOF" && err.Error() != tmpError {
				checkError(err)
			} else if bi == 0 {
				time.Sleep(time.Second)
				continue
			}
			debugLog(bi, "bytes read from FIFO")
			bo, err := c.Write(buf[:bi])
			checkError(err)
			debugLog(bo, "bytes written to file")
		}
	}
}

func readToFile(c net.Conn, f *os.File, quit chan bool) {
	_, err := f.WriteString(fmt.Sprintf("~Connected at %v\n", getTimestamp()))
	checkError(err)
	for {
		buf := make([]byte, bufferSize)
		bi, err := c.Read(buf)
		if err != nil {
			fmt.Println("Server disconnected with", err.Error())
			_, err := f.WriteString(fmt.Sprintf("\n~Connection lost at %v\n", getTimestamp()))
			checkError(err)
			quit <- true
			return
		}
		debugLog(bi, "bytes read from connection")

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

func closeConnection(c net.Conn) {
	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())
	}
	debugLog(n, "closed")
	if disableLogRotate {
		debugLog("log rotation is disabled")
		return
	}
	errR := os.Rename(outFile, getTimestamp())
	if errR != nil {
		debugLog(errR.Error())
	}
	debugLog(n, "rotated")
}

func main() {
	// checkError throws a panic, catch it at the end and return error to user
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("FATAL ERROR", r)
		}
	}()

	fmt.Println("Started at", getTimestamp())
	server := initArgs()

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

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

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

	// Make the out file
	out := makeOut(outFile)
	defer closeLog(out)

	//create connection
	var connection net.Conn
	if server.ssl {
		connection = setupTLSConnextion(&server)
	} else {
		connection = setupConnection(&server)
	}
	defer closeConnection(connection)

	quit := make(chan bool)
	go readToFile(connection, out, quit)
	readToConn(in, connection, quit)

	fmt.Println("Quit at", getTimestamp())
	fmt.Println("Thanks for playing!")
	debugLog("end of main hit")
}
<|endoftext|>


<commit_before>package main

import (
	"expvar"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"text/template"
	"time"

	"github.com/go-recaptcha/recaptcha"
	"github.com/gorilla/handlers"
	"github.com/kelseyhightower/envconfig"
	"github.com/nlopes/slack"
	"github.com/oxtoacart/bpool"
	"github.com/paulbellamy/ratecounter"
)

var captcha *recaptcha.Recaptcha
var api *slack.Client
var bufpool *bpool.BufferPool
var indexTemplate = template.Must(template.New("index.tmpl").ParseFiles("templates/index.tmpl"))

// Slack statistics
var userCount int
var activeUserCount int
var statsMutex sync.RWMutex // Guards slack statistics variables

var m = expvar.NewMap("metrics")
var counter *ratecounter.RateCounter
var hitsPerMinute expvar.Int
var requests expvar.Int
var inviteErrors expvar.Int
var missingFirstName expvar.Int
var missingLastName expvar.Int
var missingEmail expvar.Int
var missingCoC expvar.Int
var successfulCaptcha expvar.Int
var failedCaptcha expvar.Int
var invalidCaptcha expvar.Int

// config
var c Specification

type Specification struct {
	Port           string `required:"true"`
	CaptchaSitekey string `required:"true"`
	CaptchaSecret  string `required:"true"`
	SlackToken     string `required:"true"`
}

func init() {
	err := envconfig.Process("slackinviter", &c)
	if err != nil {
		log.Fatal(err.Error())
	}
	counter = ratecounter.NewRateCounter(1 * time.Minute)
	m.Set("hits_per_minute", &hitsPerMinute)
	m.Set("requests", &requests)
	m.Set("invite_errors", &inviteErrors)
	m.Set("missing_first_name", &missingFirstName)
	m.Set("missing_last_name", &missingLastName)
	m.Set("missing_email", &missingEmail)
	m.Set("missing_coc", &missingCoC)
	m.Set("failed_captcha", &failedCaptcha)
	m.Set("invalid_captcha", &invalidCaptcha)
	m.Set("successful_captcha", &successfulCaptcha)
	// Init stuff
	captcha = recaptcha.New(c.CaptchaSecret)
	api = slack.New(c.SlackToken)
	bufpool = bpool.NewBufferPool(64)
}
func main() {
	go pollSlack()
	mux := http.NewServeMux()
	mux.HandleFunc("/invite/", handleInvite)
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	mux.HandleFunc("/", homepage)
	mux.Handle("/debug/vars", onlyLocalhost(http.DefaultServeMux))
	err := http.ListenAndServe(":"+c.Port, handlers.CombinedLoggingHandler(os.Stdout, mux))
	if err != nil {
		log.Fatal(err.Error())
	}
}
func pollSlack() {
	for {
		users, err := api.GetUsers()
		if err != nil {
			log.Println("error polling slack for users:", err)
			continue
		}
		uCount := 0 // users
		aCount := 0 // active users
		for _, u := range users {
			if u.ID != "USLACKBOT" && !u.IsBot && !u.Deleted {
				uCount += 1
				if u.Presence == "active" {
					aCount += 1
				}
			}
		}
		statsMutex.Lock()
		userCount = uCount
		activeUserCount = aCount
		statsMutex.Unlock()
		time.Sleep(10 * time.Minute)
	}
}

// Homepage renders the homepage
func homepage(w http.ResponseWriter, r *http.Request) {
	counter.Incr(1)
	hitsPerMinute.Set(counter.Rate())
	requests.Add(1)
	statsMutex.RLock()
	data := map[string]interface{}{"SiteKey": c.CaptchaSitekey, "UserCount": userCount, "ActiveCount": activeUserCount}
	statsMutex.RUnlock()
	buf := bufpool.Get()
	defer bufpool.Put(buf)
	err := indexTemplate.Execute(buf, data)
	if err != nil {
		log.Println("error rendering template:", err)
		http.Error(w, "error rendering template :-(", http.StatusInternalServerError)
		return
	}
	// Set the header and write the buffer to the http.ResponseWriter
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	buf.WriteTo(w)
}

// ShowPost renders a single post
func handleInvite(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	captchaResponse := r.FormValue("g-recaptcha-response")
	remoteIP, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		failedCaptcha.Add(1)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	valid, err := captcha.Verify(captchaResponse, remoteIP)
	if err != nil {
		failedCaptcha.Add(1)
		http.Error(w, "Error validating recaptcha.. Did you click it?", http.StatusPreconditionFailed)
		return
	}
	if !valid {
		invalidCaptcha.Add(1)
		http.Error(w, "Invalid recaptcha", http.StatusInternalServerError)
		return

	}
	successfulCaptcha.Add(1)
	fname := r.FormValue("fname")
	lname := r.FormValue("lname")
	email := r.FormValue("email")
	coc := r.FormValue("coc")
	if email == "" {
		missingEmail.Add(1)
		http.Error(w, "Missing email", http.StatusPreconditionFailed)
		return
	}
	if fname == "" {
		missingFirstName.Add(1)
		http.Error(w, "Missing first name", http.StatusPreconditionFailed)
		return
	}
	if lname == "" {
		missingLastName.Add(1)
		http.Error(w, "Missing last name", http.StatusPreconditionFailed)
		return
	}
	if coc != "1" {
		missingCoC.Add(1)
		http.Error(w, "You need to accept the code of conduct", http.StatusPreconditionFailed)
		return
	}
	err = api.InviteToTeam("Gophers", fname, lname, email)
	if err != nil {
		log.Println("InviteToTeam error:", err)
		inviteErrors.Add(1)
		http.Error(w, "Error inviting you :-(", http.StatusInternalServerError)
		return
	}
}
func onlyLocalhost(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		host, _, err := net.SplitHostPort(r.RemoteAddr)
		if err != nil {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
		if host == "127.0.0.1" {
			next.ServeHTTP(w, r)
		} else {
			http.Error(w, http.StatusText(404), 404)
		}
	})
}
<commit_msg>Since we are using environment variables now, we can show expvars to everyone<commit_after>package main

import (
	"expvar"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"text/template"
	"time"

	"github.com/go-recaptcha/recaptcha"
	"github.com/gorilla/handlers"
	"github.com/kelseyhightower/envconfig"
	"github.com/nlopes/slack"
	"github.com/oxtoacart/bpool"
	"github.com/paulbellamy/ratecounter"
)

var captcha *recaptcha.Recaptcha
var api *slack.Client
var bufpool *bpool.BufferPool
var indexTemplate = template.Must(template.New("index.tmpl").ParseFiles("templates/index.tmpl"))

// Slack statistics
var userCount int
var activeUserCount int
var statsMutex sync.RWMutex // Guards slack statistics variables

var m = expvar.NewMap("metrics")
var counter *ratecounter.RateCounter
var hitsPerMinute expvar.Int
var requests expvar.Int
var inviteErrors expvar.Int
var missingFirstName expvar.Int
var missingLastName expvar.Int
var missingEmail expvar.Int
var missingCoC expvar.Int
var successfulCaptcha expvar.Int
var failedCaptcha expvar.Int
var invalidCaptcha expvar.Int

// config
var c Specification

type Specification struct {
	Port           string `required:"true"`
	CaptchaSitekey string `required:"true"`
	CaptchaSecret  string `required:"true"`
	SlackToken     string `required:"true"`
}

func init() {
	err := envconfig.Process("slackinviter", &c)
	if err != nil {
		log.Fatal(err.Error())
	}
	counter = ratecounter.NewRateCounter(1 * time.Minute)
	m.Set("hits_per_minute", &hitsPerMinute)
	m.Set("requests", &requests)
	m.Set("invite_errors", &inviteErrors)
	m.Set("missing_first_name", &missingFirstName)
	m.Set("missing_last_name", &missingLastName)
	m.Set("missing_email", &missingEmail)
	m.Set("missing_coc", &missingCoC)
	m.Set("failed_captcha", &failedCaptcha)
	m.Set("invalid_captcha", &invalidCaptcha)
	m.Set("successful_captcha", &successfulCaptcha)
	// Init stuff
	captcha = recaptcha.New(c.CaptchaSecret)
	api = slack.New(c.SlackToken)
	bufpool = bpool.NewBufferPool(64)
}
func main() {
	go pollSlack()
	mux := http.NewServeMux()
	mux.HandleFunc("/invite/", handleInvite)
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	mux.HandleFunc("/", homepage)
	mux.Handle("/debug/vars", http.DefaultServeMux)
	err := http.ListenAndServe(":"+c.Port, handlers.CombinedLoggingHandler(os.Stdout, mux))
	if err != nil {
		log.Fatal(err.Error())
	}
}
func pollSlack() {
	for {
		users, err := api.GetUsers()
		if err != nil {
			log.Println("error polling slack for users:", err)
			continue
		}
		uCount := 0 // users
		aCount := 0 // active users
		for _, u := range users {
			if u.ID != "USLACKBOT" && !u.IsBot && !u.Deleted {
				uCount += 1
				if u.Presence == "active" {
					aCount += 1
				}
			}
		}
		statsMutex.Lock()
		userCount = uCount
		activeUserCount = aCount
		statsMutex.Unlock()
		time.Sleep(10 * time.Minute)
	}
}

// Homepage renders the homepage
func homepage(w http.ResponseWriter, r *http.Request) {
	counter.Incr(1)
	hitsPerMinute.Set(counter.Rate())
	requests.Add(1)
	statsMutex.RLock()
	data := map[string]interface{}{"SiteKey": c.CaptchaSitekey, "UserCount": userCount, "ActiveCount": activeUserCount}
	statsMutex.RUnlock()
	buf := bufpool.Get()
	defer bufpool.Put(buf)
	err := indexTemplate.Execute(buf, data)
	if err != nil {
		log.Println("error rendering template:", err)
		http.Error(w, "error rendering template :-(", http.StatusInternalServerError)
		return
	}
	// Set the header and write the buffer to the http.ResponseWriter
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	buf.WriteTo(w)
}

// ShowPost renders a single post
func handleInvite(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	captchaResponse := r.FormValue("g-recaptcha-response")
	remoteIP, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		failedCaptcha.Add(1)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	valid, err := captcha.Verify(captchaResponse, remoteIP)
	if err != nil {
		failedCaptcha.Add(1)
		http.Error(w, "Error validating recaptcha.. Did you click it?", http.StatusPreconditionFailed)
		return
	}
	if !valid {
		invalidCaptcha.Add(1)
		http.Error(w, "Invalid recaptcha", http.StatusInternalServerError)
		return

	}
	successfulCaptcha.Add(1)
	fname := r.FormValue("fname")
	lname := r.FormValue("lname")
	email := r.FormValue("email")
	coc := r.FormValue("coc")
	if email == "" {
		missingEmail.Add(1)
		http.Error(w, "Missing email", http.StatusPreconditionFailed)
		return
	}
	if fname == "" {
		missingFirstName.Add(1)
		http.Error(w, "Missing first name", http.StatusPreconditionFailed)
		return
	}
	if lname == "" {
		missingLastName.Add(1)
		http.Error(w, "Missing last name", http.StatusPreconditionFailed)
		return
	}
	if coc != "1" {
		missingCoC.Add(1)
		http.Error(w, "You need to accept the code of conduct", http.StatusPreconditionFailed)
		return
	}
	err = api.InviteToTeam("Gophers", fname, lname, email)
	if err != nil {
		log.Println("InviteToTeam error:", err)
		inviteErrors.Add(1)
		http.Error(w, "Error inviting you :-(", http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>// SVFS implements a virtual file system for Openstack Swift.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/ncw/swift"
	"github.com/xlucas/svfs/svfs"

	fuse "bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
)

func main() {
	sc := swift.Connection{}
	log.SetOutput(os.Stderr)

	// FS options
	flag.StringVar(&sc.UserName, "u", "", "User name")
	flag.StringVar(&sc.ApiKey, "p", "", "User password")
	flag.StringVar(&sc.AuthUrl, "a", "https://auth.cloud.ovh.net/v2.0", "Authentication URL")
	flag.StringVar(&sc.Region, "r", "", "Region")
	flag.StringVar(&sc.Tenant, "t", "", "Tenant name")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s :\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	// Mountpoint is mandatory
	if flag.NArg() != 1 {
		flag.Usage()
		os.Exit(2)
	}
	mountpoint := os.Args[len(os.Args)-1]

	// Mount SVFS
	c, err := fuse.Mount(
		mountpoint,
		fuse.FSName("svfs"),
		fuse.Subtype("svfs"),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	// Pre-Serve: authenticate to identity endpoint
	if err = sc.Authenticate(); err != nil {
		log.Fatal(err)
	}

	// Init SVFS
	svfs := &svfs.SVFS{}
	if err = svfs.Init(&sc); err != nil {
		log.Fatal(err)
	}

	// Serve SVFS
	srv := fusefs.New(c, nil)
	if err = srv.Serve(svfs); err != nil {
		log.Fatal(err)
	}

	// Check for mount errors
	<-c.Ready
	if err = c.MountError; err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Bugfix: closes #4<commit_after>// SVFS implements a virtual file system for Openstack Swift.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/ncw/swift"
	"github.com/xlucas/svfs/svfs"

	fuse "bazil.org/fuse"
	fusefs "bazil.org/fuse/fs"
)

func main() {
	var (
		fs  *svfs.SVFS
		srv *fusefs.Server
		sc  = swift.Connection{}
	)

	// Logger
	log.SetOutput(os.Stderr)

	// FS options
	flag.StringVar(&sc.UserName, "u", "", "User name")
	flag.StringVar(&sc.ApiKey, "p", "", "User password")
	flag.StringVar(&sc.AuthUrl, "a", "https://auth.cloud.ovh.net/v2.0", "Authentication URL")
	flag.StringVar(&sc.Region, "r", "", "Region")
	flag.StringVar(&sc.Tenant, "t", "", "Tenant name")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s :\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	// Mountpoint is mandatory
	if flag.NArg() != 1 {
		flag.Usage()
		os.Exit(2)
	}
	mountpoint := os.Args[len(os.Args)-1]

	// Mount SVFS
	c, err := fuse.Mount(
		mountpoint,
		fuse.FSName("svfs"),
		fuse.Subtype("svfs"),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	// Pre-Serve: authenticate to identity endpoint
	if err = sc.Authenticate(); err != nil {
		goto Err
	}

	// Init SVFS
	fs = &svfs.SVFS{}
	if err = fs.Init(&sc); err != nil {
		goto Err
	}

	// Serve SVFS
	srv = fusefs.New(c, nil)
	if err = srv.Serve(fs); err != nil {
		goto Err
	}

	// Check for mount errors
	<-c.Ready
	if err = c.MountError; err != nil {
		goto Err
	}

	return

Err:
	fuse.Unmount(mountpoint)
	log.Fatal(err)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/kylelemons/go-gypsy/yaml"
	"github.com/shawnps/gr"
	"github.com/shawnps/rt"
	"github.com/shawnps/sp"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

var (
	port       = flag.String("p", "8000", "Port number (default 8000)")
	configFile = flag.String("c", "config.yml", "Config file (default config.yml)")
)

func getYAMLString(n yaml.Node, key string) string {
	return strings.TrimSpace(n.(yaml.Map)[key].(yaml.Scalar).String())
}

func parseYAML() (rtKey, grKey, grSecret string) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		log.Fatal(err)
	}
	configRoot, _ := config.Root.(yaml.Map)
	rtKey = configRoot["rt"].(yaml.Scalar).String()
	g := configRoot["gr"]
	grKey = getYAMLString(g, "key")
	grSecret = getYAMLString(g, "secret")

	return rtKey, grKey, grSecret
}

// Search Rotten Tomatoes, Goodreads, and Spotify.
func Search(q string, rtClient rt.RottenTomatoes, grClient gr.Goodreads, spClient sp.Spotify) (m []rt.Movie, g gr.GoodreadsResponse, s sp.SearchAlbumsResponse) {
	var wg sync.WaitGroup
	wg.Add(3)
	go func(q string) {
		defer wg.Done()
		movies, err := rtClient.SearchMovies(q)
		if err != nil {
			fmt.Println("ERROR (rt): ", err.Error())
		}
		for _, mov := range movies {
			m = append(m, mov)
		}
	}(q)
	go func(q string) {
		defer wg.Done()
		books, err := grClient.SearchBooks(q)
		if err != nil {
			fmt.Println("ERROR (gr): ", err.Error())
		}
		g = books
	}(q)
	go func(q string) {
		defer wg.Done()
		albums, err := spClient.SearchAlbums(q)
		if err != nil {
			fmt.Println("ERROR (sp): ", err.Error())
		}
		s = albums
	}(q)
	wg.Wait()
	return m, g, s
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.New("index.html").ParseFiles("templates/index.html", "templates/base.html")
	if err != nil {
		log.Panic(err)
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", nil)
	if err != nil {
		log.Panic(err)
	}
}

func SearchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	q := vars["query"]
	q, err := url.QueryUnescape(q)
	if err != nil {
		log.Panic(err)
	}
	rtKey, grKey, grSecret := parseYAML()
	rtClient := rt.RottenTomatoes{rtKey}
	grClient := gr.Goodreads{grKey, grSecret}
	spClient := sp.Spotify{}
	m, g, s := Search(q, rtClient, grClient, spClient)
	// Since spotify: URIs are not trusted, have to pass a
	// URL function to the template to use in hrefs
	funcMap := template.FuncMap{
		"URL": func(q string) template.URL { return template.URL(q) },
	}
	t, err := template.New("search.html").Funcs(funcMap).ParseFiles("templates/search.html", "templates/base.html")
	if err != nil {
		log.Panic(err)
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Movies": m, "Books": g, "Albums": s.Albums})
	if err != nil {
		log.Panic(err)
	}
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/search/{query}", SearchHandler)
	http.Handle("/", r)
	fmt.Println("Running on localhost:" + *port)

	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<commit_msg>add createDb function<commit_after>package main

import (
	"database/sql"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/kylelemons/go-gypsy/yaml"
	_ "github.com/mattn/go-sqlite3"
	"github.com/shawnps/gr"
	"github.com/shawnps/rt"
	"github.com/shawnps/sp"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

var (
	port       = flag.String("p", "8000", "Port number (default 8000)")
	configFile = flag.String("c", "config.yml", "Config file (default config.yml)")
)

func getYAMLString(n yaml.Node, key string) string {
	return strings.TrimSpace(n.(yaml.Map)[key].(yaml.Scalar).String())
}

func parseYAML() (rtKey, grKey, grSecret string) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		log.Fatal(err)
	}
	configRoot, _ := config.Root.(yaml.Map)
	rtKey = configRoot["rt"].(yaml.Scalar).String()
	g := configRoot["gr"]
	grKey = getYAMLString(g, "key")
	grSecret = getYAMLString(g, "secret")

	return rtKey, grKey, grSecret
}

func createDb() {
	db, err := sql.Open("sqlite3", "./watchreadlisten.db")
	if err != nil {
		log.Println("Error opening or creating deploy_log.db: " + err.Error())
		return
	}
	defer db.Close()
	sql := `create table if not exists entries (id integer not null primary key autoincrement, title text, link text, media_type text, timestamp datetime default current_timestamp);`
	_, err = db.Exec(sql)
	if err != nil {
		log.Println("Error creating logs table: " + err.Error())
		return
	}
}

// Search Rotten Tomatoes, Goodreads, and Spotify.
func Search(q string, rtClient rt.RottenTomatoes, grClient gr.Goodreads, spClient sp.Spotify) (m []rt.Movie, g gr.GoodreadsResponse, s sp.SearchAlbumsResponse) {
	var wg sync.WaitGroup
	wg.Add(3)
	go func(q string) {
		defer wg.Done()
		movies, err := rtClient.SearchMovies(q)
		if err != nil {
			fmt.Println("ERROR (rt): ", err.Error())
		}
		for _, mov := range movies {
			m = append(m, mov)
		}
	}(q)
	go func(q string) {
		defer wg.Done()
		books, err := grClient.SearchBooks(q)
		if err != nil {
			fmt.Println("ERROR (gr): ", err.Error())
		}
		g = books
	}(q)
	go func(q string) {
		defer wg.Done()
		albums, err := spClient.SearchAlbums(q)
		if err != nil {
			fmt.Println("ERROR (sp): ", err.Error())
		}
		s = albums
	}(q)
	wg.Wait()
	return m, g, s
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.New("index.html").ParseFiles("templates/index.html", "templates/base.html")
	if err != nil {
		log.Panic(err)
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", nil)
	if err != nil {
		log.Panic(err)
	}
}

func SearchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	q := vars["query"]
	q, err := url.QueryUnescape(q)
	if err != nil {
		log.Panic(err)
	}
	rtKey, grKey, grSecret := parseYAML()
	rtClient := rt.RottenTomatoes{rtKey}
	grClient := gr.Goodreads{grKey, grSecret}
	spClient := sp.Spotify{}
	m, g, s := Search(q, rtClient, grClient, spClient)
	// Since spotify: URIs are not trusted, have to pass a
	// URL function to the template to use in hrefs
	funcMap := template.FuncMap{
		"URL": func(q string) template.URL { return template.URL(q) },
	}
	t, err := template.New("search.html").Funcs(funcMap).ParseFiles("templates/search.html", "templates/base.html")
	if err != nil {
		log.Panic(err)
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Movies": m, "Books": g, "Albums": s.Albums})
	if err != nil {
		log.Panic(err)
	}
}

func main() {
	createDb()
	r := mux.NewRouter()
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/search/{query}", SearchHandler)
	http.Handle("/", r)
	fmt.Println("Running on localhost:" + *port)

	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/ark-lang/ark/codegen"
	"github.com/ark-lang/ark/codegen/LLVMCodegen"
	"github.com/ark-lang/ark/codegen/arkcodegen"
	"github.com/ark-lang/ark/common"
	"github.com/ark-lang/ark/doc"
	"github.com/ark-lang/ark/lexer"
	"github.com/ark-lang/ark/parser"
	"github.com/ark-lang/ark/util"
)

func main() {
	startTime := time.Now()

	verbose := true
	codegenFlag := "llvm" // defaults to none
	docFlag := false

	sourcefiles := make([]*common.Sourcefile, 0)

	// TODO write nice arg parser, should be POSIX-based
	arguments := os.Args[1:]
	for _, arg := range arguments {
		if strings.HasSuffix(arg, ".ark") {
			input, err := common.NewSourcefile(arg)
			check(err)
			sourcefiles = append(sourcefiles, input)
		} else if strings.HasPrefix(arg, "--codegen=") {
			codegenFlag = arg[len("--codegen="):]
			switch codegenFlag {
			case "none", "llvm", "ark":
				// nothing to do
			default:
				fmt.Println("Invalid argument to --codegen:", codegenFlag)
				fmt.Println("Valid arguments: none, llvm, ark")
				os.Exit(99)
			}
		} else if arg == "--version" {
			version()
			return
		} else if arg == "-v" {
			verbose = true
		} else if arg == "--docgen" {
			docFlag = true
		} else {
			fmt.Println("Unknown command:", arg)
			os.Exit(98)
		}
	}

	for _, file := range sourcefiles {
		file.Tokens = lexer.Lex(file.Contents, file.Filename, verbose)
	}

	parsedFiles := make([]*parser.File, 0)
	for _, file := range sourcefiles {
		parsedFiles = append(parsedFiles, parser.Parse(file, verbose))
	}

	if docFlag {
		docgen := &doc.Docgen{
			Input: parsedFiles,
		}
		docgen.Generate(verbose)
	} else if codegenFlag != "none" {
		var gen codegen.Codegen

		switch codegenFlag {
		case "ark":
			gen = &arkcodegen.Codegen{}
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName: "out",
			}
		default:
			panic("whoops")
		}

		gen.Generate(parsedFiles, verbose)
	}

	dur := time.Since(startTime)
	fmt.Printf("%s %d file(s) (%.2fms)\n",
		util.TEXT_GREEN+util.TEXT_BOLD+"Finished compiling"+util.TEXT_RESET,
		len(sourcefiles), float32(dur.Nanoseconds())/1000000)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func version() {
	fmt.Println("ark 2015 - experimental")
}
<commit_msg>updated version<commit_after>package main

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/ark-lang/ark/codegen"
	"github.com/ark-lang/ark/codegen/LLVMCodegen"
	"github.com/ark-lang/ark/codegen/arkcodegen"
	"github.com/ark-lang/ark/common"
	"github.com/ark-lang/ark/doc"
	"github.com/ark-lang/ark/lexer"
	"github.com/ark-lang/ark/parser"
	"github.com/ark-lang/ark/util"
)

func main() {
	startTime := time.Now()

	verbose := true
	codegenFlag := "llvm" // defaults to none
	docFlag := false

	sourcefiles := make([]*common.Sourcefile, 0)

	// TODO write nice arg parser, should be POSIX-based
	arguments := os.Args[1:]
	for _, arg := range arguments {
		if strings.HasSuffix(arg, ".ark") {
			input, err := common.NewSourcefile(arg)
			check(err)
			sourcefiles = append(sourcefiles, input)
		} else if strings.HasPrefix(arg, "--codegen=") {
			codegenFlag = arg[len("--codegen="):]
			switch codegenFlag {
			case "none", "llvm", "ark":
				// nothing to do
			default:
				fmt.Println("Invalid argument to --codegen:", codegenFlag)
				fmt.Println("Valid arguments: none, llvm, ark")
				os.Exit(99)
			}
		} else if arg == "--version" {
			version()
			return
		} else if arg == "-v" {
			verbose = true
		} else if arg == "--docgen" {
			docFlag = true
		} else {
			fmt.Println("Unknown command:", arg)
			os.Exit(98)
		}
	}

	for _, file := range sourcefiles {
		file.Tokens = lexer.Lex(file.Contents, file.Filename, verbose)
	}

	parsedFiles := make([]*parser.File, 0)
	for _, file := range sourcefiles {
		parsedFiles = append(parsedFiles, parser.Parse(file, verbose))
	}

	if docFlag {
		docgen := &doc.Docgen{
			Input: parsedFiles,
		}
		docgen.Generate(verbose)
	} else if codegenFlag != "none" {
		var gen codegen.Codegen

		switch codegenFlag {
		case "ark":
			gen = &arkcodegen.Codegen{}
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName: "out",
			}
		default:
			panic("whoops")
		}

		gen.Generate(parsedFiles, verbose)
	}

	dur := time.Since(startTime)
	fmt.Printf("%s %d file(s) (%.2fms)\n",
		util.TEXT_GREEN+util.TEXT_BOLD+"Finished compiling"+util.TEXT_RESET,
		len(sourcefiles), float32(dur.Nanoseconds())/1000000)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func version() {
	// 0.2 since LLVM/Go?
	fmt.Println("Ark version 0.2.0")
}
<|endoftext|>


<commit_before>package GraphiteBase

import (
	"fmt"
)

// The time and measured value of a metric.
type MetricValues struct {
	Time  int64
	Value float64
}

// A whole metric, whith name, time and value.
type Metric struct {
	MetricValues
	Name string
}

// Create a new metric from the given parameters.
func NewMetric(name string, value float64, timestamp int64) *Metric {
	return &Metric{
		Name: name,
		MetricValues: MetricValues{
			Value: value,
			Time: timestamp,
		},
	}
}

// Stringifies metric with "<Name> <Value> <Time>", to match Graphites Text
// protocol.
func (m *Metric) String() string {
	return fmt.Sprintf("%s %v %d", m.Name, m.Value, m.Time)
}
<commit_msg>non-fmt'ed code slipped through.<commit_after>package GraphiteBase

import (
	"fmt"
)

// The time and measured value of a metric.
type MetricValues struct {
	Time  int64
	Value float64
}

// A whole metric, whith name, time and value.
type Metric struct {
	MetricValues
	Name string
}

// Create a new metric from the given parameters.
func NewMetric(name string, value float64, timestamp int64) *Metric {
	return &Metric{
		Name: name,
		MetricValues: MetricValues{
			Value: value,
			Time:  timestamp,
		},
	}
}

// Stringifies metric with "<Name> <Value> <Time>", to match Graphites Text
// protocol.
func (m *Metric) String() string {
	return fmt.Sprintf("%s %v %d", m.Name, m.Value, m.Time)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"regexp"
	"time"

	"github.com/gojp/goreportcard/handlers"

	"github.com/boltdb/bolt"
)

var (
	addr = flag.String("http", ":8000", "HTTP listen address")
	dev  = flag.Bool("dev", false, "dev mode")
)

func makeHandler(name string, dev bool, fn func(http.ResponseWriter, *http.Request, string, bool)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		validPath := regexp.MustCompile(fmt.Sprintf(`^/%s/([a-zA-Z0-9\-_\/\.]+)$`, name))

		m := validPath.FindStringSubmatch(r.URL.Path)

		if m == nil {
			http.NotFound(w, r)
			return
		}
		if len(m) < 1 || m[1] == "" {
			http.Error(w, "Please enter a repository", http.StatusBadRequest)
			return
		}

		repo := m[1]

		// for backwards-compatibility, we must support URLs formatted as
		//   /report/[org]/[repo]
		// and they will be assumed to be github.com URLs. This is because
		// at first Go Report Card only supported github.com URLs, and assumed
		// took only the org name and repo name as parameters. This is no longer the
		// case, but we do not want external links to break.
		oldFormat := regexp.MustCompile(fmt.Sprintf(`^/%s/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)$`, name))
		m2 := oldFormat.FindStringSubmatch(r.URL.Path)
		if m2 != nil {
			// old format is being used
			repo = "github.com/" + repo
			log.Printf("Assuming intended repo is %q, redirecting", repo)
			http.Redirect(w, r, fmt.Sprintf("/%s/%s", name, repo), http.StatusMovedPermanently)
			return
		}

		fn(w, r, repo, dev)
	}
}

// initDB opens the bolt database file (or creates it if it does not exist), and creates
// a bucket for saving the repos, also only if it does not exist.
func initDB() error {
	db, err := bolt.Open(handlers.DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return err
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(handlers.RepoBucket))
		if err != nil {
			return err
		}
		_, err = tx.CreateBucketIfNotExists([]byte(handlers.MetaBucket))
		return err
	})
	return err
}

func main() {
	flag.Parse()
	if err := os.MkdirAll("_repos/src/github.com", 0755); err != nil && !os.IsExist(err) {
		log.Fatal("ERROR: could not create repos dir: ", err)
	}

	// initialize database
	if err := initDB(); err != nil {
		log.Fatal("ERROR: could not open bolt db: ", err)
	}

	http.HandleFunc("/assets/", handlers.AssetsHandler)
	http.HandleFunc("/favicon.ico", handlers.FaviconHandler)
	http.HandleFunc("/checks", handlers.CheckHandler)
	http.HandleFunc("/report/", makeHandler("report", *dev, handlers.ReportHandler))
	http.HandleFunc("/badge/", makeHandler("badge", *dev, handlers.BadgeHandler))
	http.HandleFunc("/high_scores/", handlers.HighScoresHandler)
	http.HandleFunc("/about/", handlers.AboutHandler)
	http.HandleFunc("/", handlers.HomeHandler)

	log.Printf("Running on %s ...", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>fix typo<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"regexp"
	"time"

	"github.com/gojp/goreportcard/handlers"

	"github.com/boltdb/bolt"
)

var (
	addr = flag.String("http", ":8000", "HTTP listen address")
	dev  = flag.Bool("dev", false, "dev mode")
)

func makeHandler(name string, dev bool, fn func(http.ResponseWriter, *http.Request, string, bool)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		validPath := regexp.MustCompile(fmt.Sprintf(`^/%s/([a-zA-Z0-9\-_\/\.]+)$`, name))

		m := validPath.FindStringSubmatch(r.URL.Path)

		if m == nil {
			http.NotFound(w, r)
			return
		}
		if len(m) < 1 || m[1] == "" {
			http.Error(w, "Please enter a repository", http.StatusBadRequest)
			return
		}

		repo := m[1]

		// for backwards-compatibility, we must support URLs formatted as
		//   /report/[org]/[repo]
		// and they will be assumed to be github.com URLs. This is because
		// at first Go Report Card only supported github.com URLs, and
		// took only the org name and repo name as parameters. This is no longer the
		// case, but we do not want external links to break.
		oldFormat := regexp.MustCompile(fmt.Sprintf(`^/%s/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)$`, name))
		m2 := oldFormat.FindStringSubmatch(r.URL.Path)
		if m2 != nil {
			// old format is being used
			repo = "github.com/" + repo
			log.Printf("Assuming intended repo is %q, redirecting", repo)
			http.Redirect(w, r, fmt.Sprintf("/%s/%s", name, repo), http.StatusMovedPermanently)
			return
		}

		fn(w, r, repo, dev)
	}
}

// initDB opens the bolt database file (or creates it if it does not exist), and creates
// a bucket for saving the repos, also only if it does not exist.
func initDB() error {
	db, err := bolt.Open(handlers.DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return err
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(handlers.RepoBucket))
		if err != nil {
			return err
		}
		_, err = tx.CreateBucketIfNotExists([]byte(handlers.MetaBucket))
		return err
	})
	return err
}

func main() {
	flag.Parse()
	if err := os.MkdirAll("_repos/src/github.com", 0755); err != nil && !os.IsExist(err) {
		log.Fatal("ERROR: could not create repos dir: ", err)
	}

	// initialize database
	if err := initDB(); err != nil {
		log.Fatal("ERROR: could not open bolt db: ", err)
	}

	http.HandleFunc("/assets/", handlers.AssetsHandler)
	http.HandleFunc("/favicon.ico", handlers.FaviconHandler)
	http.HandleFunc("/checks", handlers.CheckHandler)
	http.HandleFunc("/report/", makeHandler("report", *dev, handlers.ReportHandler))
	http.HandleFunc("/badge/", makeHandler("badge", *dev, handlers.BadgeHandler))
	http.HandleFunc("/high_scores/", handlers.HighScoresHandler)
	http.HandleFunc("/about/", handlers.AboutHandler)
	http.HandleFunc("/", handlers.HomeHandler)

	log.Printf("Running on %s ...", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package uploads

import (
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/db/schema"
	"github.com/materials-commons/mcstore/pkg/domain"
)

type UploadsService interface {
	Create(req CreateRequest) (*schema.Upload, error)
}

type uploadsService struct {
	dirs     dai.Dirs
	projects dai.Projects
	uploads  dai.Uploads
	access   domain.Access
}

func NewUploadsService() *uploadsService {
	session := db.RSessionMust()
	access := domain.NewAccess(dai.NewRGroups(session), dai.NewRFiles(session), dai.NewRUsers(session))
	return &uploadsService{
		dirs:     dai.NewRDirs(session),
		projects: dai.NewRProjects(session),
		uploads:  dai.NewRUploads(session),
		access:   access,
	}
}

func NewUploadsServiceFrom(dirs dai.Dirs, projects dai.Projects, uploads dai.Uploads, access domain.Access) *uploadsService {
	return &uploadsService{
		dirs:     dirs,
		projects: projects,
		uploads:  uploads,
		access:   access,
	}
}

func (s *uploadsService) Create(req CreateRequest) (*schema.Upload, error) {
	proj, err := s.getProj(req.ProjectID, req.User)
	if err != nil {
		return nil, err
	}

	dir, err := s.getDir(req.DirectoryID, proj.ID, req.User)
	if err != nil {
		return nil, err
	}

	upload := schema.CUpload().
		Owner(req.User).
		Project(req.ProjectID, proj.Name).
		Directory(req.DirectoryID, dir.Name).
		Host(req.Host).
		Create()
	return s.uploads.Insert(&upload)
}

func (s *uploadsService) getProj(projectID, user string) (*schema.Project, error) {
	project, err := s.projects.ByID(projectID)
	switch {
	case err != nil:
		return nil, err
	case !s.access.AllowedByOwner(project.Owner, user):
		return nil, app.ErrNoAccess
	default:
		return project, nil
	}
}

func (s *uploadsService) getDir(directoryID, projectID, user string) (*schema.Directory, error) {
	dir, err := s.dirs.ByID(directoryID)
	switch {
	case err != nil:
		return nil, err
	case !s.access.AllowedByOwner(dir.Owner, user):
		return nil, app.ErrNoAccess
	case !s.projects.HasDirectory(projectID, directoryID):
		return nil, app.ErrInvalid
	default:
		return dir, nil
	}
}
<commit_msg>Change service to a create service.<commit_after>package uploads

import (
	"github.com/materials-commons/mcstore/pkg/app"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/db/schema"
	"github.com/materials-commons/mcstore/pkg/domain"
)

type CreateService interface {
	Create(req CreateRequest) (*schema.Upload, error)
}

type createService struct {
	dirs     dai.Dirs
	projects dai.Projects
	uploads  dai.Uploads
	access   domain.Access
}

func NewCreateService() *createService {
	session := db.RSessionMust()
	access := domain.NewAccess(dai.NewRGroups(session), dai.NewRFiles(session), dai.NewRUsers(session))
	return &createService{
		dirs:     dai.NewRDirs(session),
		projects: dai.NewRProjects(session),
		uploads:  dai.NewRUploads(session),
		access:   access,
	}
}

func NewCreateServiceFrom(dirs dai.Dirs, projects dai.Projects, uploads dai.Uploads, access domain.Access) *createService {
	return &createService{
		dirs:     dirs,
		projects: projects,
		uploads:  uploads,
		access:   access,
	}
}

func (s *createService) Create(req CreateRequest) (*schema.Upload, error) {
	proj, err := s.getProj(req.ProjectID, req.User)
	if err != nil {
		return nil, err
	}

	dir, err := s.getDir(req.DirectoryID, proj.ID, req.User)
	if err != nil {
		return nil, err
	}

	upload := schema.CUpload().
		Owner(req.User).
		Project(req.ProjectID, proj.Name).
		Directory(req.DirectoryID, dir.Name).
		Host(req.Host).
		Create()
	return s.uploads.Insert(&upload)
}

func (s *createService) getProj(projectID, user string) (*schema.Project, error) {
	project, err := s.projects.ByID(projectID)
	switch {
	case err != nil:
		return nil, err
	case !s.access.AllowedByOwner(project.Owner, user):
		return nil, app.ErrNoAccess
	default:
		return project, nil
	}
}

func (s *createService) getDir(directoryID, projectID, user string) (*schema.Directory, error) {
	dir, err := s.dirs.ByID(directoryID)
	switch {
	case err != nil:
		return nil, err
	case !s.access.AllowedByOwner(dir.Owner, user):
		return nil, app.ErrNoAccess
	case !s.projects.HasDirectory(projectID, directoryID):
		return nil, app.ErrInvalid
	default:
		return dir, nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/mpdroog/beanstalkd" //"github.com/maxid/beanstalkd"
	"gopkg.in/gomail.v1"
	"os"
	"smtpw/config"
	"strings"
	"time"
)

const ERR_WAIT_SEC = 5

var verbose bool
var readonly bool
var hostname string

func proc(m config.Email) error {
	conf, ok := config.C.From[m.From]
	if !ok {
		return errors.New("From does not exist: " + m.From)
	}

	msg := gomail.NewMessage()
	msg.SetHeader("Message-ID", fmt.Sprintf("<%s@%s>", RandText(32), hostname))
	if conf.Bounce == nil {
		msg.SetHeader("From", conf.Display+" <"+conf.From+">")
	} else {
		// Set bounce handling
		// From receives bounces
		// Human-clients send to Reply-To
		msg.SetHeader("From", fmt.Sprintf("%s <%s>", conf.Display, *conf.Bounce))
		msg.SetHeader("Reply-To", fmt.Sprintf("%s <%s>", conf.Display, conf.From))
	}
	msg.SetHeader("To", m.To...)
	msg.SetHeader("Bcc", conf.Bcc...)
	msg.SetHeader("Subject", m.Subject)
	msg.SetBody("text/plain", m.Text)
	if len(m.Html) > 0 {
		msg.AddAlternative("text/html", m.Html)
	}

	for name, embed := range m.HtmlEmbed {
		raw, e := base64.StdEncoding.DecodeString(embed)
		if e != nil {
			return errors.New("HtmlEmbed: " + name + " is not base64!")
		}
		if !strings.Contains(m.Html, fmt.Sprintf("cid:"+name)) {
			return errors.New("HtmlEmbed: " + name + " is not used in the HTML!")
		}
		msg.Embed(gomail.CreateFile(name, raw))
	}
	for name, attachment := range m.Attachments {
		raw, e := base64.StdEncoding.DecodeString(embed)
		if e != nil {
			return errors.New("Attachment: " + name + " is not base64!")
		}
		msg.Embed(gomail.CreateFile(name, raw))
	}

	if readonly {
		fmt.Println("From: " + conf.Display + " <" + conf.From + ">")
		fmt.Println(fmt.Sprintf("To: %v", m.To))
		fmt.Println(fmt.Sprintf("Bcc: %v", conf.Bcc))
		fmt.Println("Subject: " + m.Subject)
		fmt.Println("\ntext/plain")
		fmt.Println(m.Text)
		fmt.Println("\ntext/html")
		fmt.Println(m.Html)
		fmt.Println("\n")
		return nil
	}

	mailer := gomail.NewMailer(conf.Host, conf.User, conf.Pass, conf.Port)
	return mailer.Send(msg)
}

func connect() (*beanstalkd.BeanstalkdClient, error) {
	queue, e := beanstalkd.Dial(config.C.Beanstalk)
	if e != nil {
		return nil, e
	}
	// Only listen to email queue.
	queue.Use("email")
	if _, e := queue.Watch("email"); e != nil {
		return nil, e
	}
	queue.Ignore("default")
	return queue, nil
}

func main() {
	var (
		configPath string
		skipOne    bool
	)
	flag.BoolVar(&verbose, "v", false, "Verbose-mode")
	flag.BoolVar(&skipOne, "s", false, "Delete e-mail on deverr")
	flag.BoolVar(&readonly, "r", false, "Don't email but flush to stdout")
	flag.StringVar(&configPath, "c", "./config.json", "Path to config.json")
	flag.Parse()

	if e := config.Init(configPath); e != nil {
		panic(e)
	}
	if verbose {
		fmt.Printf("%+v\n", config.C)
	}
	// TODO: Test config before starting?

	queue, e := connect()
	if e != nil {
		panic(e)
	}
	hostname, e = os.Hostname()
	if e != nil {
		panic(e)
	}

	if verbose {
		fmt.Println("SMTPw(" + hostname + ") email-tube (ignoring default)")
	}
	if readonly {
		fmt.Println("!! ReadOnly mode !!")
	}
	for {
		job, e := queue.Reserve(0)
		if e != nil {
			fmt.Println("Beanstalkd err: " + e.Error())
			time.Sleep(time.Second * ERR_WAIT_SEC)
			if strings.HasSuffix(e.Error(), "broken pipe") {
				// Beanstalkd down, reconnect!
				q, e := connect()
				if e != nil {
					fmt.Println("Reconnect err: " + e.Error())
				}
				if q != nil {
					queue = q
				}
			}
			continue
		}
		if verbose {
			fmt.Println(fmt.Sprintf("Parse job %d", job.Id))
			fmt.Println("JSON:\r\n" + string(job.Data))
		}
		// Parse
		var m config.Email
		if e := json.Unmarshal(job.Data, &m); e != nil {
			// Broken JSON
			if skipOne {
				fmt.Println("WARN: Skip job as JSON is invalid")
				queue.Delete(job.Id)
				skipOne = false
				continue
			}

			// Ignore decode trouble
			fmt.Println("CRIT: Invalid JSON received (msg=" + e.Error() + ")")
			continue
		}

		if e := proc(m); e != nil {
			// TODO: Isolate deverr from senderr
			// Processing trouble?
			fmt.Println("WARN: Failed sending, retry in 20sec (msg=" + e.Error() + ")")
			continue
		}
		queue.Delete(job.Id)
		if verbose {
			fmt.Println(fmt.Sprintf("Finished job %d", job.Id))
		}
	}
	queue.Quit()
}
<commit_msg>Bugfix. No such var embed<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/mpdroog/beanstalkd" //"github.com/maxid/beanstalkd"
	"gopkg.in/gomail.v1"
	"os"
	"smtpw/config"
	"strings"
	"time"
)

const ERR_WAIT_SEC = 5

var verbose bool
var readonly bool
var hostname string

func proc(m config.Email) error {
	conf, ok := config.C.From[m.From]
	if !ok {
		return errors.New("From does not exist: " + m.From)
	}

	msg := gomail.NewMessage()
	msg.SetHeader("Message-ID", fmt.Sprintf("<%s@%s>", RandText(32), hostname))
	if conf.Bounce == nil {
		msg.SetHeader("From", conf.Display+" <"+conf.From+">")
	} else {
		// Set bounce handling
		// From receives bounces
		// Human-clients send to Reply-To
		msg.SetHeader("From", fmt.Sprintf("%s <%s>", conf.Display, *conf.Bounce))
		msg.SetHeader("Reply-To", fmt.Sprintf("%s <%s>", conf.Display, conf.From))
	}
	msg.SetHeader("To", m.To...)
	msg.SetHeader("Bcc", conf.Bcc...)
	msg.SetHeader("Subject", m.Subject)
	msg.SetBody("text/plain", m.Text)
	if len(m.Html) > 0 {
		msg.AddAlternative("text/html", m.Html)
	}

	for name, embed := range m.HtmlEmbed {
		raw, e := base64.StdEncoding.DecodeString(embed)
		if e != nil {
			return errors.New("HtmlEmbed: " + name + " is not base64!")
		}
		if !strings.Contains(m.Html, fmt.Sprintf("cid:"+name)) {
			return errors.New("HtmlEmbed: " + name + " is not used in the HTML!")
		}
		msg.Embed(gomail.CreateFile(name, raw))
	}
	for name, attachment := range m.Attachments {
		raw, e := base64.StdEncoding.DecodeString(attachment)
		if e != nil {
			return errors.New("Attachment: " + name + " is not base64!")
		}
		msg.Embed(gomail.CreateFile(name, raw))
	}

	if readonly {
		fmt.Println("From: " + conf.Display + " <" + conf.From + ">")
		fmt.Println(fmt.Sprintf("To: %v", m.To))
		fmt.Println(fmt.Sprintf("Bcc: %v", conf.Bcc))
		fmt.Println("Subject: " + m.Subject)
		fmt.Println("\ntext/plain")
		fmt.Println(m.Text)
		fmt.Println("\ntext/html")
		fmt.Println(m.Html)
		fmt.Println("\n")
		return nil
	}

	mailer := gomail.NewMailer(conf.Host, conf.User, conf.Pass, conf.Port)
	return mailer.Send(msg)
}

func connect() (*beanstalkd.BeanstalkdClient, error) {
	queue, e := beanstalkd.Dial(config.C.Beanstalk)
	if e != nil {
		return nil, e
	}
	// Only listen to email queue.
	queue.Use("email")
	if _, e := queue.Watch("email"); e != nil {
		return nil, e
	}
	queue.Ignore("default")
	return queue, nil
}

func main() {
	var (
		configPath string
		skipOne    bool
	)
	flag.BoolVar(&verbose, "v", false, "Verbose-mode")
	flag.BoolVar(&skipOne, "s", false, "Delete e-mail on deverr")
	flag.BoolVar(&readonly, "r", false, "Don't email but flush to stdout")
	flag.StringVar(&configPath, "c", "./config.json", "Path to config.json")
	flag.Parse()

	if e := config.Init(configPath); e != nil {
		panic(e)
	}
	if verbose {
		fmt.Printf("%+v\n", config.C)
	}
	// TODO: Test config before starting?

	queue, e := connect()
	if e != nil {
		panic(e)
	}
	hostname, e = os.Hostname()
	if e != nil {
		panic(e)
	}

	if verbose {
		fmt.Println("SMTPw(" + hostname + ") email-tube (ignoring default)")
	}
	if readonly {
		fmt.Println("!! ReadOnly mode !!")
	}
	for {
		job, e := queue.Reserve(0)
		if e != nil {
			fmt.Println("Beanstalkd err: " + e.Error())
			time.Sleep(time.Second * ERR_WAIT_SEC)
			if strings.HasSuffix(e.Error(), "broken pipe") {
				// Beanstalkd down, reconnect!
				q, e := connect()
				if e != nil {
					fmt.Println("Reconnect err: " + e.Error())
				}
				if q != nil {
					queue = q
				}
			}
			continue
		}
		if verbose {
			fmt.Println(fmt.Sprintf("Parse job %d", job.Id))
			fmt.Println("JSON:\r\n" + string(job.Data))
		}
		// Parse
		var m config.Email
		if e := json.Unmarshal(job.Data, &m); e != nil {
			// Broken JSON
			if skipOne {
				fmt.Println("WARN: Skip job as JSON is invalid")
				queue.Delete(job.Id)
				skipOne = false
				continue
			}

			// Ignore decode trouble
			fmt.Println("CRIT: Invalid JSON received (msg=" + e.Error() + ")")
			continue
		}

		if e := proc(m); e != nil {
			// TODO: Isolate deverr from senderr
			// Processing trouble?
			fmt.Println("WARN: Failed sending, retry in 20sec (msg=" + e.Error() + ")")
			continue
		}
		queue.Delete(job.Id)
		if verbose {
			fmt.Println(fmt.Sprintf("Finished job %d", job.Id))
		}
	}
	queue.Quit()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strconv"
	"strings"
)

const (
	DEFAULT_PORT     = "8080"
	CF_FORWARDED_URL = "X-Cf-Forwarded-Url"
	DEFAULT_LIMIT    = 10
)

var (
	limit       int
	rateLimiter *RateLimiter
)

func main() {
	log.SetOutput(os.Stdout)

	limit = getEnv("rate_limit", DEFAULT_LIMIT)
	fmt.Printf("limit per sec [%d]\n", limit)

	rateLimiter = NewRateLimiter(limit)

	http.HandleFunc("/stats", statsHandler)
	http.Handle("/", newProxy())
	log.Fatal(http.ListenAndServe(":"+getPort(), nil))
}

func newProxy() http.Handler {
	proxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			forwardedURL := req.Header.Get(CF_FORWARDED_URL)

			url, err := url.Parse(forwardedURL)
			if err != nil {
				log.Fatalln(err.Error())
			}

			req.URL = url
			req.Host = url.Host
		},
		Transport: newRateLimitedRoundTripper(),
	}
	return proxy
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	stats, err := json.Marshal(rateLimiter.GetStats())
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Fprintf(w, string(stats))
}

func getPort() string {
	var port string
	if port = os.Getenv("PORT"); len(port) == 0 {
		port = DEFAULT_PORT
	}
	return port
}

func getEnv(env string, defaultValue int) int {
	var (
		v      string
		config int
	)
	if v = os.Getenv(env); len(v) == 0 {
		return defaultValue
	}

	config, err := strconv.Atoi(v)
	if err != nil {
		return defaultValue
	}
	return config
}

type RateLimitedRoundTripper struct {
	rateLimiter *RateLimiter
	transport   http.RoundTripper
}

func newRateLimitedRoundTripper() *RateLimitedRoundTripper {
	return &RateLimitedRoundTripper{
		rateLimiter: rateLimiter,
		transport:   http.DefaultTransport,
	}
}

func (r *RateLimitedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	var err error
	var res *http.Response

	remoteIP := strings.Split(req.RemoteAddr, ":")[0]

	fmt.Printf("request from [%s]\n", remoteIP)
	if r.rateLimiter.ExceedsLimit(remoteIP) {
		resp := &http.Response{
			StatusCode: 429,
			Body:       ioutil.NopCloser(bytes.NewBufferString("Too many requests")),
		}
		return resp, nil
	}

	res, err = r.transport.RoundTrip(req)
	if err != nil {
		return nil, err
	}
	return res, err
}
<commit_msg>Fix logging :taco:<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strconv"
	"strings"
)

const (
	DEFAULT_PORT     = "8080"
	CF_FORWARDED_URL = "X-Cf-Forwarded-Url"
	DEFAULT_LIMIT    = 10
)

var (
	limit       int
	rateLimiter *RateLimiter
)

func main() {
	log.SetOutput(os.Stdout)

	limit = getEnv("rate_limit", DEFAULT_LIMIT)
	log.Printf("limit per sec [%d]\n", limit)

	rateLimiter = NewRateLimiter(limit)

	http.HandleFunc("/stats", statsHandler)
	http.Handle("/", newProxy())
	log.Fatal(http.ListenAndServe(":"+getPort(), nil))
}

func newProxy() http.Handler {
	proxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			forwardedURL := req.Header.Get(CF_FORWARDED_URL)

			url, err := url.Parse(forwardedURL)
			if err != nil {
				log.Fatalln(err.Error())
			}

			req.URL = url
			req.Host = url.Host
		},
		Transport: newRateLimitedRoundTripper(),
	}
	return proxy
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	stats, err := json.Marshal(rateLimiter.GetStats())
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, string(stats))
}

func getPort() string {
	var port string
	if port = os.Getenv("PORT"); len(port) == 0 {
		port = DEFAULT_PORT
	}
	return port
}

func getEnv(env string, defaultValue int) int {
	var (
		v      string
		config int
	)
	if v = os.Getenv(env); len(v) == 0 {
		return defaultValue
	}

	config, err := strconv.Atoi(v)
	if err != nil {
		return defaultValue
	}
	return config
}

type RateLimitedRoundTripper struct {
	rateLimiter *RateLimiter
	transport   http.RoundTripper
}

func newRateLimitedRoundTripper() *RateLimitedRoundTripper {
	return &RateLimitedRoundTripper{
		rateLimiter: rateLimiter,
		transport:   http.DefaultTransport,
	}
}

func (r *RateLimitedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	var err error
	var res *http.Response

	remoteIP := strings.Split(req.RemoteAddr, ":")[0]

	log.Printf("request from [%s]\n", remoteIP)
	if r.rateLimiter.ExceedsLimit(remoteIP) {
		resp := &http.Response{
			StatusCode: 429,
			Body:       ioutil.NopCloser(bytes.NewBufferString("Too many requests")),
		}
		return resp, nil
	}

	res, err = r.transport.RoundTrip(req)
	if err != nil {
		return nil, err
	}
	return res, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"

	adrianConfig "github.com/daveross/adrian/config"
	adrianFonts "github.com/daveross/adrian/fonts"
	adrianServer "github.com/daveross/adrian/server"

	"github.com/labstack/echo"
)

func main() {

	log.Println("Starting Adrian 2.0")
	log.Println("Loading adrian.yaml")
	config := adrianConfig.LoadConfig("./adrian.yaml")
	log.Println("Initializing web server")
	e := adrianServer.Instantiate(config)
	log.Println("Loading fonts and starting watchers")
	for _, folder := range config.Global.Directories {
		adrianFonts.FindFonts(folder, config)
		adrianFonts.InstantiateWatcher(folder, config)
	}
	log.Println("Defining paths")

	e.GET("/css/", func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, "text/css")
		fontFilenames := strings.Split(c.QueryParam("family"), "|")
		var fontsCSS string
		for _, fontFilename := range fontFilenames {
			fontData, err := adrianFonts.GetFont(fontFilename)
			if err != nil {
				return adrianServer.Return404(c)
			}
			fontsCSS = fontsCSS + "\n" + fontData.CSS
		}
		return c.String(http.StatusOK, fontsCSS)
	})

	e.GET("/font/:filename/", func(c echo.Context) error {
		switch filepath.Ext(url.QueryUnescape(c.Param("filename"))) {
		case ".ttf":
			return outputFont(c, "font/truetype")
		case ".woff":
			return outputFont(c, "font/woff")
		case ".woff2":
			return outputFont(c, "font/woff2")
		case ".otf":
			return outputFont(c, "font/opentype")
		}

		return adrianServer.Return404(c)
	})

	log.Printf("Listening on port %d", config.Global.Port)
	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", config.Global.Port)))
}

// Basename gets the base filename (minus the last extension)
func basename(s string) string {
	n := strings.LastIndexByte(s, '.')
	if n >= 0 {
		return s[:n]
	}
	return s
}

func outputFont(c echo.Context, mimeType string) error {

	fontVariant, err := adrianFonts.GetFontVariantByUniqueID(basename(c.Param("filename")))
	if err != nil {
		return adrianServer.Return404(c)
	}

	fontFileData, ok := fontVariant.Files[adrianFonts.GetCanonicalExtension(c.Param("filename"))]
	if !ok {
		log.Fatal("Invalid font format" + adrianFonts.GetCanonicalExtension(c.Param("filename")))
	}

	fontBinary, err := ioutil.ReadFile(fontFileData.Path) // just pass the file name
	if err != nil {
		log.Fatal("Can't read font file " + fontFileData.FileName)
	}

	c.Response().Header().Set("Content-Transfer-Encoding", "binary")
	return c.Blob(http.StatusOK, mimeType, fontBinary)

}
<commit_msg>QueryUnescape returns two values<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"

	adrianConfig "github.com/daveross/adrian/config"
	adrianFonts "github.com/daveross/adrian/fonts"
	adrianServer "github.com/daveross/adrian/server"

	"github.com/labstack/echo"
)

func main() {

	log.Println("Starting Adrian 2.0")
	log.Println("Loading adrian.yaml")
	config := adrianConfig.LoadConfig("./adrian.yaml")
	log.Println("Initializing web server")
	e := adrianServer.Instantiate(config)
	log.Println("Loading fonts and starting watchers")
	for _, folder := range config.Global.Directories {
		adrianFonts.FindFonts(folder, config)
		adrianFonts.InstantiateWatcher(folder, config)
	}
	log.Println("Defining paths")

	e.GET("/css/", func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, "text/css")
		fontFilenames := strings.Split(c.QueryParam("family"), "|")
		var fontsCSS string
		for _, fontFilename := range fontFilenames {
			fontData, err := adrianFonts.GetFont(fontFilename)
			if err != nil {
				return adrianServer.Return404(c)
			}
			fontsCSS = fontsCSS + "\n" + fontData.CSS
		}
		return c.String(http.StatusOK, fontsCSS)
	})

	e.GET("/font/:filename/", func(c echo.Context) error {
		filename, error := url.QueryUnescape(c.Param("filename"))
		if error != nil {
			return adrianServer.Return404(c)
		}

		switch filepath.Ext(filename) {
		case ".ttf":
			return outputFont(c, "font/truetype")
		case ".woff":
			return outputFont(c, "font/woff")
		case ".woff2":
			return outputFont(c, "font/woff2")
		case ".otf":
			return outputFont(c, "font/opentype")
		}

		return adrianServer.Return404(c)
	})

	log.Printf("Listening on port %d", config.Global.Port)
	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", config.Global.Port)))
}

// Basename gets the base filename (minus the last extension)
func basename(s string) string {
	n := strings.LastIndexByte(s, '.')
	if n >= 0 {
		return s[:n]
	}
	return s
}

func outputFont(c echo.Context, mimeType string) error {

	fontVariant, err := adrianFonts.GetFontVariantByUniqueID(basename(c.Param("filename")))
	if err != nil {
		return adrianServer.Return404(c)
	}

	fontFileData, ok := fontVariant.Files[adrianFonts.GetCanonicalExtension(c.Param("filename"))]
	if !ok {
		log.Fatal("Invalid font format" + adrianFonts.GetCanonicalExtension(c.Param("filename")))
	}

	fontBinary, err := ioutil.ReadFile(fontFileData.Path) // just pass the file name
	if err != nil {
		log.Fatal("Can't read font file " + fontFileData.FileName)
	}

	c.Response().Header().Set("Content-Transfer-Encoding", "binary")
	return c.Blob(http.StatusOK, mimeType, fontBinary)

}
<|endoftext|>


<commit_before>package main

/*
 * A shiny status page.
 *
 * Want it to combine my existing idle page and tiny-care-terminal.
 *
 * Things to include:
 *  - some twitter accounts
 *      - @tinycarebot, @selfcare_bot and @magicrealismbot. Maybe that boat one instead of magic realism.
 *  - weather
 *  - recent git commits
 *  - system status:
 *      - User/hostname
 *      - Kerberos ticket status
 *      - Current time
 *      - Uptime
 *      - Battery and time left
 *      - Audio status and volume
 *      - Network
 *          - Local, docker, wireless
 *      - Disk
 *          - Mounts, free/used/total/percentage w/ color
 *      - CPU
 *          - Load average w/ color
 *          - Percentage
 *          - Top processes?
 *      - Status of git repos
 *
 * Minimum terminal size to support:
 *  - 189x77 (half monitor with some stacks)
 *  - 104x56ish? (half the laptop screen with some stacks)
 *  - 100x50? (nice and round)
 *  - 80x40? (my default putty)
 *
 */

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/user"
	"time"

	linuxproc "github.com/c9s/goprocinfo/linux"
	ui "github.com/gizak/termui"
)

var timerCounter uint64 = 0
var lastTimer uint64 = 0

/**
 * Make a string as wide as requested, with stuff left justified and right justified.
 *
 * width:       How wide to get.
 * left:        What text goes on the left?
 * right:       What text goes on the right?
 * fillChar:    What character to use as the filler.
 */
func fitAStringToWidth(width int, left string, right string, fillChar string) string {
	// TODO: This
	return left + fillChar + right
}

func makeP(l string) *ui.Par {
	p := ui.NewPar(l)
	p.Height = 5
	p.BorderLabel = l

	return p
}

func execAndGetOutput(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)

	var out bytes.Buffer
	cmd.Stdout = &out

	err := cmd.Run()

	return out.String(), err
}

func getUsername() string {
	curUser, userErr := user.Current()
	userName := "unknown"
	if userErr == nil {
		userName = curUser.Username
	}

	return userName
}

func getHostname() (string, string) {
	hostName, hostErr := os.Hostname()
	if hostErr != nil {
		hostName = "unknown"
	}

	prettyName, prettyNameErr := execAndGetOutput("pretty-hostname")

	if prettyNameErr == nil {
		return hostName, prettyName
	} else {
		return hostName, hostName
	}
}

func getTime() (time.Time, *linuxproc.Uptime) {
	now := time.Now().UTC()
	uptime, err := linuxproc.ReadUptime("/proc/uptime")

	if err != nil {
		uptime = nil
	}

	return now, uptime

}

// Header: User @ hostname
func makeHeader() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("")
	w.Height = 3

	// Static information
	userName := getUsername()
	hostName, prettyName := getHostname()
	var userHostHeader string

	if prettyName != hostName {
		// Host/pretty name are different
		userHostHeader = fmt.Sprintf(" %v @ %v (%v) ", userName, prettyName, hostName)
	} else {
		// Host/pretty name are the same (or pretty failed)
		userHostHeader = fmt.Sprintf(" %v @ %v ", userName, hostName)
	}

	// Function for dynamic information
	f := func(count uint64) {
		now, uptime := getTime()
		nowStr := now.Format(time.RFC1123Z)
		uptimeStr := uptime.GetTotalDuration()

		timeStr := fmt.Sprintf("%v (%v)", nowStr, uptimeStr)

		w.BorderLabel = fitAStringToWidth(ui.TermWidth()-4, userHostHeader, timeStr, "-")
	}

	// Load dynamic info
	f(0)

	return w, f
}

func makeNetwork() (*ui.Par, *ui.Table, func(uint64), func()) {
	// Create container
	c := ui.NewPar("Networking")

	// Create widget
	w := ui.NewTable()
	w.Height = 8
	w.Border = false

	var lastCount uint64 = 0

	// Function for dynamic information
	f := func(count uint64) {
		if (count == 0) || ((count - lastCount) >= 30000) {
			// First try, or after a period of time
			lastCount = count

			// Load network interfaces and information
			rows := [][]string{
				[]string{"interface0", "interface2", "interface3"},
				[]string{"123.456.789.123", "123.456.789.123", "123.456.789.123"},
			}

			w.Rows = rows

			w.Analysis()
			w.SetSize()
		}
	}

	// Function for resizes
	r := func() {
		c.X = w.X
		c.Y = w.Y
		c.Width = w.Width
		c.Height = w.Height
	}

	// Load dynamic info
	f(0)
	r()

	return c, w, f, r
}

func makeTime() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("Time")
	w.Height = 4

	c := 1

	// Function for dynamic information
	f := func(count uint64) {
		w.BorderLabel = fmt.Sprintf("Time (%v)", c)
		c = c + 1

		now, uptime := getTime()
		nowStr := now.Format(time.RFC1123Z)
		uptimeStr := uptime.GetTotalDuration()

		w.Text = fmt.Sprintf("Now: %v\nUptime: %v", nowStr, uptimeStr)
	}

	// Load dynamic info
	f(0)

	return w, f
}

func makeBattAudio() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("")
	w.Height = 3

	// Static information
	curUser, userErr := user.Current()
	userName := "unknown"
	if userErr == nil {
		userName = curUser.Username
	}

	hostName, hostErr := os.Hostname()
	if hostErr != nil {
		hostName = "unknown"
	}

	prettyName, prettyNameErr := execAndGetOutput("pretty-hostname")

	if (prettyNameErr == nil) && (prettyName != hostName) {
		// Host/pretty name are different
		w.BorderLabel = fmt.Sprintf(" %v @ %v (%v) ", userName, prettyName, hostName)
	} else {
		// Host/pretty name are the same (or pretty failed)
		w.BorderLabel = fmt.Sprintf(" %v @ %v ", userName, hostName)
	}

	// Function for dynamic information
	f := func(count uint64) {
		if count == 0 {
			// Invoked at startup
		} else {
			// Invoked on timer
		}
	}

	// Load dynamic info
	f(0)

	return w, f
}

func main() {
	// Set up the console UI
	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer log.Printf("Final Timer: %v (%v)", timerCounter, lastTimer)
	defer ui.Close()

	ui.DefaultEvtStream.Merge("timer", ui.NewTimerCh(5*time.Second))

	//
	// Create the widgets
	//

	header, headerFunc := makeHeader()
	networkContainer, network, networkFunc, networkResize := makeNetwork()
	time, timeFunc := makeTime()

	battAudio := makeP("battery/audio")
	disk := makeP("disk")
	cpu := makeP("cpu")
	repo := makeP("repos")
	commits := makeP("commits")
	twitter1 := makeP("tinycare")
	twitter2 := makeP("selfcare")
	twitter3 := makeP("a strange voyage")
	weather := makeP("weather")

	//
	// Create the layout
	//

	// Header box
	header.X = 0
	header.Y = 0
	header.Width = ui.TermWidth()
	header.Height = ui.TermHeight()

	// Allow the header box to wrap all around
	ui.Body.Width = ui.TermWidth() - 2
	ui.Body.X = 1
	ui.Body.Y = 1

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(3, 0, network),
			ui.NewCol(3, 0, disk),
			ui.NewCol(3, 0, cpu),
			ui.NewCol(3, 0, battAudio)),
		ui.NewRow(
			ui.NewCol(12, 0, time)),
		ui.NewRow(
			ui.NewCol(6, 0, repo),
			ui.NewCol(6, 0, commits)),
		ui.NewRow(
			ui.NewCol(3, 0, weather),
			ui.NewCol(3, 0, twitter1),
			ui.NewCol(3, 0, twitter2),
			ui.NewCol(3, 0, twitter3)))

	ui.Body.Align()

	render := func() {
		ui.Body.Align()
		ui.Clear()
		ui.Render(header, networkContainer, ui.Body)
	}

	//
	//  Activate
	//

	log.Printf("Failed: %v", timerCounter)

	render()

	ui.Handle("/sys/kbd/q", func(ui.Event) {
		// press q to quit
		ui.StopLoop()
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		// ctrl-c to quit
		ui.StopLoop()
	})

	ui.Handle("/timer/5s", func(e ui.Event) {
		t := e.Data.(ui.EvtTimer)
		i := t.Count

		timerCounter++
		lastTimer = i

		log.Printf("Timer: %v (%v)", timerCounter, lastTimer)

		// Call all update funcs
		headerFunc(lastTimer)
		networkFunc(lastTimer)
		timeFunc(lastTimer)

		// Re-render
		render()
	})

	ui.Handle("/sys/wnd/resize", func(ui.Event) {
		// Update header on resize
		header.Width = ui.TermWidth()
		header.Height = ui.TermHeight()

		// Re-layout on resize
		ui.Body.Width = ui.TermWidth() - 2

		// Update resize funcs
		networkResize()

		// Re-render
		render()
	})

	ui.Loop()
}
<commit_msg>Fixed header stuff.<commit_after>package main

/*
 * A shiny status page.
 *
 * Want it to combine my existing idle page and tiny-care-terminal.
 *
 * Things to include:
 *  - some twitter accounts
 *      - @tinycarebot, @selfcare_bot and @magicrealismbot. Maybe that boat one instead of magic realism.
 *  - weather
 *  - recent git commits
 *  - system status:
 *      - User/hostname
 *      - Kerberos ticket status
 *      - Current time
 *      - Uptime
 *      - Battery and time left
 *      - Audio status and volume
 *      - Network
 *          - Local, docker, wireless
 *      - Disk
 *          - Mounts, free/used/total/percentage w/ color
 *      - CPU
 *          - Load average w/ color
 *          - Percentage
 *          - Top processes?
 *      - Status of git repos
 *
 * Minimum terminal size to support:
 *  - 189x77 (half monitor with some stacks)
 *  - 104x56ish? (half the laptop screen with some stacks)
 *  - 100x50? (nice and round)
 *  - 80x40? (my default putty)
 *
 */

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/user"
	"strings"
	"time"
	"unicode/utf8"

	linuxproc "github.com/c9s/goprocinfo/linux"
	ui "github.com/gizak/termui"
)

var timerCounter uint64 = 0
var lastTimer uint64 = 0

/**
 * Make a string as wide as requested, with stuff left justified and right justified.
 *
 * width:       How wide to get.
 * left:        What text goes on the left?
 * right:       What text goes on the right?
 * fillChar:    What character to use as the filler.
 */
func fitAStringToWidth(width int, left string, right string, fillChar string) string {
	leftLen := utf8.RuneCountInString(left)
	rightLen := utf8.RuneCountInString(right)
	fillCharLen := utf8.RuneCountInString(fillChar) // Usually 1

	// Figure out how many filler chars we need
	fillLen := width - (leftLen + rightLen)
	fillRunes := (fillLen - 1 + fillCharLen) / fillCharLen
	fillStr := strings.Repeat(fillChar, fillRunes)

	return fmt.Sprintf("%s %s %s", left, fillStr, right)
}

func makeP(l string) *ui.Par {
	p := ui.NewPar(l)
	p.Height = 5
	p.BorderLabel = l

	return p
}

func execAndGetOutput(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)

	var out bytes.Buffer
	cmd.Stdout = &out

	err := cmd.Run()

	return out.String(), err
}

func getUsername() string {
	curUser, userErr := user.Current()
	userName := "unknown"
	if userErr == nil {
		userName = curUser.Username
	}

	return userName
}

func getHostname() (string, string) {
	hostName, hostErr := os.Hostname()
	if hostErr != nil {
		hostName = "unknown"
	}

	prettyName, prettyNameErr := execAndGetOutput("pretty-hostname")

	if prettyNameErr == nil {
		return hostName, prettyName
	} else {
		return hostName, hostName
	}
}

func getTime() (time.Time, *linuxproc.Uptime) {
	now := time.Now().UTC()
	uptime, err := linuxproc.ReadUptime("/proc/uptime")

	if err != nil {
		uptime = nil
	}

	return now, uptime

}

// Header: User @ hostname
func makeHeader() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("")
	w.Height = 3

	// Static information
	userName := getUsername()
	hostName, prettyName := getHostname()
	var userHostHeader string

	if prettyName != hostName {
		// Host/pretty name are different
		userHostHeader = fmt.Sprintf(" %v @ %v (%v)", userName, prettyName, hostName)
	} else {
		// Host/pretty name are the same (or pretty failed)
		userHostHeader = fmt.Sprintf("%v @ %v", userName, hostName)
	}

	// Function for dynamic information
	f := func(count uint64) {
		now, uptime := getTime()
		nowStr := now.Format(time.RFC1123Z)
		uptimeStr := uptime.GetTotalDuration()

		timeStr := fmt.Sprintf("%v (%v) ", nowStr, uptimeStr)

		w.BorderLabel = fitAStringToWidth(ui.TermWidth()-4, userHostHeader, timeStr, "-")
	}

	// Load dynamic info
	f(0)

	return w, f
}

func makeNetwork() (*ui.Par, *ui.Table, func(uint64), func()) {
	// Create container
	c := ui.NewPar("Networking")

	// Create widget
	w := ui.NewTable()
	w.Height = 8
	w.Border = false

	var lastCount uint64 = 0

	// Function for dynamic information
	f := func(count uint64) {
		if (count == 0) || ((count - lastCount) >= 30000) {
			// First try, or after a period of time
			lastCount = count

			// Load network interfaces and information
			rows := [][]string{
				[]string{"interface0", "interface2", "interface3"},
				[]string{"123.456.789.123", "123.456.789.123", "123.456.789.123"},
			}

			w.Rows = rows

			w.Analysis()
			w.SetSize()
		}
	}

	// Function for resizes
	r := func() {
		c.X = w.X
		c.Y = w.Y
		c.Width = w.Width
		c.Height = w.Height
	}

	// Load dynamic info
	f(0)
	r()

	return c, w, f, r
}

func makeTime() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("Time")
	w.Height = 4

	c := 1

	// Function for dynamic information
	f := func(count uint64) {
		w.BorderLabel = fmt.Sprintf("Time (%v)", c)
		c = c + 1

		now, uptime := getTime()
		nowStr := now.Format(time.RFC1123Z)
		uptimeStr := uptime.GetTotalDuration()

		w.Text = fmt.Sprintf("Now: %v\nUptime: %v", nowStr, uptimeStr)
	}

	// Load dynamic info
	f(0)

	return w, f
}

func makeBattAudio() (*ui.Par, func(uint64)) {
	// Create widget
	w := ui.NewPar("")
	w.Height = 3

	// Static information
	curUser, userErr := user.Current()
	userName := "unknown"
	if userErr == nil {
		userName = curUser.Username
	}

	hostName, hostErr := os.Hostname()
	if hostErr != nil {
		hostName = "unknown"
	}

	prettyName, prettyNameErr := execAndGetOutput("pretty-hostname")

	if (prettyNameErr == nil) && (prettyName != hostName) {
		// Host/pretty name are different
		w.BorderLabel = fmt.Sprintf(" %v @ %v (%v) ", userName, prettyName, hostName)
	} else {
		// Host/pretty name are the same (or pretty failed)
		w.BorderLabel = fmt.Sprintf(" %v @ %v ", userName, hostName)
	}

	// Function for dynamic information
	f := func(count uint64) {
		if count == 0 {
			// Invoked at startup
		} else {
			// Invoked on timer
		}
	}

	// Load dynamic info
	f(0)

	return w, f
}

func main() {
	// Set up the console UI
	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer log.Printf("Final Timer: %v (%v)", timerCounter, lastTimer)
	defer ui.Close()

	ui.DefaultEvtStream.Merge("timer", ui.NewTimerCh(5*time.Second))

	//
	// Create the widgets
	//

	header, headerFunc := makeHeader()
	//networkContainer, network, networkFunc, networkResize := makeNetwork()
	_, network, networkFunc, networkResize := makeNetwork()
	time, timeFunc := makeTime()

	battAudio := makeP("battery/audio")
	disk := makeP("disk")
	cpu := makeP("cpu")
	repo := makeP("repos")
	commits := makeP("commits")
	twitter1 := makeP("tinycare")
	twitter2 := makeP("selfcare")
	twitter3 := makeP("a strange voyage")
	weather := makeP("weather")

	//
	// Create the layout
	//

	// Header box
	header.X = 0
	header.Y = 0
	header.Width = ui.TermWidth()
	header.Height = ui.TermHeight()

	// Allow the header box to wrap all around
	ui.Body.Width = ui.TermWidth() - 2
	ui.Body.X = 1
	ui.Body.Y = 1

	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(3, 0, network),
			ui.NewCol(3, 0, disk),
			ui.NewCol(3, 0, cpu),
			ui.NewCol(3, 0, battAudio)),
		ui.NewRow(
			ui.NewCol(12, 0, time)),
		ui.NewRow(
			ui.NewCol(6, 0, repo),
			ui.NewCol(6, 0, commits)),
		ui.NewRow(
			ui.NewCol(3, 0, weather),
			ui.NewCol(3, 0, twitter1),
			ui.NewCol(3, 0, twitter2),
			ui.NewCol(3, 0, twitter3)))

	ui.Body.Align()

	render := func() {
		ui.Body.Align()
		ui.Clear()
		//ui.Render(header, networkContainer, ui.Body)
		ui.Render(header, ui.Body)
	}

	//
	//  Activate
	//

	log.Printf("Failed: %v", timerCounter)

	render()

	ui.Handle("/sys/kbd/q", func(ui.Event) {
		// press q to quit
		ui.StopLoop()
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		// ctrl-c to quit
		ui.StopLoop()
	})

	ui.Handle("/timer/5s", func(e ui.Event) {
		t := e.Data.(ui.EvtTimer)
		i := t.Count

		timerCounter++
		lastTimer = i

		log.Printf("Timer: %v (%v)", timerCounter, lastTimer)

		// Call all update funcs
		headerFunc(lastTimer)
		networkFunc(lastTimer)
		timeFunc(lastTimer)

		// Re-render
		render()
	})

	ui.Handle("/sys/wnd/resize", func(ui.Event) {
		// Update header on resize
		header.Width = ui.TermWidth()
		header.Height = ui.TermHeight()

		// Re-layout on resize
		ui.Body.Width = ui.TermWidth() - 2

		// Update resize funcs
		networkResize()

		// Re-render
		render()
	})

	ui.Loop()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
)

var streams []stream
var commands []*exec.Cmd

type stream struct {
	Name   string
	Stream string
	Image  string
}

func main() {
	//Read in urls of webcams from configuration file
	data, err := ioutil.ReadFile("streams.json")
	if err != nil {
		panic(err)
	}

	if err := json.Unmarshal(data, &streams); err != nil {
		panic(err)
	}

	//Startup webserver to listen to commands to execute video player
	http.HandleFunc("/", serveIndex)
	http.HandleFunc("/all", serveAll)
	http.HandleFunc("/pick", serveOne)
	// showAll()
	log.Fatal(http.ListenAndServe(":2000", nil))
}

func renderWebsite(w http.ResponseWriter) {
	const tpl = `
<!DOCTYPE html>

		<meta charset="UTF-8">
		<title>Zoo Cam Viewer</title>

All

		{{range .Streams}}
{{ .Name }}

{{else}}
no streams
{{end}}

`
	t, err := template.New("webpage").Parse(tpl)
	if err != nil {
		panic(err)
	}
	t.Execute(w, struct{ Streams []stream }{Streams: streams})
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	//Serve up basic website with icons to choose from with "all" option
	renderWebsite(w)
}

func serveAll(w http.ResponseWriter, r *http.Request) {
	//Close all existing processes, and fire up all the videos
	showAll()
	renderWebsite(w)
}

func serveOne(w http.ResponseWriter, r *http.Request) {
	//Close all existing processes, and fire up the single video passed in
	name := r.FormValue("name")
	log.Println("got stream name of " + name)
	for _, stream := range streams {
		if stream.Name == name {
			log.Println("Starting stream " + stream.Name)
			showOne(stream)
		}
	}
	renderWebsite(w)
}

func showAll() {
	killAll()
	width := 1900
	height := 1200
	streamCount := len(streams)

	//Determine how many streams we have to make even boxed grids
	boxes := 1
	for ; boxes*boxes < streamCount; boxes++ {
	}

	startWidth := 0
	startHeight := 0
	widthStep := width / boxes
	heightStep := height / boxes
	//We now have a box X box width screen (say 3x3), so split the screen appropriately
	for index, s := range streams {
		endWidth := startWidth + (index * widthStep)
		endHeight := startHeight + (index * heightStep)
		log.Printf("end width is %v and end height is %v\n", endWidth, endHeight)
		cmd := exec.Command("omxplayer", "--win", fmt.Sprintf("%v,%v,%v,%v", startWidth, startHeight, endWidth, endHeight), s.Stream)
		cmd.Stdout = os.Stdout
		cmd.Start()
		commands = append(commands, cmd)
	}
}

func showOne(s stream) {
	killAll()
	//Startup in fullscreen
	cmd := exec.Command("omxplayer", s.Stream)
	cmd.Start()
	commands = append(commands, cmd)
}

func killAll() {
	log.Println("killing all existing streams")
	for _, proc := range commands {
		proc.Process.Kill()
	}
}
<commit_msg>switching back to mplayer for additional testing, leaving omxplayer commented for easy switching<commit_after>package main

import (
	"encoding/json"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
)

var streams []stream
var commands []*exec.Cmd

type stream struct {
	Name   string
	Stream string
	Image  string
}

func main() {
	//Read in urls of webcams from configuration file
	data, err := ioutil.ReadFile("streams.json")
	if err != nil {
		panic(err)
	}

	if err := json.Unmarshal(data, &streams); err != nil {
		panic(err)
	}

	//Startup webserver to listen to commands to execute video player
	http.HandleFunc("/", serveIndex)
	http.HandleFunc("/all", serveAll)
	http.HandleFunc("/pick", serveOne)
	// showAll()
	log.Fatal(http.ListenAndServe(":2000", nil))
}

func renderWebsite(w http.ResponseWriter) {
	const tpl = `
<!DOCTYPE html>

		<meta charset="UTF-8">
		<title>Zoo Cam Viewer</title>

All

		{{range .Streams}}
{{ .Name }}

{{else}}
no streams
{{end}}

`
	t, err := template.New("webpage").Parse(tpl)
	if err != nil {
		panic(err)
	}
	t.Execute(w, struct{ Streams []stream }{Streams: streams})
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	//Serve up basic website with icons to choose from with "all" option
	renderWebsite(w)
}

func serveAll(w http.ResponseWriter, r *http.Request) {
	//Close all existing processes, and fire up all the videos
	showAll()
	renderWebsite(w)
}

func serveOne(w http.ResponseWriter, r *http.Request) {
	//Close all existing processes, and fire up the single video passed in
	name := r.FormValue("name")
	log.Println("got stream name of " + name)
	for _, stream := range streams {
		if stream.Name == name {
			log.Println("Starting stream " + stream.Name)
			showOne(stream)
		}
	}
	renderWebsite(w)
}

func showAll() {
	killAll()
	width := 1900
	height := 1200
	streamCount := len(streams)

	//Determine how many streams we have to make even boxed grids
	boxes := 1
	for ; boxes*boxes < streamCount; boxes++ {
	}

	startWidth := 0
	startHeight := 0
	widthStep := width / boxes
	heightStep := height / boxes
	//We now have a box X box width screen (say 3x3), so split the screen appropriately
	for index, s := range streams {
		endWidth := startWidth + (index * widthStep)
		endHeight := startHeight + (index * heightStep)
		log.Printf("end width is %v and end height is %v\n", endWidth, endHeight)
		// cmd := exec.Command("omxplayer", "--win", fmt.Sprintf("%v,%v,%v,%v", startWidth, startHeight, endWidth, endHeight), s.Stream)
		cmd := exec.Command("mplayer", s.Stream)
		cmd.Stdout = os.Stdout
		cmd.Start()
		commands = append(commands, cmd)
	}
}

func showOne(s stream) {
	killAll()
	//Startup in fullscreen
	// cmd := exec.Command("omxplayer", s.Stream)
	cmd := exec.Command("mplayer", s.Stream)
	cmd.Start()
	commands = append(commands, cmd)
}

func killAll() {
	log.Println("killing all existing streams")
	for _, proc := range commands {
		proc.Process.Kill()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/astaxie/beego"
	"github.com/mingzhehao/beego-blog/g"
	_ "github.com/mingzhehao/beego-blog/routers"
)

func main() {
	g.InitEnv()
	beego.Run()
}
<commit_msg>目录名称调整<commit_after>package main

import (
	"github.com/astaxie/beego"
	"github.com/mingzhehao/scloud/g"
	_ "github.com/mingzhehao/scloud/routers"
)

func main() {
	g.InitEnv()
	beego.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/urfave/cli.v1"
)

var version string
var pathToData string

func main() {
	app := cli.NewApp()
	app.Name = "linkcrawler"
	app.Usage = "crawl a site for links, or download a list of sites"
	app.Version = version
	app.Compiled = time.Now()
	app.Action = func(c *cli.Context) error {
		if !c.GlobalBool("debug") {
			turnOffDebugger()
		}
		pathToData = c.GlobalString("data")
		os.MkdirAll(pathToData, 0755)
		fmt.Printf("\nRunning CowYo at http://%s:%s\n\n", GetLocalIP(), c.GlobalString("port"))
		serve(c.GlobalString("port"))
		return nil
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "data",
			Value: "data",
			Usage: "data folder to use",
		},
		cli.StringFlag{
			Name:  "olddata",
			Value: "",
			Usage: "data folder for migrating",
		},
		cli.StringFlag{
			Name:  "port,p",
			Value: "8050",
			Usage: "port to use",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "turn on debugging",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "migrate",
			Aliases: []string{"m"},
			Usage:   "migrate from the old cowyo",
			Action: func(c *cli.Context) error {
				if !c.GlobalBool("debug") {
					turnOffDebugger()
				}
				pathToData = c.GlobalString("data")
				pathToOldData := c.GlobalString("olddata")
				if len(pathToOldData) == 0 {
					fmt.Printf("You need to specify folder with -olddata")
					return nil
				}
				os.MkdirAll(pathToData, 0755)
				if !exists(pathToOldData) {
					fmt.Printf("Can not find '%s', does it exist?", pathToOldData)
					return nil
				}
				migrate(pathToOldData, pathToData)
				return nil
			},
		},
	}

	app.Run(os.Args)

}
<commit_msg>Changed app info<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/urfave/cli.v1"
)

var version string
var pathToData string

func main() {
	app := cli.NewApp()
	app.Name = "cowyo"
	app.Usage = "a simple wiki"
	app.Version = version
	app.Compiled = time.Now()
	app.Action = func(c *cli.Context) error {
		if !c.GlobalBool("debug") {
			turnOffDebugger()
		}
		pathToData = c.GlobalString("data")
		os.MkdirAll(pathToData, 0755)
		fmt.Printf("\nRunning CowYo at http://%s:%s\n\n", GetLocalIP(), c.GlobalString("port"))
		serve(c.GlobalString("port"))
		return nil
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "data",
			Value: "data",
			Usage: "data folder to use",
		},
		cli.StringFlag{
			Name:  "olddata",
			Value: "",
			Usage: "data folder for migrating",
		},
		cli.StringFlag{
			Name:  "port,p",
			Value: "8050",
			Usage: "port to use",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "turn on debugging",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "migrate",
			Aliases: []string{"m"},
			Usage:   "migrate from the old cowyo",
			Action: func(c *cli.Context) error {
				if !c.GlobalBool("debug") {
					turnOffDebugger()
				}
				pathToData = c.GlobalString("data")
				pathToOldData := c.GlobalString("olddata")
				if len(pathToOldData) == 0 {
					fmt.Printf("You need to specify folder with -olddata")
					return nil
				}
				os.MkdirAll(pathToData, 0755)
				if !exists(pathToOldData) {
					fmt.Printf("Can not find '%s', does it exist?", pathToOldData)
					return nil
				}
				migrate(pathToOldData, pathToData)
				return nil
			},
		},
	}

	app.Run(os.Args)

}
<|endoftext|>