<commit_before>package main

// Implements a server that tails Graphite's logs
// finds out when new data sources become available
// and serves out a UI that lets you see/render those
// continiously.

// Written by J.A. Oldenbeuving / ojilles@gmail.com

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/rcrowley/go-metrics"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
	//"github.com/jteeuwen/go-bindata"
)

type Datasource struct {
	Name        string
	Create_date time.Time
	Params      string
}

type state struct {
	*sync.RWMutex // inherits locking methods
	Vals          []Datasource
}

type configuration struct {
	JsonPullInterval int
	GraphiteURL      string
	ServerPort       int
	logfileLocation  string
}

const myLogFormat = log.Ldate | log.Ltime

// declare a globally scoped State variable, otherwise
// the request handlers can't get to it. If there is a better
// way to do this, plmk.
var State = &state{&sync.RWMutex{}, []Datasource{}}

const maxState int = 1000

// Instantiate struct to hold our configuration
var C = configuration{JsonPullInterval: 5000, GraphiteURL: "asdfsdfadsf"}

func init() {
	flag.IntVar(&C.JsonPullInterval, "i", 5000, "Number of [ms] interval for Web UI's to update themselves. Clients only update their config every 5min")
	flag.IntVar(&C.ServerPort, "p", 2934, "Port number the webserver will bind to (pick a free one please)")
	flag.StringVar(&C.logfileLocation, "l", "creates.log", "Location of the Carbon logfiles we need to tail")
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := log.New(os.Stdout, "http	", myLogFormat)

		m := metrics.GetOrRegisterTimer(fmt.Sprintf("%s%s", r.Method, r.URL.Path), metrics.DefaultRegistry)
		m.Time(func() {
			fn(w, r)
		})
		l.Printf("Request: %v %v %v", r.Method, r.URL, r.RemoteAddr)
	}
}

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	State.RLock() // grab a lock, but then don't forget to
	js, err := json.Marshal(State.Vals)
	State.RUnlock() // unlock it again once we're done

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

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	metrics.WriteJSONOnce(metrics.DefaultRegistry, w)
}

func configHandler(w http.ResponseWriter, r *http.Request) {
	js, _ := json.Marshal(C)
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func frontpageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	data, _ := Asset("index.html")
	data, _ = Asset("index2.html")
	if len(data) == 0 {
		data = []byte("Fatal Error: index.html file not found.")
	}
	w.Write(data)
}

func parseTime(s string) time.Time {
	// 24/08/2014 20:59:54
	var t, _ = time.Parse("02/01/2006 15:04:05", s)
	return t
}

func addItemToState(ds Datasource) {
	var foundDuplicate = false
	l := log.New(os.Stdout, "tail	", myLogFormat)
	m_ds := metrics.GetOrRegisterCounter("tail/datasources", metrics.DefaultRegistry)

	// Find out if we already have one with the same name, if
	// so skip it.
	State.RLock()
	for i := 0; i < len(State.Vals) && !foundDuplicate; i++ {
		if ds.Name == State.Vals[i].Name {
			foundDuplicate = true
		}
	}
	State.RUnlock()

	if !foundDuplicate {
		// We're writing to shared datastructures, grab a Write-lock
		State.Lock()
		defer State.Unlock()
		State.Vals = append(State.Vals, ds)
		defer m_ds.Inc(1)
		if len(State.Vals) > maxState {
			State.Vals = State.Vals[:1000]
		}
		l.Printf("New datasource: %+v (total: %v)", ds.Name, len(State.Vals))
	}
}

func tailLogfile(c chan string) {
	m_lines := metrics.GetOrRegisterCounter("tail/input_lines", metrics.DefaultRegistry)

	var dataPath = regexp.MustCompile(`.*out:(.*) :: \[creates\] creating database file .*/whisper/(.*)\.wsp (.*)`)
	t, err := tail.TailFile(C.logfileLocation, tail.Config{Follow: true, ReOpen: true, MustExist: true})
	if err == nil {
		for line := range t.Lines {
			m_lines.Inc(1)
			match := dataPath.FindStringSubmatch(line.Text)
			if len(match) > 0 {
				ds := fmt.Sprintf("%s", strings.Replace(match[2], `/`, `.`, -1))
				tmp := Datasource{Name: ds, Create_date: parseTime(match[1]), Params: match[3]}
				addItemToState(tmp)
			}
		}
	}
	c <- fmt.Sprintf("%s", err)
}

func main() {
	error_channel := make(chan string)
	l := log.New(os.Stdout, "main	", myLogFormat)
	flag.Parse()

	// Set up metrics registry
	//	go metrics.Log(
	//		metrics.DefaultRegistry,
	//		5e9, // Xe9 -> X seconds
	//		log.New(os.Stdout, "metrics	", myLogFormat))

	// Set up web handlers in goroutines
	http.HandleFunc("/", makeHandler(frontpageHandler))
	http.HandleFunc("/json/", makeHandler(jsonHandler))
	http.HandleFunc("/stats/", makeHandler(statsHandler))
	http.HandleFunc("/config/", makeHandler(configHandler))

	http.Handle("/assets/",
		http.StripPrefix("/assets/",
			http.FileServer(http.Dir("./assets"))))
	go http.ListenAndServe(fmt.Sprintf(":%v", C.ServerPort), nil)
	go tailLogfile(error_channel)

	l.Println("Graphite News -- Showing which new metrics are available since 2014\n")
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v		:: Main User Interface", C.ServerPort))
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v/config/	:: Internal configuration in JSON", C.ServerPort))
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v/stats/	:: Internal Metrics in JSON", C.ServerPort))
	l.Println(fmt.Sprintf("Configuration: %+v", C))
	// Wait for errors to appear then shut down
	l.Println(<-error_channel)
}
<commit_msg>Oeps, removing testing code<commit_after>package main

// Implements a server that tails Graphite's logs
// finds out when new data sources become available
// and serves out a UI that lets you see/render those
// continiously.

// Written by J.A. Oldenbeuving / ojilles@gmail.com

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/rcrowley/go-metrics"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
	//"github.com/jteeuwen/go-bindata"
)

type Datasource struct {
	Name        string
	Create_date time.Time
	Params      string
}

type state struct {
	*sync.RWMutex // inherits locking methods
	Vals          []Datasource
}

type configuration struct {
	JsonPullInterval int
	GraphiteURL      string
	ServerPort       int
	logfileLocation  string
}

const myLogFormat = log.Ldate | log.Ltime

// declare a globally scoped State variable, otherwise
// the request handlers can't get to it. If there is a better
// way to do this, plmk.
var State = &state{&sync.RWMutex{}, []Datasource{}}

const maxState int = 1000

// Instantiate struct to hold our configuration
var C = configuration{JsonPullInterval: 5000, GraphiteURL: "asdfsdfadsf"}

func init() {
	flag.IntVar(&C.JsonPullInterval, "i", 5000, "Number of [ms] interval for Web UI's to update themselves. Clients only update their config every 5min")
	flag.IntVar(&C.ServerPort, "p", 2934, "Port number the webserver will bind to (pick a free one please)")
	flag.StringVar(&C.logfileLocation, "l", "creates.log", "Location of the Carbon logfiles we need to tail")
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := log.New(os.Stdout, "http	", myLogFormat)

		m := metrics.GetOrRegisterTimer(fmt.Sprintf("%s%s", r.Method, r.URL.Path), metrics.DefaultRegistry)
		m.Time(func() {
			fn(w, r)
		})
		l.Printf("Request: %v %v %v", r.Method, r.URL, r.RemoteAddr)
	}
}

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	State.RLock() // grab a lock, but then don't forget to
	js, err := json.Marshal(State.Vals)
	State.RUnlock() // unlock it again once we're done

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

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	metrics.WriteJSONOnce(metrics.DefaultRegistry, w)
}

func configHandler(w http.ResponseWriter, r *http.Request) {
	js, _ := json.Marshal(C)
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func frontpageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	data, _ := Asset("index.html")
	if len(data) == 0 {
		data = []byte("Fatal Error: index.html file not found.")
	}
	w.Write(data)
}

func parseTime(s string) time.Time {
	// 24/08/2014 20:59:54
	var t, _ = time.Parse("02/01/2006 15:04:05", s)
	return t
}

func addItemToState(ds Datasource) {
	var foundDuplicate = false
	l := log.New(os.Stdout, "tail	", myLogFormat)
	m_ds := metrics.GetOrRegisterCounter("tail/datasources", metrics.DefaultRegistry)

	// Find out if we already have one with the same name, if
	// so skip it.
	State.RLock()
	for i := 0; i < len(State.Vals) && !foundDuplicate; i++ {
		if ds.Name == State.Vals[i].Name {
			foundDuplicate = true
		}
	}
	State.RUnlock()

	if !foundDuplicate {
		// We're writing to shared datastructures, grab a Write-lock
		State.Lock()
		defer State.Unlock()
		State.Vals = append(State.Vals, ds)
		defer m_ds.Inc(1)
		if len(State.Vals) > maxState {
			State.Vals = State.Vals[:1000]
		}
		l.Printf("New datasource: %+v (total: %v)", ds.Name, len(State.Vals))
	}
}

func tailLogfile(c chan string) {
	m_lines := metrics.GetOrRegisterCounter("tail/input_lines", metrics.DefaultRegistry)

	var dataPath = regexp.MustCompile(`.*out:(.*) :: \[creates\] creating database file .*/whisper/(.*)\.wsp (.*)`)
	t, err := tail.TailFile(C.logfileLocation, tail.Config{Follow: true, ReOpen: true, MustExist: true})
	if err == nil {
		for line := range t.Lines {
			m_lines.Inc(1)
			match := dataPath.FindStringSubmatch(line.Text)
			if len(match) > 0 {
				ds := fmt.Sprintf("%s", strings.Replace(match[2], `/`, `.`, -1))
				tmp := Datasource{Name: ds, Create_date: parseTime(match[1]), Params: match[3]}
				addItemToState(tmp)
			}
		}
	}
	c <- fmt.Sprintf("%s", err)
}

func main() {
	error_channel := make(chan string)
	l := log.New(os.Stdout, "main	", myLogFormat)
	flag.Parse()

	// Set up metrics registry
	//	go metrics.Log(
	//		metrics.DefaultRegistry,
	//		5e9, // Xe9 -> X seconds
	//		log.New(os.Stdout, "metrics	", myLogFormat))

	// Set up web handlers in goroutines
	http.HandleFunc("/", makeHandler(frontpageHandler))
	http.HandleFunc("/json/", makeHandler(jsonHandler))
	http.HandleFunc("/stats/", makeHandler(statsHandler))
	http.HandleFunc("/config/", makeHandler(configHandler))

	http.Handle("/assets/",
		http.StripPrefix("/assets/",
			http.FileServer(http.Dir("./assets"))))
	go http.ListenAndServe(fmt.Sprintf(":%v", C.ServerPort), nil)
	go tailLogfile(error_channel)

	l.Println("Graphite News -- Showing which new metrics are available since 2014\n")
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v		:: Main User Interface", C.ServerPort))
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v/config/	:: Internal configuration in JSON", C.ServerPort))
	l.Println(fmt.Sprintf("Graphite News -- http://localhost:%v/stats/	:: Internal Metrics in JSON", C.ServerPort))
	l.Println(fmt.Sprintf("Configuration: %+v", C))
	// Wait for errors to appear then shut down
	l.Println(<-error_channel)
}
<|endoftext|>


<commit_before>package main

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

func newCommand(args []string) {
	var (
		format string
		name   string
	)
	fs := flag.NewFlagSet("new", flag.ExitOnError)
	fs.StringVar(&format, "format", "date", "shorthand of format")
	fs.StringVar(&name, "name", "", "specify the file name")

	fs.Parse(args)
	fmt.Println("format:", format)
	fmt.Println("name:", name)
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) == 0 {
		os.Exit(0)
	}
	switch args[0] {
	case "new":
		newCommand(args[1:])
	default:
		os.Exit(0)
	}
}
<commit_msg>Implement new commend<commit_after>package main

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

func newCommand(args []string) {
	var (
		format string
		name   string
	)
	fs := flag.NewFlagSet("new", flag.ExitOnError)
	fs.StringVar(&format, "format", "date", "specify the format of prefix")
	fs.StringVar(&name, "name", "", "specify the file name")

	fs.Parse(args)

	fn, err := fileName(format, name)
	if err != nil {
		log.Fatal(err)
		return
	}

	err = createFile(fn, ".")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fn, "is generated")
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) == 0 {
		os.Exit(0)
	}
	switch args[0] {
	case "new":
		newCommand(args[1:])
	default:
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jideji/servicelauncher/config"
	"github.com/jideji/servicelauncher/service"
	"github.com/jideji/servicelauncher/web"
	"net/http"
	"os"
	"sort"
)

func main() {
	if len(os.Args) < 2 {
		showHelp()
	}

	action := os.Args[1]

	services := config.LoadServices()

	if action == "server" {
		h := web.WebHandler(services)
		http.Handle("/", h)
		fmt.Println("Listening on port :8080")
		err := http.ListenAndServe(":8080", nil)
		if err != nil {
			panic(err)
		}
		return
	}

	selected := resolveServices(services, os.Args[2:]...)

	lastErrCode := 0
	for _, service := range selected {
		err := doAction(service, action)
		if err != nil {
			if c, ok := err.(CmdError); ok {
				println(c.Msg)
				lastErrCode = c.Code
			} else {
				println(err.Error())
			}
		}
	}

	os.Exit(lastErrCode)
}

func resolveServices(services map[string]service.Service, names ...string) []service.Service {
	var selected []service.Service
	if len(names) > 0 {
		for _, name := range names {
			service, ok := services[name]
			if !ok {
				println(fmt.Sprintf("No service named '%s' found.", name))
				os.Exit(10)
			}
			selected = append(selected, service)
		}
	} else {
		for _, service := range services {
			selected = append(selected, service)
		}
	}
	sort.Sort(byName(selected))

	return selected
}

func doAction(srv service.Service, action string) error {
	running, err := srv.IsRunning()
	if err != nil {
		return err
	}

	if action == "status" {
		if running {
			pid, _ := srv.Pid()
			fmt.Printf("Service '%s' is running with pid %d.\n", srv.Name(), pid)
		} else {
			fmt.Printf("Service '%s' is not running.\n", srv.Name())
		}
		return nil
	}

	if action == "stop" || action == "restart" {
		if running {
			pid, err := srv.Pid()
			if err != nil {
				return err
			}
			fmt.Printf("Killing service '%s' (process %d).\n", srv.Name(), pid)
			srv.Stop()
			running = false
		} else {
			fmt.Printf("Service '%s' not running.\n", srv.Name())
		}
	}

	if action == "start" || action == "restart" {
		if running {
			return cmdError(fmt.Sprintf("Service '%s' already running. Try restart.", srv.Name()), 11)
		}
		err := srv.Start()
		if err != nil {
			return err
		}
		pid, err := srv.Pid()
		if err != nil {
			return err
		}
		fmt.Printf("Service '%s' started with pid %d.\n", srv.Name(), pid)
	}
	return nil
}

func showHelp() {
	fmt.Fprint(os.Stderr, "SYNTAX:\n")
	fmt.Fprintf(os.Stderr, "\t%s <action> [<service name>]\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\t%s server\n", os.Args[0])
	fmt.Fprint(os.Stderr, "Actions:\n")
	fmt.Fprint(os.Stderr, "\tstart, stop, restart, status\n")
	fmt.Fprint(os.Stderr, "Examples:\n")
	fmt.Fprintf(os.Stderr, "\t%s start httpserver\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\t%s status\n", os.Args[0])
	os.Exit(1)
}

func cmdError(msg string, code int) error {
	return CmdError{Msg: msg, Code: code}
}

type CmdError struct {
	Msg  string
	Code int
}

func (c CmdError) Error() string {
	return c.Msg
}

// ByName implements sort.Interface for []ServiceStatus based on
// the Name field.
type byName []service.Service

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
<commit_msg>Added colorful status indicator to output for services.<commit_after>package main

import (
	"fmt"
	"github.com/jideji/servicelauncher/config"
	"github.com/jideji/servicelauncher/service"
	"github.com/jideji/servicelauncher/web"
	"net/http"
	"os"
	"sort"
)

func main() {
	if len(os.Args) < 2 {
		showHelp()
	}

	action := os.Args[1]

	services := config.LoadServices()

	if action == "server" {
		h := web.WebHandler(services)
		http.Handle("/", h)
		fmt.Println("Listening on port :8080")
		err := http.ListenAndServe(":8080", nil)
		if err != nil {
			panic(err)
		}
		return
	}

	selected := resolveServices(services, os.Args[2:]...)

	lastErrCode := 0
	for _, service := range selected {
		err := doAction(service, action)
		if err != nil {
			if c, ok := err.(CmdError); ok {
				println(c.Msg)
				lastErrCode = c.Code
			} else {
				println(err.Error())
			}
		}
	}

	os.Exit(lastErrCode)
}

func resolveServices(services map[string]service.Service, names ...string) []service.Service {
	var selected []service.Service
	if len(names) > 0 {
		for _, name := range names {
			service, ok := services[name]
			if !ok {
				println(fmt.Sprintf("No service named '%s' found.", name))
				os.Exit(10)
			}
			selected = append(selected, service)
		}
	} else {
		for _, service := range services {
			selected = append(selected, service)
		}
	}
	sort.Sort(byName(selected))

	return selected
}

func doAction(srv service.Service, action string) error {
	running, err := srv.IsRunning()
	if err != nil {
		return err
	}

	if action == "status" {
		if running {
			pid, _ := srv.Pid()
			fmt.Printf("(\033[32mx\033[0m) Service '%s' is running with pid %d.\n", srv.Name(), pid)
		} else {
			fmt.Printf("( ) Service '%s' is not running.\n", srv.Name())
		}
		return nil
	}

	if action == "stop" || action == "restart" {
		if running {
			pid, err := srv.Pid()
			if err != nil {
				return err
			}
			fmt.Printf("Killing service '%s' (process %d).\n", srv.Name(), pid)
			srv.Stop()
			running = false
		} else {
			fmt.Printf("(\033[33m!\033[0m) Service '%s' not running.\n", srv.Name())
		}
	}

	if action == "start" || action == "restart" {
		if running {
			return cmdError(fmt.Sprintf("(\033[31m!\033[0m) Service '%s' already running. Try restart.", srv.Name()), 11)
		}
		err := srv.Start()
		if err != nil {
			return err
		}
		pid, err := srv.Pid()
		if err != nil {
			return err
		}
		fmt.Printf("Service '%s' started with pid %d.\n", srv.Name(), pid)
	}
	return nil
}

func showHelp() {
	fmt.Fprint(os.Stderr, "SYNTAX:\n")
	fmt.Fprintf(os.Stderr, "\t%s <action> [<service name>]\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\t%s server\n", os.Args[0])
	fmt.Fprint(os.Stderr, "Actions:\n")
	fmt.Fprint(os.Stderr, "\tstart, stop, restart, status\n")
	fmt.Fprint(os.Stderr, "Examples:\n")
	fmt.Fprintf(os.Stderr, "\t%s start httpserver\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\t%s status\n", os.Args[0])
	os.Exit(1)
}

func cmdError(msg string, code int) error {
	return CmdError{Msg: msg, Code: code}
}

type CmdError struct {
	Msg  string
	Code int
}

func (c CmdError) Error() string {
	return c.Msg
}

// ByName implements sort.Interface for []ServiceStatus based on
// the Name field.
type byName []service.Service

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/cptspacetoaster/slackbot/robots"
	"github.com/gorilla/schema"
)

func main() {
	http.HandleFunc("/slack", SlashCommandHandler)
	http.HandleFunc("/slack_hook", HookHandler)
	StartServer()
}

func HookHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.OutgoingWebHook)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	c := strings.Split(command.Text, " ")
	command.Robot = c[1]
	command.Text = strings.Join(c[2:], " ")

	robot := GetRobot(command.Robot)
	if robot == nil {
		jsonResp(w, "No robot for that command yet :(")
		return
	}
	w.WriteHeader(http.StatusOK)
	jsonResp(w, robot.Run(&command.Payload))
}

func SlashCommandHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.SlashCommand)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	command.Robot = command.Command[1:]
	robot := GetRobot(command.Robot)
	if robot == nil {
		plainResp(w, "No robot for that command yet :(")
		return
	}
	plainResp(w, robot.Run(&command.Payload))
}

func jsonResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	resp := map[string]string{"text": msg}
	r, err := json.Marshal(resp)
	if err != nil {
		log.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}

func plainResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(msg))
}

func StartServer() {
	port := robots.Config.Port
	log.Printf("Starting HTTP server on %d", port)
	err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
	if err != nil {
		log.Fatal("Server start error: ", err)
	}
}

func GetRobot(command string) robots.Robot {
	if r, ok := robots.Robots[command]; ok {
		return r
	}
	return nil
}
<commit_msg>Change to outgoing-webhook parsing<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/cptspacetoaster/slackbot/robots"
	"github.com/gorilla/schema"
)

func main() {
	http.HandleFunc("/slack", SlashCommandHandler)
	http.HandleFunc("/slack_hook", HookHandler)
	StartServer()
}

func HookHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.OutgoingWebHook)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	log.Printf("Recieved command: %s from \"%s\"\n", command.Text[1:len(command.Text)], command.TeamDomain)
	//Assume outgoing webhooks are preceded with a character
	c := strings.Split(command.Text[1:len(command.Text)], " ")
	command.Robot = c[0]
	command.Text = strings.Join(c[1:], " ")

	robot := GetRobot(command.Robot)
	if robot == nil {
		jsonResp(w, "No robot for that command yet :(")
		return
	}
	w.WriteHeader(http.StatusOK)
	jsonResp(w, robot.Run(&command.Payload))
}

func SlashCommandHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	d := schema.NewDecoder()
	command := new(robots.SlashCommand)
	err = d.Decode(command, r.PostForm)
	if err != nil {
		log.Println("Couldn't parse post request:", err)
	}
	command.Robot = command.Command[1:]
	robot := GetRobot(command.Robot)
	if robot == nil {
		plainResp(w, "No robot for that command yet :(")
		return
	}
	plainResp(w, robot.Run(&command.Payload))
}

func jsonResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	resp := map[string]string{"text": msg}
	r, err := json.Marshal(resp)
	if err != nil {
		log.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}

func plainResp(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(msg))
}

func StartServer() {
	port := robots.Config.Port
	log.Printf("Starting HTTP server on %d", port)
	err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
	if err != nil {
		log.Fatal("Server start error: ", err)
	}
}

func GetRobot(command string) robots.Robot {
	if r, ok := robots.Robots[command]; ok {
		return r
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"

	baps3 "github.com/UniversityRadioYork/baps3-go"
	"github.com/docopt/docopt-go"
)

func parseArgs() (args map[string]interface{}, err error) {
	usage := `ury-listd-go.

Usage:
  ury-listd-go [-p <port>] [-a <address>] [-P <port>] [-A <address>]
  ury-listd-go -h
  ury-listd-go -v

Options:
  -p --port=<port>              The port ury-listd-go listens on [default: 1351].
  -a --addr=<address>           The host ury-listd-go listens on [default: 127.0.0.1].
  -P --playoutport=<port>       The playout system's listening port [default: 1350].
  -A --playoutaddr=<address>    The playout system's listening address [default: 127.0.0.1].
  -h --help                     Show this screen.
  -v --version                  Show version.`

	return docopt.Parse(usage, nil, true, "ury-listd-go 0.0", false)
}

func main() {
	logger := log.New(os.Stdout, "", log.Lshortfile)
	args, err := parseArgs()
	if err != nil {
		logger.Fatal("Error parsing args: " + err.Error())
	}

	// Set up server listener
	serverCh := make(chan baps3.Message)
	server, err := MakeServer(args["--addr"].(string), args["--port"].(string), serverCh)
	if err != nil {
		logger.Fatal("Error initialising connection server: " + err.Error())
	}
	go server.run()

	// Set up connection to playout
	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGINT)

	responseCh := make(chan baps3.Message)
	wg := new(sync.WaitGroup)
	wg.Add(1)
	connector := baps3.InitConnector("", responseCh, wg, logger)
	connector.Connect(args["--playoutaddr"].(string) + ":" + args["--playoutport"].(string))
	go connector.Run()

	// Main loop
	for {
		select {
		case res := <-responseCh:
			logger.Println(res.String())
		case <-sigs:
			logger.Println("Exiting...")
			close(connector.ReqCh)
			wg.Wait()
			os.Exit(0)
		}
	}
}
<commit_msg>Use global logger where appropriate<commit_after>package main

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"

	baps3 "github.com/UniversityRadioYork/baps3-go"
	"github.com/docopt/docopt-go"
)

func parseArgs() (args map[string]interface{}, err error) {
	usage := `ury-listd-go.

Usage:
  ury-listd-go [-p <port>] [-a <address>] [-P <port>] [-A <address>]
  ury-listd-go -h
  ury-listd-go -v

Options:
  -p --port=<port>              The port ury-listd-go listens on [default: 1351].
  -a --addr=<address>           The host ury-listd-go listens on [default: 127.0.0.1].
  -P --playoutport=<port>       The playout system's listening port [default: 1350].
  -A --playoutaddr=<address>    The playout system's listening address [default: 127.0.0.1].
  -h --help                     Show this screen.
  -v --version                  Show version.`

	return docopt.Parse(usage, nil, true, "ury-listd-go 0.0", false)
}

func main() {
	log.SetFlags(log.Lshortfile) // Set up default logger
	args, err := parseArgs()
	if err != nil {
		log.Fatal("Error parsing args: " + err.Error())
	}

	// Set up server listener
	serverCh := make(chan baps3.Message)
	server, err := MakeServer(args["--addr"].(string), args["--port"].(string), serverCh)
	if err != nil {
		log.Fatal("Error initialising connection server: " + err.Error())
	}
	go server.run()

	// Set up connection to playout
	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGINT)

	responseCh := make(chan baps3.Message)
	wg := new(sync.WaitGroup)
	wg.Add(1)
	connLog := log.New(os.Stderr, "playd: ", 0)
	connector := baps3.InitConnector("", responseCh, wg, connLog)
	connector.Connect(args["--playoutaddr"].(string) + ":" + args["--playoutport"].(string))
	go connector.Run()

	// Main connector loop
	for {
		select {
		case res := <-responseCh:
			// Pass stuff through to server
			connLog.Println(res.String())
			server.ProcessCommand(res)
		case <-sigs:
			log.Println("Exiting...")
			close(connector.ReqCh)
			wg.Wait()
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type Builtin struct {
	Run func(args []string)
}

var BUILTINS = map[string]*Builtin{
	"cd": &Builtin{func(args []string) {
		os.Chdir(args[0])
	}},
	"exit": &Builtin{func(args []string) {
		var code int
		if len(args) == 1 {
			code, _ = strconv.Atoi(args[0])
		}
		os.Exit(code)
	}},
	"exec": &Builtin{func(args []string) {
		cmd := exec.Command(args[0], args[1:]...)
		spawnPrograms(cmd)
	}},
	"set": &Builtin{func(args []string) {
		for _, arg := range args {
			keyValuePair := strings.Split(arg, "=")
			if len(keyValuePair) == 2 {
				os.Setenv(keyValuePair[0], keyValuePair[1])
			}
		}
	}},
}

func init() {
	os.Setenv("PROMPT", "->")
}

func main() {
	prompt()

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		commands := splitOnPipes(scanner.Text())

		var cmds []*exec.Cmd
		for _, command := range commands {
			name, args := parseCommand(command)
			if name == "" {
				continue
			}

			if isBuiltin(name) {
				callBuiltin(name, args)
			} else {
				cmd := exec.Command(name, args...)
				cmds = append(cmds, cmd)
			}
		}

		if len(cmds) > 0 {
			spawnPrograms(cmds...)
		}

		prompt()
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "Reading standard input:", err)
	}
}

func prompt() {
	fmt.Fprintf(os.Stdout, "%s ", os.Getenv("PROMPT"))
}

func splitOnPipes(line string) (commands []string) {
	pipeRegexp := regexp.MustCompile("([^\"'|]+)|[\"']([^\"']+)[\"']")
	if pipeRegexp.MatchString(line) {
		commands = pipeRegexp.FindAllString(line, -1)
	} else {
		commands = append(commands, line)
	}

	for i, command := range commands {
		commands[i] = strings.TrimSpace(command)
	}

	return
}

func parseCommand(line string) (name string, args []string) {
	regexpBySpace := regexp.MustCompile("\\s+")
	cmd := regexpBySpace.Split(line, -1)

	name = cmd[0]
	// expand environment variables
	// somehow os/exec.Command.Run() doesn't expand automatically
	envVarRegexp := regexp.MustCompile("^\\$(.+)$")
	for _, arg := range cmd[1:] {
		if envVarRegexp.MatchString(arg) {
			match := envVarRegexp.FindStringSubmatch(arg)
			arg = os.Getenv(match[1])
		}

		args = append(args, arg)
	}

	return
}

func isBuiltin(name string) bool {
	_, ok := BUILTINS[name]

	return ok
}

func callBuiltin(name string, args []string) {
	builtin, _ := BUILTINS[name]
	builtin.Run(args)
}

func spawnPrograms(cmds ...*exec.Cmd) {
	stdout, stderr, err := pipeline(cmds)
	if err != nil {
		fmt.Printf("%s\n", err)
	}

	if len(stdout) > 0 {
		fmt.Printf("%s", stdout)
	}

	if len(stderr) > 0 {
		fmt.Printf("%s", stderr)
	}
}

func pipeline(cmds []*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error) {
	// Collect the output from the command(s)
	var output bytes.Buffer
	var stderr bytes.Buffer

	last := len(cmds) - 1
	for i, cmd := range cmds[:last] {
		var err error
		// Connect each command's stdin to the previous command's stdout
		if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
			return nil, nil, err
		}
		// Connect each command's stderr to a buffer
		cmd.Stderr = &stderr
	}

	// Connect the output and error for the last command
	cmds[last].Stdout, cmds[last].Stderr = &output, &stderr

	// Start each command
	for _, cmd := range cmds {
		if err := cmd.Start(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Wait for each command to complete
	for _, cmd := range cmds {
		if err := cmd.Wait(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Return the pipeline output and the collected standard error
	return output.Bytes(), stderr.Bytes(), nil
}
<commit_msg>Simpler promopt implementation<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

type Builtin struct {
	Run func(args []string)
}

var BUILTINS = map[string]*Builtin{
	"cd": &Builtin{func(args []string) {
		os.Chdir(args[0])
	}},
	"exit": &Builtin{func(args []string) {
		var code int
		if len(args) == 1 {
			code, _ = strconv.Atoi(args[0])
		}
		os.Exit(code)
	}},
	"exec": &Builtin{func(args []string) {
		cmd := exec.Command(args[0], args[1:]...)
		spawnPrograms(cmd)
	}},
	"set": &Builtin{func(args []string) {
		for _, arg := range args {
			keyValuePair := strings.Split(arg, "=")
			if len(keyValuePair) == 2 {
				os.Setenv(keyValuePair[0], keyValuePair[1])
			}
		}
	}},
}

func init() {
	os.Setenv("PROMPT", "-> ")
}

func main() {
	prompt()

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		commands := splitOnPipes(scanner.Text())

		var cmds []*exec.Cmd
		for _, command := range commands {
			name, args := parseCommand(command)
			if name == "" {
				continue
			}

			if isBuiltin(name) {
				callBuiltin(name, args)
			} else {
				cmd := exec.Command(name, args...)
				cmds = append(cmds, cmd)
			}
		}

		if len(cmds) > 0 {
			spawnPrograms(cmds...)
		}

		prompt()
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "Reading standard input:", err)
	}
}

func prompt() {
	fmt.Printf(os.Getenv("PROMPT"))
}

func splitOnPipes(line string) (commands []string) {
	pipeRegexp := regexp.MustCompile("([^\"'|]+)|[\"']([^\"']+)[\"']")
	if pipeRegexp.MatchString(line) {
		commands = pipeRegexp.FindAllString(line, -1)
	} else {
		commands = append(commands, line)
	}

	for i, command := range commands {
		commands[i] = strings.TrimSpace(command)
	}

	return
}

func parseCommand(line string) (name string, args []string) {
	regexpBySpace := regexp.MustCompile("\\s+")
	cmd := regexpBySpace.Split(line, -1)

	name = cmd[0]
	// expand environment variables
	// somehow os/exec.Command.Run() doesn't expand automatically
	envVarRegexp := regexp.MustCompile("^\\$(.+)$")
	for _, arg := range cmd[1:] {
		if envVarRegexp.MatchString(arg) {
			match := envVarRegexp.FindStringSubmatch(arg)
			arg = os.Getenv(match[1])
		}

		args = append(args, arg)
	}

	return
}

func isBuiltin(name string) bool {
	_, ok := BUILTINS[name]

	return ok
}

func callBuiltin(name string, args []string) {
	builtin, _ := BUILTINS[name]
	builtin.Run(args)
}

func spawnPrograms(cmds ...*exec.Cmd) {
	stdout, stderr, err := pipeline(cmds)
	if err != nil {
		fmt.Printf("%s\n", err)
	}

	if len(stdout) > 0 {
		fmt.Printf("%s", stdout)
	}

	if len(stderr) > 0 {
		fmt.Printf("%s", stderr)
	}
}

func pipeline(cmds []*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error) {
	// Collect the output from the command(s)
	var output bytes.Buffer
	var stderr bytes.Buffer

	last := len(cmds) - 1
	for i, cmd := range cmds[:last] {
		var err error
		// Connect each command's stdin to the previous command's stdout
		if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
			return nil, nil, err
		}
		// Connect each command's stderr to a buffer
		cmd.Stderr = &stderr
	}

	// Connect the output and error for the last command
	cmds[last].Stdout, cmds[last].Stderr = &output, &stderr

	// Start each command
	for _, cmd := range cmds {
		if err := cmd.Start(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Wait for each command to complete
	for _, cmd := range cmds {
		if err := cmd.Wait(); err != nil {
			return output.Bytes(), stderr.Bytes(), err
		}
	}

	// Return the pipeline output and the collected standard error
	return output.Bytes(), stderr.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	fmt.Println("hello!")
}
<commit_msg>Converted to a hello http server<commit_after>package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", hello)
	log.Fatalln(http.ListenAndServe(":8080", nil))
}

func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello!"))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	_ "net/http/pprof"
	"os"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/image-server/image-server/core"
	fetcher "github.com/image-server/image-server/fetcher/http"
	"github.com/image-server/image-server/logger/logfile"
	"github.com/image-server/image-server/logger/statsd"
	"github.com/image-server/image-server/paths"
	"github.com/image-server/image-server/uploader"
)

// configT collects all the global state of the logging setup.
type configT struct {
	port          string
	extensions    string
	localBasePath string

	remoteBaseURL  string
	remoteBasePath string

	namespace string
	outputs   string
	listen    string

	uploaderType string
	maxFileAge   int

	awsAccessKeyID string
	awsSecretKey   string
	awsBucket      string
	awsRegion      string

	mantaURL    string
	mantaUser   string
	mantaKeyID  string
	sdcIdentity string

	maximumWidth   int
	defaultQuality int

	uploaderConcurrency  int
	processorConcurrency int
	httpTimeout          int
	gomaxprocs           int

	statsdHost   string
	statsdPort   int
	statsdPrefix string
	profile      bool

	version bool
}

var config configT

var commands = []*Command{
	cmdServer,
	cmdCli,
	cmdVersion,
}

// A Command is an implementation of a images command
// like images server or images cli.
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

func main() {
	registerFlags()
	flag.Parse()
	args := flag.Args()

	defer glog.Flush()

	if config.version {
		cmdVersion.Run(cmdVersion, args)
		exit()
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}
			cmd.Run(cmd, args)
			exit()
			return
		}
	}
}

func exit() {
	os.Exit(0)
}

// globalFlags returns flags. If the flags are not present, it will try
// extracting values from the environment, otherwise it will use default values
func registerFlags() {

	// HTTP Server settings
	flag.StringVar(&config.port, "port", "7000", "Specifies the server port.")
	flag.StringVar(&config.extensions, "extensions", "jpg,gif,webp", "Whitelisted extensions (separated by commas)")
	flag.StringVar(&config.localBasePath, "local_base_path", "public", "Directory where the images will be saved")

	// Uploader paths
	flag.StringVar(&config.remoteBaseURL, "remote_base_url", "", "Source domain for images")
	flag.StringVar(&config.remoteBasePath, "remote_base_path", "", "base path for cloud storage")

	// For CLI
	flag.StringVar(&config.namespace, "namespace", "", "Namespace")
	flag.StringVar(&config.outputs, "outputs", "", "Output files with dimension and compression: 'x300.jpg,x300.webp'")
	flag.StringVar(&config.listen, "listen", "127.0.0.1", "IP address the server listens to")

	// Uploader
	flag.StringVar(&config.uploaderType, "uploader", "", "Uploader ['s3', 'manta']")
	flag.IntVar(&config.maxFileAge, "max_file_age", 30, "Max file age in minutes")

	// S3 uploader
	flag.StringVar(&config.awsAccessKeyID, "aws_access_key_id", "", "S3 Access Key")
	flag.StringVar(&config.awsSecretKey, "aws_secret_key", "", "S3 Secret")
	flag.StringVar(&config.awsBucket, "aws_bucket", "", "S3 Bucket")
	flag.StringVar(&config.awsRegion, "aws_region", "", "S3 Region")

	// Manta uploader
	flag.StringVar(&config.mantaURL, "manta_url", "", "URL of Manta endpoint. https://us-east.manta.joyent.com")
	flag.StringVar(&config.mantaUser, "manta_user", "", "The account name")
	flag.StringVar(&config.mantaKeyID, "manta_key_id", "", "The fingerprint of the account or user SSH public key. Example: $(ssh-keygen -l -f $HOME/.ssh/id_rsa.pub | awk '{print $2}')")
	flag.StringVar(&config.sdcIdentity, "sdc_identity", "", "Example: $HOME/.ssh/id_rsa")

	// Default image settings
	flag.IntVar(&config.maximumWidth, "maximum_width", 1000, "Maximum image width")
	flag.IntVar(&config.defaultQuality, "default_quality", 75, "Default image compression quality")

	// Settings
	flag.IntVar(&config.uploaderConcurrency, "uploader_concurrency", 10, "Uploader concurrency")
	flag.IntVar(&config.processorConcurrency, "processor_concurrency", 4, "Processor concurrency")
	flag.IntVar(&config.httpTimeout, "http_timeout", 5, "HTTP request timeout in seconds")
	flag.IntVar(&config.gomaxprocs, "gomaxprocs", 0, "It will use the default when set to 0")

	// Monitoring and Profiling
	flag.StringVar(&config.statsdHost, "statsd_host", "127.0.0.1", "Statsd host")
	flag.IntVar(&config.statsdPort, "statsd_port", 8125, "Statsd port")
	flag.StringVar(&config.statsdPrefix, "statsd_prefix", "image_server.", "Statsd prefix")
	flag.BoolVar(&config.profile, "profile", false, "Enable pprof")

	// About & Help
	flag.BoolVar(&config.version, "version", false, "Version of images")
}

// initializeUploader creates base path on destination server
func initializeUploader(sc *core.ServerConfiguration) {
	err := uploader.Initialize(sc)
	if err != nil {
		log.Println("EXITING: Unable to initialize uploader: ", err)
		os.Exit(2)
	}
}

func serverConfiguration() (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromConfig()
	statsd.Enable(config.statsdHost, config.statsdPort, config.statsdPrefix)
	logfile.Enable()

	adapters := &core.Adapters{
		Fetcher: &fetcher.Fetcher{},
		Paths:   &paths.Paths{LocalBasePath: sc.LocalBasePath, RemoteBasePath: sc.RemoteBasePath, RemoteBaseURL: sc.RemoteBaseURL},
	}
	sc.Adapters = adapters
	sc.CleanUpTicker = time.NewTicker(5 * time.Second)

	return sc, nil
}

// serverConfigurationFromContext returns a core.ServerConfiguration initialized
// from command line flags or defaults.
// Command line flags preceding the Command (server, process, etc) are registered
// as globals. Flags succeeding the Command are not globals.
func serverConfigurationFromConfig() *core.ServerConfiguration {
	httpTimeout := time.Duration(config.httpTimeout) * time.Second
	var maxFileAge time.Duration
	if config.maxFileAge > 0 {
		maxFileAge = time.Duration(config.maxFileAge) * time.Minute
	} else {
		maxFileAge = time.Minute
	}

	var uploader string
	if config.uploaderType != "" {
		uploader = config.uploaderType
	} else {
		if config.awsAccessKeyID != "" {
			uploader = "s3"
		} else if config.mantaKeyID != "" {
			uploader = "manta"
		} else {
			uploader = "noop"
		}
	}

	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(config.extensions, ","),
		LocalBasePath:         config.localBasePath,

		MaximumWidth:   config.maximumWidth,
		RemoteBasePath: config.remoteBasePath,
		RemoteBaseURL:  config.remoteBaseURL,

		UploaderType: uploader,
		MaxFileAge:   maxFileAge,

		// AWS specific
		AWSAccessKeyID: config.awsAccessKeyID,
		AWSSecretKey:   config.awsSecretKey,
		AWSBucket:      config.awsBucket,
		AWSRegion:      config.awsRegion,

		// Manta specific
		MantaURL:    config.mantaURL,
		MantaUser:   config.mantaUser,
		MantaKeyID:  config.mantaKeyID,
		SDCIdentity: config.sdcIdentity,

		Outputs:             config.outputs,
		DefaultQuality:      uint(config.defaultQuality),
		UploaderConcurrency: uint(config.uploaderConcurrency),
		HTTPTimeout:         httpTimeout,
	}
}
<commit_msg>decrease frequency of garbage collector<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	_ "net/http/pprof"
	"os"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/image-server/image-server/core"
	fetcher "github.com/image-server/image-server/fetcher/http"
	"github.com/image-server/image-server/logger/logfile"
	"github.com/image-server/image-server/logger/statsd"
	"github.com/image-server/image-server/paths"
	"github.com/image-server/image-server/uploader"
)

// configT collects all the global state of the logging setup.
type configT struct {
	port          string
	extensions    string
	localBasePath string

	remoteBaseURL  string
	remoteBasePath string

	namespace string
	outputs   string
	listen    string

	uploaderType string
	maxFileAge   int

	awsAccessKeyID string
	awsSecretKey   string
	awsBucket      string
	awsRegion      string

	mantaURL    string
	mantaUser   string
	mantaKeyID  string
	sdcIdentity string

	maximumWidth   int
	defaultQuality int

	uploaderConcurrency  int
	processorConcurrency int
	httpTimeout          int
	gomaxprocs           int

	statsdHost   string
	statsdPort   int
	statsdPrefix string
	profile      bool

	version bool
}

var config configT

var commands = []*Command{
	cmdServer,
	cmdCli,
	cmdVersion,
}

// A Command is an implementation of a images command
// like images server or images cli.
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

func main() {
	registerFlags()
	flag.Parse()
	args := flag.Args()

	defer glog.Flush()

	if config.version {
		cmdVersion.Run(cmdVersion, args)
		exit()
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			cmd.Flag.Parse(args[1:])
			args = cmd.Flag.Args()
			cmd.Run(cmd, args)
			exit()
			return
		}
	}
}

func exit() {
	os.Exit(0)
}

// globalFlags returns flags. If the flags are not present, it will try
// extracting values from the environment, otherwise it will use default values
func registerFlags() {

	// HTTP Server settings
	flag.StringVar(&config.port, "port", "7000", "Specifies the server port.")
	flag.StringVar(&config.extensions, "extensions", "jpg,gif,webp", "Whitelisted extensions (separated by commas)")
	flag.StringVar(&config.localBasePath, "local_base_path", "public", "Directory where the images will be saved")

	// Uploader paths
	flag.StringVar(&config.remoteBaseURL, "remote_base_url", "", "Source domain for images")
	flag.StringVar(&config.remoteBasePath, "remote_base_path", "", "base path for cloud storage")

	// For CLI
	flag.StringVar(&config.namespace, "namespace", "", "Namespace")
	flag.StringVar(&config.outputs, "outputs", "", "Output files with dimension and compression: 'x300.jpg,x300.webp'")
	flag.StringVar(&config.listen, "listen", "127.0.0.1", "IP address the server listens to")

	// Uploader
	flag.StringVar(&config.uploaderType, "uploader", "", "Uploader ['s3', 'manta']")
	flag.IntVar(&config.maxFileAge, "max_file_age", 30, "Max file age in minutes")

	// S3 uploader
	flag.StringVar(&config.awsAccessKeyID, "aws_access_key_id", "", "S3 Access Key")
	flag.StringVar(&config.awsSecretKey, "aws_secret_key", "", "S3 Secret")
	flag.StringVar(&config.awsBucket, "aws_bucket", "", "S3 Bucket")
	flag.StringVar(&config.awsRegion, "aws_region", "", "S3 Region")

	// Manta uploader
	flag.StringVar(&config.mantaURL, "manta_url", "", "URL of Manta endpoint. https://us-east.manta.joyent.com")
	flag.StringVar(&config.mantaUser, "manta_user", "", "The account name")
	flag.StringVar(&config.mantaKeyID, "manta_key_id", "", "The fingerprint of the account or user SSH public key. Example: $(ssh-keygen -l -f $HOME/.ssh/id_rsa.pub | awk '{print $2}')")
	flag.StringVar(&config.sdcIdentity, "sdc_identity", "", "Example: $HOME/.ssh/id_rsa")

	// Default image settings
	flag.IntVar(&config.maximumWidth, "maximum_width", 1000, "Maximum image width")
	flag.IntVar(&config.defaultQuality, "default_quality", 75, "Default image compression quality")

	// Settings
	flag.IntVar(&config.uploaderConcurrency, "uploader_concurrency", 10, "Uploader concurrency")
	flag.IntVar(&config.processorConcurrency, "processor_concurrency", 4, "Processor concurrency")
	flag.IntVar(&config.httpTimeout, "http_timeout", 5, "HTTP request timeout in seconds")
	flag.IntVar(&config.gomaxprocs, "gomaxprocs", 0, "It will use the default when set to 0")

	// Monitoring and Profiling
	flag.StringVar(&config.statsdHost, "statsd_host", "127.0.0.1", "Statsd host")
	flag.IntVar(&config.statsdPort, "statsd_port", 8125, "Statsd port")
	flag.StringVar(&config.statsdPrefix, "statsd_prefix", "image_server.", "Statsd prefix")
	flag.BoolVar(&config.profile, "profile", false, "Enable pprof")

	// About & Help
	flag.BoolVar(&config.version, "version", false, "Version of images")
}

// initializeUploader creates base path on destination server
func initializeUploader(sc *core.ServerConfiguration) {
	err := uploader.Initialize(sc)
	if err != nil {
		log.Println("EXITING: Unable to initialize uploader: ", err)
		os.Exit(2)
	}
}

func serverConfiguration() (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromConfig()
	statsd.Enable(config.statsdHost, config.statsdPort, config.statsdPrefix)
	logfile.Enable()

	adapters := &core.Adapters{
		Fetcher: &fetcher.Fetcher{},
		Paths:   &paths.Paths{LocalBasePath: sc.LocalBasePath, RemoteBasePath: sc.RemoteBasePath, RemoteBaseURL: sc.RemoteBaseURL},
	}
	sc.Adapters = adapters
	sc.CleanUpTicker = time.NewTicker(2 * time.Minute)

	return sc, nil
}

// serverConfigurationFromContext returns a core.ServerConfiguration initialized
// from command line flags or defaults.
// Command line flags preceding the Command (server, process, etc) are registered
// as globals. Flags succeeding the Command are not globals.
func serverConfigurationFromConfig() *core.ServerConfiguration {
	httpTimeout := time.Duration(config.httpTimeout) * time.Second
	var maxFileAge time.Duration
	if config.maxFileAge > 0 {
		maxFileAge = time.Duration(config.maxFileAge) * time.Minute
	} else {
		maxFileAge = time.Minute
	}

	var uploader string
	if config.uploaderType != "" {
		uploader = config.uploaderType
	} else {
		if config.awsAccessKeyID != "" {
			uploader = "s3"
		} else if config.mantaKeyID != "" {
			uploader = "manta"
		} else {
			uploader = "noop"
		}
	}

	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(config.extensions, ","),
		LocalBasePath:         config.localBasePath,

		MaximumWidth:   config.maximumWidth,
		RemoteBasePath: config.remoteBasePath,
		RemoteBaseURL:  config.remoteBaseURL,

		UploaderType: uploader,
		MaxFileAge:   maxFileAge,

		// AWS specific
		AWSAccessKeyID: config.awsAccessKeyID,
		AWSSecretKey:   config.awsSecretKey,
		AWSBucket:      config.awsBucket,
		AWSRegion:      config.awsRegion,

		// Manta specific
		MantaURL:    config.mantaURL,
		MantaUser:   config.mantaUser,
		MantaKeyID:  config.mantaKeyID,
		SDCIdentity: config.sdcIdentity,

		Outputs:             config.outputs,
		DefaultQuality:      uint(config.defaultQuality),
		UploaderConcurrency: uint(config.uploaderConcurrency),
		HTTPTimeout:         httpTimeout,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
)

var wd, _ = os.Getwd()

func main() {
	tmpdir, err := ioutil.TempDir("", "bif")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(tmpdir)
	gopath := tmpdir
	if s := os.Getenv("GOPATH"); s != "" {
		gopath += string(os.PathListSeparator) + s
	}

	p, err := build.ImportDir(wd, 0)
	if err != nil {
		log.Fatalln(err)
	}

	rel, _ := filepath.Rel(p.Root, p.Dir)
	pdir := filepath.Join(tmpdir, rel)
	os.MkdirAll(pdir, 0777)
	for _, name := range p.GoFiles {
		err = copyfile(name, filepath.Join(pdir, name))
		if err != nil {
			log.Fatalln(err)
		}
	}
	err = gen(filepath.Join(pdir, "bif.go"), p)
	if err != nil {
		log.Fatalln(err)
	}
	bifmain := filepath.Join(tmpdir, "bifmain.go")
	err = genbifmain(bifmain, p)
	if err != nil {
		log.Fatalln(err)
	}
	//arg := append([]string{"run", "bif.go"}, p.GoFiles...)
	//cmd := exec.Command("go", arg...)
	cmd := exec.Command("go", "run", bifmain)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = append(envNoGopath(), "GOPATH="+gopath)
	err = cmd.Run()
	if err != nil {
		log.Fatalln(err)
	}
}

func envNoGopath() (a []string) {
	for _, s := range os.Environ() {
		if !strings.HasPrefix(s, "GOPATH=") {
			a = append(a, s)
		}
	}
	return a
}

func copyfile(src, dst string) error {
	r, err := os.Open(src)
	if err != nil {
		return err
	}
	defer r.Close()
	w, err := os.Create(dst)
	if err != nil {
		return err
	}
	_, err = io.Copy(w, r)
	if err != nil {
		w.Close()
		return err
	}
	return w.Close()
}

var (
	pmainTmpl = template.Must(template.New("main").Parse(`
package main

import (
	"os"
	"reflect"

	"github.com/kr/bif/interp"
)

func BifMain() {
	var env *interp.Env
{{range .Globals}}
	env = env.With({{.Name|printf "%q"}}, reflect.ValueOf({{.Name}}))
{{end}}

	// TODO(kr): packages
	interp.Run(env, nil)
	os.Exit(0)
}
`))
	bifmainTmpl = template.Must(template.New("main").Parse(`
package main

import p {{.ImportPath|printf "%q"}}

func main() {
	p.BifMain()
}
`))
)

func gen(name string, p *build.Package) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	tab, _, err := syms(p, true)
	if err != nil {
		return err
	}

	var x = struct{ Globals []sym }{tab}

	if err := pmainTmpl.Execute(f, x); err != nil {
		return err
	}
	return nil
}

func genbifmain(name string, p *build.Package) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()
	var x = struct{ ImportPath string }{p.ImportPath}
	if err := bifmainTmpl.Execute(f, x); err != nil {
		return err
	}
	return nil
}

func syms(p *build.Package, includePrivate bool) ([]sym, map[string][]string, error) {
	fset := token.NewFileSet() // positions are relative to fset

	pkgs, err := parser.ParseDir(fset, ".", func(fi os.FileInfo) bool {
		for _, s := range p.GoFiles {
			if s == fi.Name() {
				return true
			}
		}
		return false
	}, 0)
	if err != nil {
		return nil, nil, err
	}

	pkg, ok := pkgs[p.Name]
	if !ok {
		return nil, nil, fmt.Errorf("no package %s here", p.Name)
	}

	if !includePrivate {
		ok = ast.PackageExports(pkg)
		if !ok {
			return nil, nil, fmt.Errorf("no exported symbols in %s", p.Name)
		}
	}

	vis := &visitor{}
	ast.Walk(vis, pkg)

	return vis.tab, nil, nil
}

type sym struct {
	Name    string
	CanAddr bool
}

type visitor struct {
	tab []sym
}

func (v *visitor) Visit(x ast.Node) (w ast.Visitor) {
	switch x := x.(type) {
	case *ast.FuncDecl:
		if x.Recv == nil && x.Name.Name != "init" {
			v.tab = append(v.tab, sym{x.Name.Name, false})
		}
		return nil
	case *ast.ImportSpec:
		return nil
	case *ast.ValueSpec:
		// TODO(kr): keep track of writable symbols (vars)
		// and make their reflect.Value values settable
		// in pmainTmpl above.
		for _, id := range x.Names {
			v.tab = append(v.tab, sym{id.Name, false})
		}
		return nil
	case *ast.TypeSpec:
		return nil
	}
	return v
}
<commit_msg>modify the user's package less<commit_after>package main

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
)

var wd, _ = os.Getwd()

func main() {
	tmpdir, err := ioutil.TempDir("", "bif")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(tmpdir)
	gopath := tmpdir
	if s := os.Getenv("GOPATH"); s != "" {
		gopath += string(os.PathListSeparator) + s
	}

	p, err := build.ImportDir(wd, 0)
	if err != nil {
		log.Fatalln(err)
	}

	rel, _ := filepath.Rel(p.Root, p.Dir)
	pdir := filepath.Join(tmpdir, rel)
	os.MkdirAll(pdir, 0777)
	for _, name := range p.GoFiles {
		err = copyfile(name, filepath.Join(pdir, name))
		if err != nil {
			log.Fatalln(err)
		}
	}
	err = gen(filepath.Join(pdir, "bif.go"), p)
	if err != nil {
		log.Fatalln(err)
	}
	bifmain := filepath.Join(tmpdir, "bifmain.go")
	err = genbifmain(bifmain, p)
	if err != nil {
		log.Fatalln(err)
	}
	//arg := append([]string{"run", "bif.go"}, p.GoFiles...)
	//cmd := exec.Command("go", arg...)
	cmd := exec.Command("go", "run", bifmain)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = append(envNoGopath(), "GOPATH="+gopath)
	err = cmd.Run()
	if err != nil {
		log.Fatalln(err)
	}
}

func envNoGopath() (a []string) {
	for _, s := range os.Environ() {
		if !strings.HasPrefix(s, "GOPATH=") {
			a = append(a, s)
		}
	}
	return a
}

func copyfile(src, dst string) error {
	r, err := os.Open(src)
	if err != nil {
		return err
	}
	defer r.Close()
	w, err := os.Create(dst)
	if err != nil {
		return err
	}
	_, err = io.Copy(w, r)
	if err != nil {
		w.Close()
		return err
	}
	return w.Close()
}

var (
	pmainTmpl = template.Must(template.New("main").Parse(`
package main

import (
	"reflect"

	"github.com/kr/bif/interp"
)

func BifEnv() *interp.Env {
	var env *interp.Env
{{range .Globals}}
	env = env.With({{.Name|printf "%q"}}, reflect.ValueOf({{.Name}}))
{{end}}
	return env
}
`))
	bifmainTmpl = template.Must(template.New("main").Parse(`
package main

import (
	p {{.ImportPath|printf "%q"}}
	"github.com/kr/bif/interp"
)

func main() {
	// TODO(kr): packages
	env := p.BifEnv()
	interp.Run(env, nil)
}
`))
)

func gen(name string, p *build.Package) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	tab, _, err := syms(p, true)
	if err != nil {
		return err
	}

	var x = struct{ Globals []sym }{tab}

	if err := pmainTmpl.Execute(f, x); err != nil {
		return err
	}
	return nil
}

func genbifmain(name string, p *build.Package) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()
	var x = struct{ ImportPath string }{p.ImportPath}
	if err := bifmainTmpl.Execute(f, x); err != nil {
		return err
	}
	return nil
}

func syms(p *build.Package, includePrivate bool) ([]sym, map[string][]string, error) {
	fset := token.NewFileSet() // positions are relative to fset

	pkgs, err := parser.ParseDir(fset, ".", func(fi os.FileInfo) bool {
		for _, s := range p.GoFiles {
			if s == fi.Name() {
				return true
			}
		}
		return false
	}, 0)
	if err != nil {
		return nil, nil, err
	}

	pkg, ok := pkgs[p.Name]
	if !ok {
		return nil, nil, fmt.Errorf("no package %s here", p.Name)
	}

	if !includePrivate {
		ok = ast.PackageExports(pkg)
		if !ok {
			return nil, nil, fmt.Errorf("no exported symbols in %s", p.Name)
		}
	}

	vis := &visitor{}
	ast.Walk(vis, pkg)

	return vis.tab, nil, nil
}

type sym struct {
	Name    string
	CanAddr bool
}

type visitor struct {
	tab []sym
}

func (v *visitor) Visit(x ast.Node) (w ast.Visitor) {
	switch x := x.(type) {
	case *ast.FuncDecl:
		if x.Recv == nil && x.Name.Name != "init" {
			v.tab = append(v.tab, sym{x.Name.Name, false})
		}
		return nil
	case *ast.ImportSpec:
		return nil
	case *ast.ValueSpec:
		// TODO(kr): keep track of writable symbols (vars)
		// and make their reflect.Value values settable
		// in pmainTmpl above.
		for _, id := range x.Names {
			v.tab = append(v.tab, sym{id.Name, false})
		}
		return nil
	case *ast.TypeSpec:
		return nil
	}
	return v
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"

	"github.com/paultag/go-dictd/database"
	"github.com/paultag/go-dictd/dictd"
)

func main() {
	server := dictd.NewServer("pault.ag")
	levelDB, err := database.NewLevelDBDatabase("/home/tag/jargon.ldb", "jargon file")
	if err != nil {
		log.Fatal(err)
	}

	urbanDB := database.UrbanDictionaryDatabase{}

	server.RegisterDatabase(levelDB, "jargon")
	server.RegisterDatabase(&urbanDB, "urban")

	link, err := net.Listen("tcp", ":2628")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := link.Accept()
		if err != nil {
			log.Printf("Error: %s", err)
		}
		go dictd.Handle(&server, conn)
	}
}
<commit_msg>add in congress :)<commit_after>package main

import (
	"log"
	"net"

	"github.com/paultag/go-dictd/database"
	"github.com/paultag/go-dictd/dictd"
)

func main() {
	server := dictd.NewServer("pault.ag")
	jargon, err := database.NewLevelDBDatabase(
		"/home/tag/jargon.ldb",
		"jargon file",
	)
	congress, err := database.NewLevelDBDatabase(
		"/home/tag/congress.ldb",
		"congress words",
	)
	if err != nil {
		log.Fatal(err)
	}

	urbanDB := database.UrbanDictionaryDatabase{}

	server.RegisterDatabase(jargon, "jargon")
	server.RegisterDatabase(congress, "congress")
	server.RegisterDatabase(&urbanDB, "urban")

	link, err := net.Listen("tcp", ":2628")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := link.Accept()
		if err != nil {
			log.Printf("Error: %s", err)
		}
		go dictd.Handle(&server, conn)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/oschwald/geoip2-golang"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// The GeoIP database containing data on what IP match to what city/country blah
// blah.
var db *geoip2.Reader

func main() {
	// Initialize the database.
	var err error
	db, err = geoip2.Open("GeoLite2-City.mmdb")
	if err != nil {
		log.Fatal(err)
	}

	// Get the HTTP server rollin'
	http.HandleFunc("/", HTTPRequestHandler)
	log.Println("Server listening!")
	http.ListenAndServe(":61430", nil)
}

// Standard request handler if there's no static file to be served.
func HTTPRequestHandler(w http.ResponseWriter, r *http.Request) {
	// Get the current time, so that we can then calculate the execution time.
	start := time.Now()

	var requestIP string
	// The request is most likely being done through a reverse proxy.
	if realIP, ok := r.Header["X-Real-IP"]; ok && len(r.Header["X-Real-Ip"]) > 0 {
		requestIP = realIP[0]
	} else {
		// Get the real actual request IP without the trolls
		requestIP = UnfuckRequestIP(r.RemoteAddr)
	}

	// Log how much time it took to respond to the request, when we're done.
	defer log.Printf(
		"[rq] %s %s %s %dns",
		requestIP,
		r.Method,
		r.URL.Path,
		time.Since(start).Nanoseconds())

	// Index, redirect to github.com page.
	if r.URL.Path == "/" {
		http.Redirect(w, r, "https://github.com/TheHowl/ip.zxq.co/blob/master/README.md", 301)
		return
	}

	// Separate two strings when there is a / in the URL requested.
	requestedThings := strings.Split(r.URL.Path, "/")

	var IPAddress string
	var Which string
	// How in the world the user would manage to even send a request to
	// something without even having Path = "/"?
	// I... have no idea. But I'm paranoid. So let's just do it anyway.
	if len(requestedThings) < 2 {
		IPAddress = ""
	} else {
		IPAddress = requestedThings[1]
	}
	// In case the user didn't write a specific index, let's specify it for
	// them.
	if len(requestedThings) < 3 {
		Which = ""
	} else {
		Which = requestedThings[2]
	}

	// Query parameters array making
	queryParamsRaw, _ := url.ParseQuery(r.URL.RawQuery)
	queryParams := SimplifyQueryMap(queryParamsRaw)
	queryParams = AppendDefaultIfNotSet(queryParams, "callback", "#none#")
	queryParams = AppendDefaultIfNotSet(queryParams, "pretty", "0")

	// Get the geodata of the requested IP.
	o, contentType := IPToResponse(IPAddress, Which, queryParams)

	// Set the content type as the one given by IPToResponse.
	w.Header().Set("Content-Type", contentType+"; charset=utf-8")
	// Write the data out to the response.
	fmt.Fprint(w, o)
}

// Appends a default value to a map only if the key, defined as k, doesn't
// already exist in the array.
func AppendDefaultIfNotSet(sl map[string]string, k string, dv string) map[string]string {
	if _, ok := sl[k]; !ok {
		sl[k] = dv
	}
	return sl
}

// url.ParseQuery returns a map containing as a value a slice with often just
// one value. We're fixing that.
func SimplifyQueryMap(sl url.Values) map[string]string {
	var ret map[string]string = map[string]string{}
	for k, v := range sl {
		// We're getting only the last element, because we take as granted that
		// what the use actually means is the last element, if he has provided
		// multiple values for the same key.
		if len(v) > 0 {
			ret[k] = v[len(v)-1]
		}
	}
	return ret
}

// Remove from the IP eventual [ or ], and remove the port part of the IP.
func UnfuckRequestIP(ip string) string {
	ip = strings.Replace(ip, "[", "", 1)
	ip = strings.Replace(ip, "]", "", 1)
	ss := strings.Split(ip, ":")
	ip = strings.Join(ss[:len(ss)-1], ":")
	return ip
}

// Turn the IP into a JSON string containing geodata.
//
// * i: the raw IP string.
// * specific: the specific value to get from the geodata array. Default is ""
// * params: Set callback in the map to a non-"#none#" value to use it as a
//   JSONP callback. Set "pretty" to 1 if you want a 2-space indented JSON
//   output.
func IPToResponse(i string, specific string, params map[string]string) (string, string) {
	ip := net.ParseIP(i)
	if ip == nil {
		return "Please provide a valid IP address", "text/html"
	}

	// Query the maxmind database for that IP address.
	record, err := db.City(ip)
	if err != nil {
		log.Fatal(err)
	}

	// String containing the region/subdivision of the IP. (E.g.: Scotland, or
	// California).
	var sd string
	// If there are subdivisions for this IP, set sd as the first element in the
	// array's name.
	if record.Subdivisions != nil {
		sd = record.Subdivisions[0].Names["en"]
	}

	// Create a new instance of all the data to be returned to the user.
	data := map[string]string{}
	// Fill up the data array with the geoip data.
	data["ip"] = ip.String()
	data["country"] = record.Country.IsoCode
	data["country_full"] = record.Country.Names["en"]
	data["city"] = record.City.Names["en"]
	data["region"] = sd
	data["continent"] = record.Continent.Code
	data["continent_full"] = record.Continent.Names["en"]
	data["postal"] = record.Postal.Code
	// precision of latitude/longitude is up to 4 decimal places (even on
	// ipinfo.io).
	data["loc"] = fmt.Sprintf("%.4f,%.4f", record.Location.Latitude, record.Location.Longitude)

	// Since we don't have HTML output, nor other data from geo data,
	// everything is the same if you do /8.8.8.8, /8.8.8.8/json or /8.8.8.8/geo.
	if specific == "" || specific == "json" || specific == "geo" {
		var bytes_output []byte
		if params["pretty"] == "1" {
			bytes_output, _ = json.MarshalIndent(data, "", "  ")
		} else {
			bytes_output, _ = json.Marshal(data)
		}
		return JSONPify(params["callback"], string(bytes_output[:])),
			"application/json"
	} else if val, ok := data[specific]; ok {
		// If we got a specific value for what the user requested, return only
		// that specific value.
		return val, "text/html"
	} else {
		// We got nothing to show to the user.
		return "undefined", "text/html"
	}
}

// Wraps wrapData into a JSONP callback, if the callback name is valid.
func JSONPify(callback string, wrapData string) string {
	// If you have a callback name longer than 2000 characters, I gotta say, you
	// really should learn to minify your javascript code!
	if callback != "#none#" && callback != "" && len(callback) < 2000 {
		// In case you're wondering, yes, there is a reason for the empty
		// comment! http://stackoverflow.com/a/16048976/5328069
		wrapData = fmt.Sprintf("/**/ typeof %s === 'function' "+
			"&& %s(%s);", callback, callback, wrapData)
	}
	return wrapData
}
<commit_msg>top meme<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/oschwald/geoip2-golang"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// The GeoIP database containing data on what IP match to what city/country blah
// blah.
var db *geoip2.Reader

func main() {
	// Initialize the database.
	var err error
	db, err = geoip2.Open("GeoLite2-City.mmdb")
	if err != nil {
		log.Fatal(err)
	}

	// Get the HTTP server rollin'
	http.HandleFunc("/", HTTPRequestHandler)
	log.Println("Server listening!")
	http.ListenAndServe(":61430", nil)
}

// Standard request handler if there's no static file to be served.
func HTTPRequestHandler(w http.ResponseWriter, r *http.Request) {
	// Get the current time, so that we can then calculate the execution time.
	start := time.Now()

	var requestIP string
	// The request is most likely being done through a reverse proxy.
	if realIP, ok := r.Header["X-Real-Ip"]; ok && len(r.Header["X-Real-Ip"]) > 0 {
		requestIP = realIP[0]
	} else {
		// Get the real actual request IP without the trolls
		requestIP = UnfuckRequestIP(r.RemoteAddr)
	}

	// Log how much time it took to respond to the request, when we're done.
	defer log.Printf(
		"[rq] %s %s %s %dns",
		requestIP,
		r.Method,
		r.URL.Path,
		time.Since(start).Nanoseconds())

	// Index, redirect to github.com page.
	if r.URL.Path == "/" {
		http.Redirect(w, r, "https://github.com/TheHowl/ip.zxq.co/blob/master/README.md", 301)
		return
	}

	// Separate two strings when there is a / in the URL requested.
	requestedThings := strings.Split(r.URL.Path, "/")

	var IPAddress string
	var Which string
	// How in the world the user would manage to even send a request to
	// something without even having Path = "/"?
	// I... have no idea. But I'm paranoid. So let's just do it anyway.
	if len(requestedThings) < 2 {
		IPAddress = ""
	} else {
		IPAddress = requestedThings[1]
	}
	// In case the user didn't write a specific index, let's specify it for
	// them.
	if len(requestedThings) < 3 {
		Which = ""
	} else {
		Which = requestedThings[2]
	}

	// Query parameters array making
	queryParamsRaw, _ := url.ParseQuery(r.URL.RawQuery)
	queryParams := SimplifyQueryMap(queryParamsRaw)
	queryParams = AppendDefaultIfNotSet(queryParams, "callback", "#none#")
	queryParams = AppendDefaultIfNotSet(queryParams, "pretty", "0")

	// Get the geodata of the requested IP.
	o, contentType := IPToResponse(IPAddress, Which, queryParams)

	// Set the content type as the one given by IPToResponse.
	w.Header().Set("Content-Type", contentType+"; charset=utf-8")
	// Write the data out to the response.
	fmt.Fprint(w, o)
}

// Appends a default value to a map only if the key, defined as k, doesn't
// already exist in the array.
func AppendDefaultIfNotSet(sl map[string]string, k string, dv string) map[string]string {
	if _, ok := sl[k]; !ok {
		sl[k] = dv
	}
	return sl
}

// url.ParseQuery returns a map containing as a value a slice with often just
// one value. We're fixing that.
func SimplifyQueryMap(sl url.Values) map[string]string {
	var ret map[string]string = map[string]string{}
	for k, v := range sl {
		// We're getting only the last element, because we take as granted that
		// what the use actually means is the last element, if he has provided
		// multiple values for the same key.
		if len(v) > 0 {
			ret[k] = v[len(v)-1]
		}
	}
	return ret
}

// Remove from the IP eventual [ or ], and remove the port part of the IP.
func UnfuckRequestIP(ip string) string {
	ip = strings.Replace(ip, "[", "", 1)
	ip = strings.Replace(ip, "]", "", 1)
	ss := strings.Split(ip, ":")
	ip = strings.Join(ss[:len(ss)-1], ":")
	return ip
}

// Turn the IP into a JSON string containing geodata.
//
// * i: the raw IP string.
// * specific: the specific value to get from the geodata array. Default is ""
// * params: Set callback in the map to a non-"#none#" value to use it as a
//   JSONP callback. Set "pretty" to 1 if you want a 2-space indented JSON
//   output.
func IPToResponse(i string, specific string, params map[string]string) (string, string) {
	ip := net.ParseIP(i)
	if ip == nil {
		return "Please provide a valid IP address", "text/html"
	}

	// Query the maxmind database for that IP address.
	record, err := db.City(ip)
	if err != nil {
		log.Fatal(err)
	}

	// String containing the region/subdivision of the IP. (E.g.: Scotland, or
	// California).
	var sd string
	// If there are subdivisions for this IP, set sd as the first element in the
	// array's name.
	if record.Subdivisions != nil {
		sd = record.Subdivisions[0].Names["en"]
	}

	// Create a new instance of all the data to be returned to the user.
	data := map[string]string{}
	// Fill up the data array with the geoip data.
	data["ip"] = ip.String()
	data["country"] = record.Country.IsoCode
	data["country_full"] = record.Country.Names["en"]
	data["city"] = record.City.Names["en"]
	data["region"] = sd
	data["continent"] = record.Continent.Code
	data["continent_full"] = record.Continent.Names["en"]
	data["postal"] = record.Postal.Code
	// precision of latitude/longitude is up to 4 decimal places (even on
	// ipinfo.io).
	data["loc"] = fmt.Sprintf("%.4f,%.4f", record.Location.Latitude, record.Location.Longitude)

	// Since we don't have HTML output, nor other data from geo data,
	// everything is the same if you do /8.8.8.8, /8.8.8.8/json or /8.8.8.8/geo.
	if specific == "" || specific == "json" || specific == "geo" {
		var bytes_output []byte
		if params["pretty"] == "1" {
			bytes_output, _ = json.MarshalIndent(data, "", "  ")
		} else {
			bytes_output, _ = json.Marshal(data)
		}
		return JSONPify(params["callback"], string(bytes_output[:])),
			"application/json"
	} else if val, ok := data[specific]; ok {
		// If we got a specific value for what the user requested, return only
		// that specific value.
		return val, "text/html"
	} else {
		// We got nothing to show to the user.
		return "undefined", "text/html"
	}
}

// Wraps wrapData into a JSONP callback, if the callback name is valid.
func JSONPify(callback string, wrapData string) string {
	// If you have a callback name longer than 2000 characters, I gotta say, you
	// really should learn to minify your javascript code!
	if callback != "#none#" && callback != "" && len(callback) < 2000 {
		// In case you're wondering, yes, there is a reason for the empty
		// comment! http://stackoverflow.com/a/16048976/5328069
		wrapData = fmt.Sprintf("/**/ typeof %s === 'function' "+
			"&& %s(%s);", callback, callback, wrapData)
	}
	return wrapData
}
<|endoftext|>


<commit_before>package cpu6502

import (
	"io/ioutil"
	"testing"
)

type CpuTest struct {
	Name string
	Mem  []byte
	End  Cpu
}

type Ram []byte

func (r Ram) Read(v uint16) byte     { return r[v] }
func (r Ram) Write(v uint16, b byte) { r[v] = b }

var CpuTests = []CpuTest{
	{
		Name: "load, set",
		Mem:  []byte{0xa9, 0x01, 0x8d, 0x00, 0x02, 0xa9, 0x05, 0x8d, 0x01, 0x02, 0xa9, 0x08, 0x8d, 0x02, 0x02},
		End: Cpu{
			A:  0x08,
			S:  0xff,
			PC: 0x0611,
			P:  0x30,
		},
	},
	{
		Name: "load, transfer, increment, add",
		Mem:  []byte{0xa9, 0xc0, 0xaa, 0xe8, 0x69, 0xc4, 0x00},
		End: Cpu{
			A:  0x84,
			X:  0xc1,
			S:  0xff,
			PC: 0x0608,
			P:  0xb1,
		},
	},
	{
		Name: "bne",
		Mem:  []byte{0xa2, 0x08, 0xca, 0x8e, 0x00, 0x02, 0xe0, 0x03, 0xd0, 0xf8, 0x8e, 0x01, 0x02, 0x00},
		End: Cpu{
			X:  0x03,
			S:  0xff,
			PC: 0x060f,
			P:  0x33,
		},
	},
	{
		Name: "relative",
		Mem:  []byte{0xa9, 0x01, 0xc9, 0x02, 0xd0, 0x02, 0x85, 0x22, 0x00},
		End: Cpu{
			A:  0x01,
			S:  0xff,
			PC: 0x060a,
			P:  0xb0,
		},
	},
	{
		Name: "indirect",
		Mem:  []byte{0xa9, 0x01, 0x85, 0xf0, 0xa9, 0xcc, 0x85, 0xf1, 0x6c, 0xf0, 0x00},
		End: Cpu{
			A:  0xcc,
			S:  0xff,
			PC: 0xcc03,
			P:  0xb0,
		},
	},
	{
		Name: "indexed indirect",
		Mem:  []byte{0xa2, 0x01, 0xa9, 0x05, 0x85, 0x01, 0xa9, 0x06, 0x85, 0x02, 0xa0, 0x0a, 0x8c, 0x05, 0x06, 0xa1, 0x00},
		End: Cpu{
			A:  0x0a,
			X:  0x01,
			Y:  0x0a,
			S:  0xff,
			PC: 0x0613,
			P:  0x30,
		},
	},
	{
		Name: "indirect indexed",
		Mem:  []byte{0xa0, 0x01, 0xa9, 0x03, 0x85, 0x01, 0xa9, 0x07, 0x85, 0x02, 0xa2, 0x0a, 0x8e, 0x04, 0x07, 0xb1, 0x01},
		End: Cpu{
			A:  0x0a,
			X:  0x0a,
			Y:  0x01,
			S:  0xff,
			PC: 0x0613,
			P:  0x30,
		},
	},
	{
		Name: "stack",
		Mem:  []byte{0xa2, 0x00, 0xa0, 0x00, 0x8a, 0x99, 0x00, 0x02, 0x48, 0xe8, 0xc8, 0xc0, 0x10, 0xd0, 0xf5, 0x68, 0x99, 0x00, 0x02, 0xc8, 0xc0, 0x20, 0xd0, 0xf7},
		End: Cpu{
			X:  0x10,
			Y:  0x20,
			S:  0xff,
			PC: 0x061a,
			P:  0x33,
		},
	},
	{
		Name: "jsr/rts",
		Mem:  []byte{0x20, 0x09, 0x06, 0x20, 0x0c, 0x06, 0x20, 0x12, 0x06, 0xa2, 0x00, 0x60, 0xe8, 0xe0, 0x05, 0xd0, 0xfb, 0x60, 0x00},
		End: Cpu{
			X:  0x05,
			S:  0xfd,
			PC: 0x0614,
			P:  0x33,
		},
	},
	{
		Name: "others",
		Mem:  []byte{0xa9, 0x30, 0x29, 0x9f, 0x0a, 0xa2, 0x0f, 0x86, 0x00, 0x06, 0x00, 0xa4, 0x00, 0x24, 0x00},
		End: Cpu{
			A:  0x20,
			X:  0x0f,
			Y:  0x1e,
			S:  0xff,
			PC: 0x0611,
			P:  0x32,
		},
	},
	{
		Name: "trb1",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x33, 0x14, 0x00},
		End: Cpu{
			A:  0x33,
			S:  0xff,
			PC: 0x060a,
			P:  0x30,
		},
	},
	{
		Name: "trb2",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x41, 0x14, 0x00},
		End: Cpu{
			A:  0x41,
			S:  0xff,
			PC: 0x060a,
			P:  0x32,
		},
	},
	{
		Name: "tsb1",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x33, 0x04, 0x00},
		End: Cpu{
			A:  0x33,
			S:  0xff,
			PC: 0x060a,
			P:  0x30,
		},
	},
	{
		Name: "tsb2",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x41, 0x04, 0x00},
		End: Cpu{
			A:  0x41,
			S:  0xff,
			PC: 0x060a,
			P:  0x32,
		},
	},
}

func Test6502(t *testing.T) {
	for _, test := range CpuTests {
		r := make(Ram, 0xffff+1)
		c := New(r)
		copy(r[c.PC:], test.Mem)
		c.Run()
		if c.A != test.End.A ||
			c.X != test.End.X ||
			c.Y != test.End.Y ||
			c.S != test.End.S ||
			c.PC != test.End.PC ||
			c.P != test.End.P {
			t.Fatalf("bad cpu state %s, got:\n%sexpected:\n%s", test.Name, c, &test.End)
		}
	}
}

// Download from https://github.com/Klaus2m5/6502_65C02_functional_tests/blob/master/bin_files/6502_functional_test.bin
// GPL, so not included here.
func TestFunctional(t *testing.T) {
	b, err := ioutil.ReadFile("6502_functional_test.bin")
	if err != nil {
		t.Fatal(err)
	}
	r := make(Ram, 0xffff+1)
	copy(r[:], b)
	c := New(r)
	c.PC = 0x0400
	for !c.Halt {
		pc := c.PC
		c.Step()
		if c.PC == pc {
			t.Fatal()
		}
	}
}
<commit_msg>Better error detection<commit_after>package cpu6502

import (
	"io/ioutil"
	"testing"
)

type CpuTest struct {
	Name string
	Mem  []byte
	End  Cpu
}

type Ram []byte

func (r Ram) Read(v uint16) byte     { return r[v] }
func (r Ram) Write(v uint16, b byte) { r[v] = b }

var CpuTests = []CpuTest{
	{
		Name: "load, set",
		Mem:  []byte{0xa9, 0x01, 0x8d, 0x00, 0x02, 0xa9, 0x05, 0x8d, 0x01, 0x02, 0xa9, 0x08, 0x8d, 0x02, 0x02},
		End: Cpu{
			A:  0x08,
			S:  0xff,
			PC: 0x0611,
			P:  0x30,
		},
	},
	{
		Name: "load, transfer, increment, add",
		Mem:  []byte{0xa9, 0xc0, 0xaa, 0xe8, 0x69, 0xc4, 0x00},
		End: Cpu{
			A:  0x84,
			X:  0xc1,
			S:  0xff,
			PC: 0x0608,
			P:  0xb1,
		},
	},
	{
		Name: "bne",
		Mem:  []byte{0xa2, 0x08, 0xca, 0x8e, 0x00, 0x02, 0xe0, 0x03, 0xd0, 0xf8, 0x8e, 0x01, 0x02, 0x00},
		End: Cpu{
			X:  0x03,
			S:  0xff,
			PC: 0x060f,
			P:  0x33,
		},
	},
	{
		Name: "relative",
		Mem:  []byte{0xa9, 0x01, 0xc9, 0x02, 0xd0, 0x02, 0x85, 0x22, 0x00},
		End: Cpu{
			A:  0x01,
			S:  0xff,
			PC: 0x060a,
			P:  0xb0,
		},
	},
	{
		Name: "indirect",
		Mem:  []byte{0xa9, 0x01, 0x85, 0xf0, 0xa9, 0xcc, 0x85, 0xf1, 0x6c, 0xf0, 0x00},
		End: Cpu{
			A:  0xcc,
			S:  0xff,
			PC: 0xcc03,
			P:  0xb0,
		},
	},
	{
		Name: "indexed indirect",
		Mem:  []byte{0xa2, 0x01, 0xa9, 0x05, 0x85, 0x01, 0xa9, 0x06, 0x85, 0x02, 0xa0, 0x0a, 0x8c, 0x05, 0x06, 0xa1, 0x00},
		End: Cpu{
			A:  0x0a,
			X:  0x01,
			Y:  0x0a,
			S:  0xff,
			PC: 0x0613,
			P:  0x30,
		},
	},
	{
		Name: "indirect indexed",
		Mem:  []byte{0xa0, 0x01, 0xa9, 0x03, 0x85, 0x01, 0xa9, 0x07, 0x85, 0x02, 0xa2, 0x0a, 0x8e, 0x04, 0x07, 0xb1, 0x01},
		End: Cpu{
			A:  0x0a,
			X:  0x0a,
			Y:  0x01,
			S:  0xff,
			PC: 0x0613,
			P:  0x30,
		},
	},
	{
		Name: "stack",
		Mem:  []byte{0xa2, 0x00, 0xa0, 0x00, 0x8a, 0x99, 0x00, 0x02, 0x48, 0xe8, 0xc8, 0xc0, 0x10, 0xd0, 0xf5, 0x68, 0x99, 0x00, 0x02, 0xc8, 0xc0, 0x20, 0xd0, 0xf7},
		End: Cpu{
			X:  0x10,
			Y:  0x20,
			S:  0xff,
			PC: 0x061a,
			P:  0x33,
		},
	},
	{
		Name: "jsr/rts",
		Mem:  []byte{0x20, 0x09, 0x06, 0x20, 0x0c, 0x06, 0x20, 0x12, 0x06, 0xa2, 0x00, 0x60, 0xe8, 0xe0, 0x05, 0xd0, 0xfb, 0x60, 0x00},
		End: Cpu{
			X:  0x05,
			S:  0xfd,
			PC: 0x0614,
			P:  0x33,
		},
	},
	{
		Name: "others",
		Mem:  []byte{0xa9, 0x30, 0x29, 0x9f, 0x0a, 0xa2, 0x0f, 0x86, 0x00, 0x06, 0x00, 0xa4, 0x00, 0x24, 0x00},
		End: Cpu{
			A:  0x20,
			X:  0x0f,
			Y:  0x1e,
			S:  0xff,
			PC: 0x0611,
			P:  0x32,
		},
	},
	{
		Name: "trb1",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x33, 0x14, 0x00},
		End: Cpu{
			A:  0x33,
			S:  0xff,
			PC: 0x060a,
			P:  0x30,
		},
	},
	{
		Name: "trb2",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x41, 0x14, 0x00},
		End: Cpu{
			A:  0x41,
			S:  0xff,
			PC: 0x060a,
			P:  0x32,
		},
	},
	{
		Name: "tsb1",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x33, 0x04, 0x00},
		End: Cpu{
			A:  0x33,
			S:  0xff,
			PC: 0x060a,
			P:  0x30,
		},
	},
	{
		Name: "tsb2",
		Mem:  []byte{0xa9, 0xa6, 0x85, 0x00, 0xa9, 0x41, 0x04, 0x00},
		End: Cpu{
			A:  0x41,
			S:  0xff,
			PC: 0x060a,
			P:  0x32,
		},
	},
}

func Test6502(t *testing.T) {
	for _, test := range CpuTests {
		r := make(Ram, 0xffff+1)
		c := New(r)
		copy(r[c.PC:], test.Mem)
		c.Run()
		if c.A != test.End.A ||
			c.X != test.End.X ||
			c.Y != test.End.Y ||
			c.S != test.End.S ||
			c.PC != test.End.PC ||
			c.P != test.End.P {
			t.Fatalf("bad cpu state %s, got:\n%sexpected:\n%s", test.Name, c, &test.End)
		}
	}
}

// Download from https://github.com/Klaus2m5/6502_65C02_functional_tests/blob/master/bin_files/6502_functional_test.bin
// GPL, so not included here.
func TestFunctional(t *testing.T) {
	b, err := ioutil.ReadFile("6502_functional_test.bin")
	if err != nil {
		t.Fatal(err)
	}
	r := make(Ram, 0xffff+1)
	copy(r[:], b)
	c := New(r)
	c.PC = 0x0400
	for !c.Halt {
		pc := c.PC
		c.Step()
		if c.PC == pc {
			t.Fatalf("repeated PC: 0x%04X", pc)
		} else if c.PC <= 0x1ff {
			t.Fatalf("low PC: 0x%04X", c.PC)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"

	auth "github.com/abbot/go-http-auth"
)

func main() {
	var (
		listen, cert, key, htpasswdFile, where string
	)
	flag.StringVar(&listen, "listen", ":443", "Bind address to listen on")
	flag.StringVar(&key, "key", "/etc/ssl/private/key.pem", "Path to PEM key")
	flag.StringVar(&cert, "cert", "/etc/ssl/private/cert.pem", "Path to PEM certificate")
	flag.StringVar(&htpasswdFile, "htpasswdFile", "", "File to use for htpasswd protected access")
	flag.StringVar(&where, "where", "http://localhost:80", "Place to forward connections to")

	flag.Parse()
	url, err := url.Parse(where)
	if err != nil {
		log.Fatal("Fatal parsing -where:", err)
	}

	var handler http.Handler = httputil.NewSingleHostReverseProxy(url)

	if htpasswdFile != "" {
		fd, err := os.Open(htpasswdFile)
		if err != nil {
			log.Fatal("Error opening htpasswdFile:", err)
		}
		fd.Close()
		secrets := auth.HtpasswdFileProvider(htpasswdFile)
		authenticator := auth.NewBasicAuthenticator(where, secrets)
		handler = auth.JustCheck(authenticator, handler.ServeHTTP)
	}

	err = http.ListenAndServeTLS(listen, cert, key, handler)
	if err != nil {
		log.Fatal("http.ListenAndServeTLS:", err)
	}
}
<commit_msg>Add authentication by source subnet<commit_after>package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"

	auth "github.com/abbot/go-http-auth"
)

type SubnetRoute struct {
	inside, outside http.Handler
	*net.IPNet
}

func (s *SubnetRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        host, _, err := net.SplitHostPort(r.RemoteAddr)
        if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
        }
	ip := net.ParseIP(host)
	if ip == nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	if s.Contains(ip) {
		s.inside.ServeHTTP(w, r)
	} else {
		s.outside.ServeHTTP(w, r)
	}
}

func main() {
	var (
		listen, cert, key, htpasswdFile, where, subnet string
	)
	flag.StringVar(&listen, "listen", ":443", "Bind address to listen on")
	flag.StringVar(&key, "key", "/etc/ssl/private/key.pem", "Path to PEM key")
	flag.StringVar(&cert, "cert", "/etc/ssl/private/cert.pem", "Path to PEM certificate")
	flag.StringVar(&htpasswdFile, "htpasswdFile", "", "File to use for htpasswd protected access")
	flag.StringVar(&where, "where", "http://localhost:80", "Place to forward connections to")
	flag.StringVar(&subnet, "subnet", "", "If specified, subnet which can circumvent htpasswd authorization")
	flag.Parse()

	url, err := url.Parse(where)
	if err != nil {
		log.Fatalln("Fatal parsing -where:", err)
	}

	_, ipNet, err := net.ParseCIDR(subnet)
	if err != nil {
		log.Fatalln("Error parsing -subnet:", err)
	}

	var handler, authenticated http.Handler
	handler = httputil.NewSingleHostReverseProxy(url)

        // Only really authenticated if htpasswdFile is specified
	authenticated = handler

	if htpasswdFile != "" {
                // First check that the htpasswdFile exists and is readable
		fd, err := os.Open(htpasswdFile)
		if err != nil {
			log.Fatalln("Error opening htpasswdFile:", err)
		}
		fd.Close()

		secrets := auth.HtpasswdFileProvider(htpasswdFile)
		authenticator := auth.NewBasicAuthenticator(where, secrets)
		authenticated = auth.JustCheck(authenticator, handler.ServeHTTP)
	}

	if subnet != "" {
		handler = &SubnetRoute{handler, authenticated, ipNet}
	}

	err = http.ListenAndServeTLS(listen, cert, key, handler)
	if err != nil {
		log.Fatalln("http.ListenAndServeTLS:", err)
	}
}
<|endoftext|>