<commit_before>package main

import (
	"encoding/csv"
	"github.com/yhat/scrape"
	"golang.org/x/net/html"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
)

type space struct {
	Name, Status, Updated, Available string
}

type structure struct {
	Name, URLCode string
	Number        int
	Spaces        []space
}

func main() {

	c := make(chan structure)
	go getStructures(c)
	for i := range c {
		writeData(i)
	}

}

func getStructures(c chan<- structure) {
	for i := 1; i < 9; i++ {
		if i == 7 || i == 4 {
			continue
		}

		s := structure{
			Name:    "Structure" + strconv.Itoa(i),
			Number:  i,
			URLCode: strconv.Itoa(i + 88),
		}
		s.Spaces = s.getSpaces()

		c <- s
	}
	close(c)
}

func (s structure) getSpaces() []space {

	spaces := []space{
		space{Name: "WSU Permit"},
		space{Name: "Student OneCard"},
		space{Name: "Visitor"},
	}
	re := map[string]*regexp.Regexp{
		"avail":   regexp.MustCompile(`[0-9]+`),
		"status":  regexp.MustCompile(`(OPEN|CLOSED|FULL)`),
		"updated": regexp.MustCompile(`(?P<1>^.+: )(?P<2>.+)`),
	}

	// Request
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://m.wayne.edu/parking.php?location="+s.URLCode, nil)
	if err != nil {
		log.Fatalln("Error making request:", err)
	}
	req.Header.Set("User-Agent", "Apple-iPhone6C1/")

	// Response
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln("Error sending request:", err)
	}
	defer resp.Body.Close()

	body, err := html.Parse(resp.Body)
	if err != nil {
		log.Fatalln("Error parsing response body:", err)
	}

	// Parse relevant response data
	dataString, _ := scrape.Find(body, scrape.ByClass("available"))
	lastUpdated, _ := scrape.Find(body, scrape.ByClass("last_updated"))

	avail := re["avail"].FindAllString(scrape.Text(dataString), -1)
	if len(avail) == 0 {
		avail = []string{"0", "0", "0"}
	}
	status := re["status"].FindAllString(scrape.Text(dataString), -1)
	updated := re["updated"].FindStringSubmatch(scrape.Text(lastUpdated))[2]

	for key := range spaces {
		spaces[key].Available = avail[key]
		spaces[key].Status = status[key]
		spaces[key].Updated = updated
	}

	return spaces

}

func writeData(s structure) {

	file, err := os.OpenFile(s.Name+".csv", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Fatalln("CSV file could not be created or opened:", err)
	}
	defer file.Close()

	writer := csv.NewWriter(file)

	if stat, _ := file.Stat(); stat.Size() == 0 {
		writer.Write([]string{"Updated", "Type", "Status", "Spaces Available"})
	}

	for _, sp := range s.Spaces {
		writer.Write([]string{sp.Updated, sp.Name, sp.Status, sp.Available})
	}
	writer.Flush()

}
<commit_msg>Fix filepath issue<commit_after>package main

import (
	"encoding/csv"
	"github.com/yhat/scrape"
	"golang.org/x/net/html"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
)

type space struct {
	Name, Status, Updated, Available string
}

type structure struct {
	Name, URLCode string
	Number        int
	Spaces        []space
}

func main() {

	c := make(chan structure)
	go getStructures(c)
	for i := range c {
		writeData(i)
	}

}

func getStructures(c chan<- structure) {
	for i := 1; i < 9; i++ {
		if i == 7 || i == 4 {
			continue
		}

		s := structure{
			Name:    "Structure" + strconv.Itoa(i),
			Number:  i,
			URLCode: strconv.Itoa(i + 88),
		}
		s.Spaces = s.getSpaces()

		c <- s
	}
	close(c)
}

func (s structure) getSpaces() []space {

	spaces := []space{
		space{Name: "WSU Permit"},
		space{Name: "Student OneCard"},
		space{Name: "Visitor"},
	}
	re := map[string]*regexp.Regexp{
		"avail":   regexp.MustCompile(`[0-9]+`),
		"status":  regexp.MustCompile(`(OPEN|CLOSED|FULL)`),
		"updated": regexp.MustCompile(`(?P<1>^.+: )(?P<2>.+)`),
	}

	// Request
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://m.wayne.edu/parking.php?location="+s.URLCode, nil)
	if err != nil {
		log.Fatalln("Error making request:", err)
	}
	req.Header.Set("User-Agent", "Apple-iPhone6C1/")

	// Response
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln("Error sending request:", err)
	}
	defer resp.Body.Close()

	body, err := html.Parse(resp.Body)
	if err != nil {
		log.Fatalln("Error parsing response body:", err)
	}

	// Parse relevant response data
	dataString, _ := scrape.Find(body, scrape.ByClass("available"))
	lastUpdated, _ := scrape.Find(body, scrape.ByClass("last_updated"))

	avail := re["avail"].FindAllString(scrape.Text(dataString), -1)
	if len(avail) == 0 {
		avail = []string{"0", "0", "0"}
	}
	status := re["status"].FindAllString(scrape.Text(dataString), -1)
	updated := re["updated"].FindStringSubmatch(scrape.Text(lastUpdated))[2]

	for key := range spaces {
		spaces[key].Available = avail[key]
		spaces[key].Status = status[key]
		spaces[key].Updated = updated
	}

	return spaces

}

func writeData(s structure) {

	file, err := os.OpenFile("/home/dsifford/Dropbox/ParkingData/"+s.Name+".csv", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Fatalln("CSV file could not be created or opened:", err)
	}
	defer file.Close()

	writer := csv.NewWriter(file)

	if stat, _ := file.Stat(); stat.Size() == 0 {
		writer.Write([]string{"Updated", "Type", "Status", "Spaces Available"})
	}

	for _, sp := range s.Spaces {
		writer.Write([]string{sp.Updated, sp.Name, sp.Status, sp.Available})
	}
	writer.Flush()

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"runtime"
	"sync"

	"github.com/arodland/go-hammer/hammer"
	"github.com/droundy/goopt"
)

var threads = goopt.Int([]string{"-T", "--threads"}, 4, "number of request threads")
var runFor = goopt.Int([]string{"-t", "--time", "--run-for"}, 60, "runtime in seconds")
var backlog = goopt.Int([]string{"-b", "--backlog"}, 10, "request backlog size")
var qps = goopt.Int([]string{"-r", "--rate"}, 10, "rumber of requests/second to send")
var urls = goopt.Strings([]string{"-u", "--url"}, "URL", "specify URLs to request")
var headerOpt = goopt.Strings([]string{"-h", "--header"}, "header", "specify headers to send with requests")

var skipBody = goopt.Flag(
	[]string{"--no-read-body"},
	[]string{"--read-body"},
	"Close the connection without reading the request body; don't measure the time to read the body.",
	"Time the request body.",
)

var logErrors = goopt.Flag(
	[]string{"--log-errors"},
	[]string{"--no-log-errors"},
	"Log all server error responses to disk.",
	"Don't log error responses.",
)

var name = goopt.String([]string{"--name"}, "hammer", "name for reporting")
var report = goopt.String([]string{"--report"}, "", "filename to write a report")
var statsfile = goopt.String([]string{"--stats"}, "", "filename to write statistics")

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	goopt.Parse(nil)

	*urls = append(*urls, goopt.Args...)

	if len(*urls) == 0 {
		fmt.Print(goopt.Help())
		return
	}

	var headers map[string][]string

	colon := regexp.MustCompile(`\s*:\s*`)
	for _, header := range *headerOpt {
		parts := colon.Split(header, 2)
		if headers[parts[0]] == nil {
			headers[parts[0]] = []string{parts[1]}
		} else {
			headers[parts[0]] = append(headers[parts[0]], parts[1])
		}
	}

	opts := hammer.RandomURLGeneratorOptions{
		URLs:    *urls,
		Headers: headers,
		Name:    *name,
	}
	if *skipBody {
		opts.BodyBehavior = hammer.IgnoreBody
	} else {
		opts.BodyBehavior = hammer.DiscardBody
	}
	generator := hammer.RandomURLGenerator(opts)

	h := hammer.Hammer{
		RunFor:           float64(*runFor),
		Threads:          *threads,
		Backlog:          *backlog,
		QPS:              float64(*qps),
		LogErrors:        *logErrors,
		GenerateFunction: generator,
	}

	var reportPrinter func(hammer.StatsSummary)
	if *report != "" {
		reportPrinter = h.ReportPrinter(*report)
	}
	var statsPrinter func(hammer.StatsSummary)
	if *statsfile != "" {
		statsPrinter = h.StatsPrinter(*statsfile)
	}

	statschan := make(chan hammer.StatsSummary)
	wg := sync.WaitGroup{}
	wg.Add(1)
	var percentDone int

	go func() {
		var stats hammer.StatsSummary
		for stats = range statschan {
			if reportPrinter != nil {
				reportPrinter(stats)
			}
			runTime := stats.End.Sub(stats.Begin).Seconds()
			percent := int(100 * runTime / h.RunFor)
			if percent/10 > percentDone/10 && percent < 100 {
				fmt.Printf("%d%%...", percent)
			}
			percentDone = percent
		}
		fmt.Printf("done\n")
		stats.PrintReport(os.Stdout)
		if statsPrinter != nil {
			statsPrinter(stats)
		}
		wg.Done()
	}()

	h.Run(statschan)
	wg.Wait()
}
<commit_msg>Godoc for main<commit_after>/*
Hammer is a utility for load-testing HTTP servers. In command-line form you
can think of it as an alternative to apachebench or siege, sending requests
at a controlled rate to a given URL or list of URLs and reporting on
throughput, latency, and the status codes of the responses. It is also
structured as a library that can be used to perform more advanced tasks,
such as using the response to one request to create a later request, and
gathering statistics for each type of request separately.

Example

hammer --threads 10 -r 20 -t 60 http://www.example.com/

Will send 20 requests per second to http://www.example.com/ for 60 seconds,
making a maximum of 10 concurrent requests.

Command Line Options

--url, -u: URLs to request

Specify one or more URLs for hammer to send requests to. Any options
provided on the commandline without a flag will also be interpreted as URLs,
so the use of --url or -u is optional.

--threads, -T: Number of request goroutines

This value controls the number of goroutines that will be used to send
requests to servers, which limits the maximum number of parallel requests
that can be in flight at one time. Too low a value can result in fewer
requests being sent than you requested; too high can result in resource
exhaustion on the target server or the hammering machine itself.

--time, --run-for, -t: Runtime (seconds)

Hammer will run until this timer expires, or until it is terminated by a
signal.

--rate, -r: Request rate (requests/second)

Hammer will attempt to send this many requests per second in total. If you
specify multiple URLs, the requests will be divided up evenly among all of
them.

--backlog, -b: Backlog size (requests)

The backlog is a queue of requests between the request rate throttler and
the requesting threads, ready to be sent immediately. If the requesting
threads are unable to send requests at the desired rate, the backlog will
fill up. Later, if possible, requests will be sent as fast as possible until
the backlog is empty in an attempt to "catch up". The backlog can help
smooth over network or server hiccups, but too large a backlog can result in
large request spikes.

--no-read-body, --read-body:

By default, hammer will read the entire HTTP response body and record the
time that it took to receive the response. With --no-read-body, hammer will
only read until the end of the headers, and no body timings will be
available. In the case of large or slow response bodies, you may be able to
generate many more requests by ignoring the bodies.

--log-errors, --no-log-errors:

If --log-errors is enabled, hammer will write a file to disk containing the
response headers and body whenever a 4xx or 5xx HTTP response is received
from the server. This may help to diagnose transient problems that appear
under load.

--report: Report filename

If this option is set, it specifies a file to write statistics to every
second during the run, in addition to writing them to the console at the end
of the run. If the filename contains a '*' character it will be replaced
with the value of the --name option.

--stats: Stats filename

If this option is set, it specifies a file to append abbreviated statistics
(single-line, tab-separated) to at the end of the run.

--name: Stats name

Name to use for --report and --stats output.

--header, -h:

Use --header to add headers to outgoing requests. Use as --header 'Name:
value'. Can be specified multiple times.
*/
package main

import (
	"fmt"
	"os"
	"regexp"
	"runtime"
	"sync"

	"github.com/arodland/go-hammer/hammer"
	"github.com/droundy/goopt"
)

var threads = goopt.Int([]string{"-T", "--threads"}, 4, "number of request threads")
var runFor = goopt.Int([]string{"-t", "--time", "--run-for"}, 60, "runtime in seconds")
var qps = goopt.Int([]string{"-r", "--rate"}, 10, "rumber of requests/second to send")
var backlog = goopt.Int([]string{"-b", "--backlog"}, 4, "request backlog size")

var skipBody = goopt.Flag(
	[]string{"--no-read-body"},
	[]string{"--read-body"},
	"Close the connection without reading the request body; don't measure the time to read the body.",
	"Time the request body.",
)

var logErrors = goopt.Flag(
	[]string{"--log-errors"},
	[]string{"--no-log-errors"},
	"Log all server error responses to disk.",
	"Don't log error responses.",
)

var report = goopt.String([]string{"--report"}, "", "filename to write a report")
var statsfile = goopt.String([]string{"--stats"}, "", "filename to write statistics")
var name = goopt.String([]string{"--name"}, "hammer", "name for reporting")

var headerOpt = goopt.Strings([]string{"-h", "--header"}, "header", "specify headers to send with requests")
var urls = goopt.Strings([]string{"-u", "--url"}, "URL", "specify URLs to request")

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	goopt.Parse(nil)

	*urls = append(*urls, goopt.Args...)

	if len(*urls) == 0 {
		fmt.Print(goopt.Help())
		return
	}

	var headers map[string][]string

	colon := regexp.MustCompile(`\s*:\s*`)
	for _, header := range *headerOpt {
		parts := colon.Split(header, 2)
		if headers[parts[0]] == nil {
			headers[parts[0]] = []string{parts[1]}
		} else {
			headers[parts[0]] = append(headers[parts[0]], parts[1])
		}
	}

	opts := hammer.RandomURLGeneratorOptions{
		URLs:    *urls,
		Headers: headers,
		Name:    *name,
	}
	if *skipBody {
		opts.BodyBehavior = hammer.IgnoreBody
	} else {
		opts.BodyBehavior = hammer.DiscardBody
	}
	generator := hammer.RandomURLGenerator(opts)

	h := hammer.Hammer{
		RunFor:           float64(*runFor),
		Threads:          *threads,
		Backlog:          *backlog,
		QPS:              float64(*qps),
		LogErrors:        *logErrors,
		GenerateFunction: generator,
	}

	var reportPrinter func(hammer.StatsSummary)
	if *report != "" {
		reportPrinter = h.ReportPrinter(*report)
	}
	var statsPrinter func(hammer.StatsSummary)
	if *statsfile != "" {
		statsPrinter = h.StatsPrinter(*statsfile)
	}

	statschan := make(chan hammer.StatsSummary)
	wg := sync.WaitGroup{}
	wg.Add(1)
	var percentDone int

	go func() {
		var stats hammer.StatsSummary
		for stats = range statschan {
			if reportPrinter != nil {
				reportPrinter(stats)
			}
			runTime := stats.End.Sub(stats.Begin).Seconds()
			percent := int(100 * runTime / h.RunFor)
			if percent/10 > percentDone/10 && percent < 100 {
				fmt.Printf("%d%%...", percent)
			}
			percentDone = percent
		}
		fmt.Printf("done\n")
		stats.PrintReport(os.Stdout)
		if statsPrinter != nil {
			statsPrinter(stats)
		}
		wg.Done()
	}()

	h.Run(statschan)
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"sync"
	"text/template"

	"github.com/fatih/color"
	"github.com/spf13/pflag"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	var (
		contextName           string
		kubeconfigPath        string
		labelSelectorExpr     string
		namespace             string
		allNamespaces         bool
		quiet                 bool
		timestamps            bool
		raw                   bool
		tmplString            string
		sinceStart            bool
		includePatterns       []*regexp.Regexp
		excludePatternStrings []string
	)

	flags := pflag.NewFlagSet("ktail", pflag.ExitOnError)
	flags.Usage = func() {
		flags.PrintDefaults()
	}
	flags.StringVar(&contextName, "context", "", "Kubernetes context name")
	flags.StringVar(&kubeconfigPath, "kubeconfig", "",
		"Path to kubeconfig (only required out-of-cluster)")
	flags.StringVarP(&namespace, "namespace", "n", "", "Kubernetes namespace")
	flags.StringArrayVarP(&excludePatternStrings, "exclude", "x", []string{},
		"Exclude using a regular expression. Pattern can be repeated. Takes priority over"+
			" include patterns and labels.")
	flags.StringVarP(&labelSelectorExpr, "selector", "l", "",
		"Match pods by label (see 'kubectl get -h' for syntax).")
	flags.StringVarP(&tmplString, "template", "t", "",
		"Template to format each line. For example, for"+
			" just the message, use --template '{{ .Message }}'.")
	flags.BoolVar(&allNamespaces, "all-namespaces", false, "Apply to all Kubernetes namespaces")
	flags.BoolVarP(&raw, "raw", "r", false, "Don't format output; output messages only (unless --timestamps)")
	flags.BoolVar(&timestamps, "timestamps", false, "Include timestamps on each line")
	flags.BoolVarP(&quiet, "quiet", "q", false, "Don't print events about new/deleted pods")
	flags.BoolVarP(&sinceStart, "since-start", "", false,
		"Start reading log from the beginning of the container's lifetime.")

	if err := flags.Parse(os.Args[1:]); err != nil {
		fail(err.Error())
		os.Exit(1)
	}

	var excludePatterns []*regexp.Regexp
	for _, p := range excludePatternStrings {
		r, err := regexp.Compile(p)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", p, err)
		}
		excludePatterns = append(excludePatterns, r)
	}

	for _, arg := range flags.Args() {
		r, err := regexp.Compile(arg)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", arg, err)
		}
		includePatterns = append(includePatterns, r)
	}

	if tmplString == "" {
		if raw {
			tmplString = `{{.Message}}`
		} else {
			tmplString = "{{.Pod.Name}}:{{.Container.Name}} {{.Message}}"
			if allNamespaces {
				tmplString = "{{.Pod.Namespace}}/" + tmplString
			}
		}
		if timestamps {
			tmplString = "{{.Timestamp}} " + tmplString
		}
	}
	tmplString += "\n"

	if kubeconfigPath == "" {
		if os.Getenv("KUBECONFIG") != "" {
			kubeconfigPath = os.Getenv("KUBECONFIG")
		} else {
			kubeconfigPath = clientcmd.RecommendedHomeFile
		}
	}

	labelSelector := labels.Everything()
	if labelSelectorExpr != "" {
		if sel, err := labels.Parse(labelSelectorExpr); err != nil {
			fail(err.Error())
		} else {
			labelSelector = sel
		}
	}

	inclusionMatcher := buildMatcher(includePatterns, labelSelector, true)
	exclusionMatcher := buildMatcher(excludePatterns, nil, false)

	tmpl, err := template.New("line").Parse(tmplString)
	if err != nil {
		fail("Invalid template: %s", err)
	}

	clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		&clientcmd.ClientConfigLoadingRules{
			ExplicitPath: kubeconfigPath,
		},
		&clientcmd.ConfigOverrides{
			CurrentContext: contextName,
		})

	config, err := clientConfig.ClientConfig()
	if err != nil {
		fail(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		fail(err.Error())
	}

	rawConfig, err := clientConfig.RawConfig()
	if err != nil {
		fail(err.Error())
	}

	if allNamespaces {
		namespace = v1.NamespaceAll
	} else if namespace == "" {
		if rawConfig.Contexts[rawConfig.CurrentContext].Namespace == "" {
			namespace = v1.NamespaceDefault
		} else {
			namespace = rawConfig.Contexts[rawConfig.CurrentContext].Namespace
		}
	}

	yellow := color.New(color.FgYellow)
	red := color.New(color.FgRed)

	formatPod := func(pod *v1.Pod) string {
		if allNamespaces {
			return fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
		}
		return pod.Name
	}

	formatPodAndContainer := func(pod *v1.Pod, container *v1.Container) string {
		return fmt.Sprintf("%s:%s", formatPod(pod), container.Name)
	}

	var stdoutMutex sync.Mutex
	controller := NewController(clientset, ControllerOptions{
		Namespace:        namespace,
		InclusionMatcher: inclusionMatcher,
		ExclusionMatcher: exclusionMatcher,
		SinceStart:       sinceStart,
	},
		Callbacks{
			OnEvent: func(event LogEvent) {
				stdoutMutex.Lock()
				defer stdoutMutex.Unlock()
				_ = tmpl.Execute(os.Stdout, event)
			},
			OnEnter: func(
				pod *v1.Pod,
				container *v1.Container,
				initialAddPhase bool) bool {
				if !quiet {
					if initialAddPhase {
						_, _ = yellow.Fprintf(os.Stderr,
							"==> Detected running container [%s]\n", formatPodAndContainer(pod, container))
					} else {
						_, _ = yellow.Fprintf(os.Stderr,
							"==> New container [%s]\n", formatPodAndContainer(pod, container))
					}
				}
				return true
			},
			OnExit: func(pod *v1.Pod, container *v1.Container) {
				if !quiet {
					var status = "unknown"
					for _, containerStatus := range pod.Status.ContainerStatuses {
						if containerStatus.Name == container.Name {
							if containerStatus.State.Running != nil {
								status = "running"
							} else if containerStatus.State.Waiting != nil {
								status = "waiting"
							} else if containerStatus.State.Terminated != nil {
								status = "terminated"
							}
							break
						}
					}
					_, _ = yellow.Fprintf(os.Stderr,
						"==> Container left (%s) [%s]\n", status,
						formatPodAndContainer(pod, container))
				}
			},
			OnError: func(pod *v1.Pod, container *v1.Container, err error) {
				_, _ = red.Fprintf(os.Stderr,
					"==> Warning: Error while tailing container [%s]: %s\n",
					formatPodAndContainer(pod, container), err)
			},
		})
	controller.Run()
}

func fail(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}
<commit_msg>Add -T as alias for --timestamps.<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"sync"
	"text/template"

	"github.com/fatih/color"
	"github.com/spf13/pflag"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	var (
		contextName           string
		kubeconfigPath        string
		labelSelectorExpr     string
		namespace             string
		allNamespaces         bool
		quiet                 bool
		timestamps            bool
		raw                   bool
		tmplString            string
		sinceStart            bool
		includePatterns       []*regexp.Regexp
		excludePatternStrings []string
	)

	flags := pflag.NewFlagSet("ktail", pflag.ExitOnError)
	flags.Usage = func() {
		flags.PrintDefaults()
	}
	flags.StringVar(&contextName, "context", "", "Kubernetes context name")
	flags.StringVar(&kubeconfigPath, "kubeconfig", "",
		"Path to kubeconfig (only required out-of-cluster)")
	flags.StringVarP(&namespace, "namespace", "n", "", "Kubernetes namespace")
	flags.StringArrayVarP(&excludePatternStrings, "exclude", "x", []string{},
		"Exclude using a regular expression. Pattern can be repeated. Takes priority over"+
			" include patterns and labels.")
	flags.StringVarP(&labelSelectorExpr, "selector", "l", "",
		"Match pods by label (see 'kubectl get -h' for syntax).")
	flags.StringVarP(&tmplString, "template", "t", "",
		"Template to format each line. For example, for"+
			" just the message, use --template '{{ .Message }}'.")
	flags.BoolVar(&allNamespaces, "all-namespaces", false, "Apply to all Kubernetes namespaces")
	flags.BoolVarP(&raw, "raw", "r", false, "Don't format output; output messages only (unless --timestamps)")
	flags.BoolVarP(&timestamps, "timestamps", "T", false, "Include timestamps on each line")
	flags.BoolVarP(&quiet, "quiet", "q", false, "Don't print events about new/deleted pods")
	flags.BoolVarP(&sinceStart, "since-start", "", false,
		"Start reading log from the beginning of the container's lifetime.")

	if err := flags.Parse(os.Args[1:]); err != nil {
		fail(err.Error())
		os.Exit(1)
	}

	var excludePatterns []*regexp.Regexp
	for _, p := range excludePatternStrings {
		r, err := regexp.Compile(p)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", p, err)
		}
		excludePatterns = append(excludePatterns, r)
	}

	for _, arg := range flags.Args() {
		r, err := regexp.Compile(arg)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", arg, err)
		}
		includePatterns = append(includePatterns, r)
	}

	if tmplString == "" {
		if raw {
			tmplString = `{{.Message}}`
		} else {
			tmplString = "{{.Pod.Name}}:{{.Container.Name}} {{.Message}}"
			if allNamespaces {
				tmplString = "{{.Pod.Namespace}}/" + tmplString
			}
		}
		if timestamps {
			tmplString = "{{.Timestamp}} " + tmplString
		}
	}
	tmplString += "\n"

	if kubeconfigPath == "" {
		if os.Getenv("KUBECONFIG") != "" {
			kubeconfigPath = os.Getenv("KUBECONFIG")
		} else {
			kubeconfigPath = clientcmd.RecommendedHomeFile
		}
	}

	labelSelector := labels.Everything()
	if labelSelectorExpr != "" {
		if sel, err := labels.Parse(labelSelectorExpr); err != nil {
			fail(err.Error())
		} else {
			labelSelector = sel
		}
	}

	inclusionMatcher := buildMatcher(includePatterns, labelSelector, true)
	exclusionMatcher := buildMatcher(excludePatterns, nil, false)

	tmpl, err := template.New("line").Parse(tmplString)
	if err != nil {
		fail("Invalid template: %s", err)
	}

	clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		&clientcmd.ClientConfigLoadingRules{
			ExplicitPath: kubeconfigPath,
		},
		&clientcmd.ConfigOverrides{
			CurrentContext: contextName,
		})

	config, err := clientConfig.ClientConfig()
	if err != nil {
		fail(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		fail(err.Error())
	}

	rawConfig, err := clientConfig.RawConfig()
	if err != nil {
		fail(err.Error())
	}

	if allNamespaces {
		namespace = v1.NamespaceAll
	} else if namespace == "" {
		if rawConfig.Contexts[rawConfig.CurrentContext].Namespace == "" {
			namespace = v1.NamespaceDefault
		} else {
			namespace = rawConfig.Contexts[rawConfig.CurrentContext].Namespace
		}
	}

	yellow := color.New(color.FgYellow)
	red := color.New(color.FgRed)

	formatPod := func(pod *v1.Pod) string {
		if allNamespaces {
			return fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
		}
		return pod.Name
	}

	formatPodAndContainer := func(pod *v1.Pod, container *v1.Container) string {
		return fmt.Sprintf("%s:%s", formatPod(pod), container.Name)
	}

	var stdoutMutex sync.Mutex
	controller := NewController(clientset, ControllerOptions{
		Namespace:        namespace,
		InclusionMatcher: inclusionMatcher,
		ExclusionMatcher: exclusionMatcher,
		SinceStart:       sinceStart,
	},
		Callbacks{
			OnEvent: func(event LogEvent) {
				stdoutMutex.Lock()
				defer stdoutMutex.Unlock()
				_ = tmpl.Execute(os.Stdout, event)
			},
			OnEnter: func(
				pod *v1.Pod,
				container *v1.Container,
				initialAddPhase bool) bool {
				if !quiet {
					if initialAddPhase {
						_, _ = yellow.Fprintf(os.Stderr,
							"==> Detected running container [%s]\n", formatPodAndContainer(pod, container))
					} else {
						_, _ = yellow.Fprintf(os.Stderr,
							"==> New container [%s]\n", formatPodAndContainer(pod, container))
					}
				}
				return true
			},
			OnExit: func(pod *v1.Pod, container *v1.Container) {
				if !quiet {
					var status = "unknown"
					for _, containerStatus := range pod.Status.ContainerStatuses {
						if containerStatus.Name == container.Name {
							if containerStatus.State.Running != nil {
								status = "running"
							} else if containerStatus.State.Waiting != nil {
								status = "waiting"
							} else if containerStatus.State.Terminated != nil {
								status = "terminated"
							}
							break
						}
					}
					_, _ = yellow.Fprintf(os.Stderr,
						"==> Container left (%s) [%s]\n", status,
						formatPodAndContainer(pod, container))
				}
			},
			OnError: func(pod *v1.Pod, container *v1.Container, err error) {
				_, _ = red.Fprintf(os.Stderr,
					"==> Warning: Error while tailing container [%s]: %s\n",
					formatPodAndContainer(pod, container), err)
			},
		})
	controller.Run()
}

func fail(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"strings"

	"github.com/bitly/go-simplejson"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/logger"
)

type waypointPayload struct {
	Sequence    uint8
	AddressType uint8
	Rssi        int8
	Valid       uint8
}

// configure the agent logger
var log = logger.GetLogger("driver-go-ble")

func sendRssi(device string, waypoint string, rssi int8, conn *ninja.NinjaConnection) {
	log.Debugf(">> Device:%s Waypoint:%s Rssi: %d", device, waypoint, rssi)

	packet, _ := simplejson.NewJson([]byte(`{
    "params": [
        {
            "device": "",
            "waypoint": "",
            "rssi": 0,
            "isSphere": true
        },
        "locator"
    ],
    "time": 0,
    "jsonrpc": "2.0"
}`))

	packet.Get("params").GetIndex(0).Set("device", device)
	packet.Get("params").GetIndex(0).Set("waypoint", waypoint)
	packet.Get("params").GetIndex(0).Set("rssi", rssi)
	conn.PublishMessage("$device/"+device+"/TEMPPATH/rssi", packet)
}

func main() {
	os.Exit(realMain())
}

func realMain() int {

	var conn, err = ninja.Connect("com.ninjablocks.ble")

	if err != nil {
		log.Errorf("Connect failed: %v", err)
		return 1
	}

	out, err := exec.Command("hciconfig").Output()
	if err != nil {
		log.Errorf(fmt.Sprintf("Error: %s", err))
	}
	re := regexp.MustCompile("([0-9A-F]{2}\\:{0,1}){6}")
	mac := strings.Replace(re.FindString(string(out)), ":", "", -1)
	log.Infof("The local mac is %s\n", mac)

	client := &gatt.Client{
		StateChange: func(newState string) {
			log.Infof("Client state change: %s", newState)
		},
	}

	/*
	  Waypoint notification characteristic {
	    "startHandle": 45,
	    "properties": 16, (useNotify = true, useIndicate = false)
	    "valueHandle": 46,
	    "uuid": "fff4",
	    "endHandle": 48,
	  }
	*/

	activeWaypoints := make(map[string]bool)

	client.Rssi = func(address string, rssi int8) {
		//log.Printf("Rssi update address:%s rssi:%d", address, rssi)
		sendRssi(strings.Replace(address, ":", "", -1), mac, rssi, conn)
		//spew.Dump(device);
	}

	client.Advertisement = func(device *gatt.DiscoveredDevice) {
		log.Debugf("Discovered address:%s rssi:%d", device.Address, device.Rssi)

		if device.Advertisement.LocalName != "NinjaSphereWaypoint" {
			return
		}

		if activeWaypoints[device.Address] {
			return
		}

		if device.Connected == nil {
			device.Connected = func() {
				log.Infof("Connected to waypoint: %s", device.Address)
				//spew.Dump(device.Advertisement)

				// XXX: Yes, magic numbers.... this enables the notification from our Waypoints
				client.Notify(device.Address, true, 45, 48, true, false)
			}

			device.Disconnected = func() {
				log.Infof("Disconnceted from waypoint: %s", device.Address)

				activeWaypoints[device.Address] = false
			}

			device.Notification = func(notification *gatt.Notification) {
				//log.Printf("Got the notification!")

				//XXX: Add the ieee into the payload somehow??
				var payload waypointPayload
				err := binary.Read(bytes.NewReader(notification.Data), binary.LittleEndian, &payload)
				if err != nil {
					log.Errorf("Failed to read waypoint payload : %s", err)
				}

				//	ieee := net.HardwareAddr(reverse(notification.Data[4:]))

				//spew.Dump("ieee:", reverse(notification.Data[4:]), strings.ToUpper(ieee.String()), payload)

				sendRssi(fmt.Sprintf("%x", reverse(notification.Data[4:])), strings.Replace(device.Address, ":", "", -1), payload.Rssi, conn)
			}
		}

		err := client.Connect(device.Address, device.PublicAddress)
		if err != nil {
			log.Errorf("Connect error:%s", err)
			return
		}

		activeWaypoints[device.Address] = true

	}

	err = client.Start()

	if err != nil {
		log.Errorf("Failed to start client: %s", err)
	}

	err = client.StartScanning(true)
	if err != nil {
		log.Errorf("Failed to start scanning: %s", err)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	// Block until a signal is received.
	s := <-c
	log.Infof("Got signal:", s)

	return 0
}

// reverse returns a reversed copy of u.
func reverse(u []byte) []byte {
	l := len(u)
	b := make([]byte, l)
	for i := 0; i < l/2+1; i++ {
		b[i], b[l-i-1] = u[l-i-1], u[i]
	}
	return b
}
<commit_msg>Add device name and isSphere to rssi packets<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"strings"

	"github.com/bitly/go-simplejson"
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/logger"
)

type waypointPayload struct {
	Sequence    uint8
	AddressType uint8
	Rssi        int8
	Valid       uint8
}

// configure the agent logger
var log = logger.GetLogger("driver-go-ble")

func sendRssi(device string, name string, waypoint string, rssi int8, isSphere bool, conn *ninja.NinjaConnection) {
	log.Debugf(">> Device:%s Waypoint:%s Rssi: %d", device, waypoint, rssi)

	packet, _ := simplejson.NewJson([]byte(`{
    "params": [
        {
            "device": "",
            "waypoint": "",
            "rssi": 0,
            "isSphere": true
        },
        "locator"
    ],
    "time": 0,
    "jsonrpc": "2.0"
}`))

	packet.Get("params").GetIndex(0).Set("device", device)
	if name != "" {
		packet.Get("params").GetIndex(0).Set("name", name)
	}
	packet.Get("params").GetIndex(0).Set("waypoint", waypoint)
	packet.Get("params").GetIndex(0).Set("rssi", rssi)
	packet.Get("params").GetIndex(0).Set("isSphere", isSphere)

	spew.Dump(packet)
	conn.PublishMessage("$device/"+device+"/TEMPPATH/rssi", packet)
}

func main() {
	os.Exit(realMain())
}

func realMain() int {

	var conn, err = ninja.Connect("com.ninjablocks.ble")

	if err != nil {
		log.Errorf("Connect failed: %v", err)
		return 1
	}

	out, err := exec.Command("hciconfig").Output()
	if err != nil {
		log.Errorf(fmt.Sprintf("Error: %s", err))
	}
	re := regexp.MustCompile("([0-9A-F]{2}\\:{0,1}){6}")
	mac := strings.Replace(re.FindString(string(out)), ":", "", -1)
	log.Infof("The local mac is %s\n", mac)

	client := &gatt.Client{
		StateChange: func(newState string) {
			log.Infof("Client state change: %s", newState)
		},
	}

	/*
	  Waypoint notification characteristic {
	    "startHandle": 45,
	    "properties": 16, (useNotify = true, useIndicate = false)
	    "valueHandle": 46,
	    "uuid": "fff4",
	    "endHandle": 48,
	  }
	*/

	activeWaypoints := make(map[string]bool)

	client.Rssi = func(address string, name string, rssi int8) {
		//log.Printf("Rssi update address:%s rssi:%d", address, rssi)
		sendRssi(strings.Replace(address, ":", "", -1), name, mac, rssi, true, conn)
		//spew.Dump(device);
	}

	client.Advertisement = func(device *gatt.DiscoveredDevice) {
		log.Debugf("Discovered address:%s rssi:%d", device.Address, device.Rssi)

		if device.Advertisement.LocalName != "NinjaSphereWaypoint" {
			return
		}

		if activeWaypoints[device.Address] {
			return
		}

		if device.Connected == nil {
			device.Connected = func() {
				log.Infof("Connected to waypoint: %s", device.Address)
				//spew.Dump(device.Advertisement)

				// XXX: Yes, magic numbers.... this enables the notification from our Waypoints
				client.Notify(device.Address, true, 45, 48, true, false)
			}

			device.Disconnected = func() {
				log.Infof("Disconnected from waypoint: %s", device.Address)

				activeWaypoints[device.Address] = false
			}

			device.Notification = func(notification *gatt.Notification) {
				//log.Printf("Got the notification!")

				//XXX: Add the ieee into the payload somehow??
				var payload waypointPayload
				err := binary.Read(bytes.NewReader(notification.Data), binary.LittleEndian, &payload)
				if err != nil {
					log.Errorf("Failed to read waypoint payload : %s", err)
				}

				//	ieee := net.HardwareAddr(reverse(notification.Data[4:]))

				spew.Dump("ieee:", payload)

				sendRssi(fmt.Sprintf("%x", reverse(notification.Data[4:])), "", strings.Replace(device.Address, ":", "", -1), payload.Rssi, false, conn)
			}
		}

		err := client.Connect(device.Address, device.PublicAddress)
		if err != nil {
			log.Errorf("Connect error:%s", err)
			return
		}

		activeWaypoints[device.Address] = true

	}

	err = client.Start()

	if err != nil {
		log.Errorf("Failed to start client: %s", err)
	}

	err = client.StartScanning(true)
	if err != nil {
		log.Errorf("Failed to start scanning: %s", err)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	// Block until a signal is received.
	s := <-c
	log.Infof("Got signal:", s)

	return 0
}

// reverse returns a reversed copy of u.
func reverse(u []byte) []byte {
	l := len(u)
	b := make([]byte, l)
	for i := 0; i < l/2+1; i++ {
		b[i], b[l-i-1] = u[l-i-1], u[i]
	}
	return b
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/dimfeld/httptreemux"
	"github.com/kabukky/httpscerts"
	"github.com/kabukky/journey/configuration"
	"github.com/kabukky/journey/database"
	"github.com/kabukky/journey/filenames"
	"github.com/kabukky/journey/server"
	"github.com/kabukky/journey/templates"
	"log"
	"net/http"
	"os"
	"runtime"
)

func httpsRedirect(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	http.Redirect(w, r, configuration.Config.HttpsUrl+r.RequestURI, http.StatusMovedPermanently)
	return
}

func checkHttpsCertificates() {
	// Check https certificates. If they are not available generate temporary ones for testing.
	err := httpscerts.Check(filenames.HttpsCertFilename, filenames.HttpsKeyFilename)
	if err != nil {
		log.Println("Warning: couldn't load https certs. Generating new ones. Replace " + filenames.HttpsCertFilename + " and " + filenames.HttpsKeyFilename + " with your own certificates as soon as possible!")
		err := httpscerts.Generate(filenames.HttpsCertFilename, filenames.HttpsKeyFilename, configuration.Config.HttpsUrl)
		if err != nil {
			log.Fatal("Error: Couldn't create https certificates.")
			return
		}
	}
}

func main() {
	// Setup

	// GOMAXPROCS - Maybe not needed
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Write log to file
	logFile, err := os.OpenFile(filenames.LogFilename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Error: Couldn't open log file: " + err.Error())
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	// Configuration is read from config.json by loading the configuration package

	// Database
	err = database.Initialize()
	if err != nil {
		log.Fatal("Error: Couldn't initialize database: " + err.Error())
		return
	}

	// Templates
	err = templates.Generate()
	if err != nil {
		log.Fatal("Error: Couldn't compile templates: " + err.Error())
		return
	}

	// HTTP(S) Server
	// Determine the kind of https support (as set in the config.json)
	switch configuration.Config.HttpsUsage {
	case "AdminOnly":
		checkHttpsCertificates()
		httpRouter := httptreemux.New()
		httpsRouter := httptreemux.New()
		// Blog as http
		server.InitializeBlog(httpRouter)
		// Blog as https
		server.InitializeBlog(httpsRouter)
		// Admin as https and http redirect
		// Add redirection to http router
		httpRouter.GET("/admin", httpsRedirect)
		// Add routes to https router
		server.InitializeAdmin(httpsRouter)
		// Start https server
		log.Println("Starting https server on port " + configuration.Config.HttpsHostAndPort + "...")
		go http.ListenAndServeTLS(configuration.Config.HttpsHostAndPort, filenames.HttpsCertFilename, filenames.HttpsKeyFilename, httpsRouter)
		// Start http server
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	case "All":
		checkHttpsCertificates()
		httpsRouter := httptreemux.New()
		httpRouter := httptreemux.New()
		// Blog as https
		server.InitializeBlog(httpsRouter)
		// Admin as https
		server.InitializeAdmin(httpsRouter)
		// Add redirection to http router
		httpRouter.GET("/", httpsRedirect)
		// Start https server
		log.Println("Starting https server on port " + configuration.Config.HttpsHostAndPort + "...")
		go http.ListenAndServeTLS(configuration.Config.HttpsHostAndPort, filenames.HttpsCertFilename, filenames.HttpsKeyFilename, httpsRouter)
		// Start http server
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	default: // This is configuration.HttpsUsage == "None"
		httpRouter := httptreemux.New()
		// Blog as http
		server.InitializeBlog(httpRouter)
		// Admin as http
		server.InitializeAdmin(httpRouter)
		// Start http server
		log.Println("Starting server without HTTPS support. Please enable HTTPS in " + filenames.ConfigFilename + " to improve security.")
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	}
}
<commit_msg>Fixed redirection to https<commit_after>package main

import (
	"github.com/dimfeld/httptreemux"
	"github.com/kabukky/httpscerts"
	"github.com/kabukky/journey/configuration"
	"github.com/kabukky/journey/database"
	"github.com/kabukky/journey/filenames"
	"github.com/kabukky/journey/server"
	"github.com/kabukky/journey/templates"
	"log"
	"net/http"
	"os"
	"runtime"
)

func httpsRedirect(w http.ResponseWriter, r *http.Request, _ map[string]string) {
	http.Redirect(w, r, configuration.Config.HttpsUrl+r.RequestURI, http.StatusMovedPermanently)
	return
}

func checkHttpsCertificates() {
	// Check https certificates. If they are not available generate temporary ones for testing.
	err := httpscerts.Check(filenames.HttpsCertFilename, filenames.HttpsKeyFilename)
	if err != nil {
		log.Println("Warning: couldn't load https certs. Generating new ones. Replace " + filenames.HttpsCertFilename + " and " + filenames.HttpsKeyFilename + " with your own certificates as soon as possible!")
		err := httpscerts.Generate(filenames.HttpsCertFilename, filenames.HttpsKeyFilename, configuration.Config.HttpsUrl)
		if err != nil {
			log.Fatal("Error: Couldn't create https certificates.")
			return
		}
	}
}

func main() {
	// Setup

	// GOMAXPROCS - Maybe not needed
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Write log to file
	logFile, err := os.OpenFile(filenames.LogFilename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Error: Couldn't open log file: " + err.Error())
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	// Configuration is read from config.json by loading the configuration package

	// Database
	err = database.Initialize()
	if err != nil {
		log.Fatal("Error: Couldn't initialize database: " + err.Error())
		return
	}

	// Templates
	err = templates.Generate()
	if err != nil {
		log.Fatal("Error: Couldn't compile templates: " + err.Error())
		return
	}

	// HTTP(S) Server
	// Determine the kind of https support (as set in the config.json)
	switch configuration.Config.HttpsUsage {
	case "AdminOnly":
		checkHttpsCertificates()
		httpRouter := httptreemux.New()
		httpsRouter := httptreemux.New()
		// Blog as http
		server.InitializeBlog(httpRouter)
		// Blog as https
		server.InitializeBlog(httpsRouter)
		// Admin as https and http redirect
		// Add redirection to http router
		httpRouter.GET("/admin/*path", httpsRedirect)
		// Add routes to https router
		server.InitializeAdmin(httpsRouter)
		// Start https server
		log.Println("Starting https server on port " + configuration.Config.HttpsHostAndPort + "...")
		go http.ListenAndServeTLS(configuration.Config.HttpsHostAndPort, filenames.HttpsCertFilename, filenames.HttpsKeyFilename, httpsRouter)
		// Start http server
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	case "All":
		checkHttpsCertificates()
		httpsRouter := httptreemux.New()
		httpRouter := httptreemux.New()
		// Blog as https
		server.InitializeBlog(httpsRouter)
		// Admin as https
		server.InitializeAdmin(httpsRouter)
		// Add redirection to http router
		httpRouter.GET("/", httpsRedirect)
		httpRouter.GET("/*path", httpsRedirect)
		// Start https server
		log.Println("Starting https server on port " + configuration.Config.HttpsHostAndPort + "...")
		go http.ListenAndServeTLS(configuration.Config.HttpsHostAndPort, filenames.HttpsCertFilename, filenames.HttpsKeyFilename, httpsRouter)
		// Start http server
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	default: // This is configuration.HttpsUsage == "None"
		httpRouter := httptreemux.New()
		// Blog as http
		server.InitializeBlog(httpRouter)
		// Admin as http
		server.InitializeAdmin(httpRouter)
		// Start http server
		log.Println("Starting server without HTTPS support. Please enable HTTPS in " + filenames.ConfigFilename + " to improve security.")
		log.Println("Starting http server on port " + configuration.Config.HttpHostAndPort + "...")
		http.ListenAndServe(configuration.Config.HttpHostAndPort, httpRouter)
	}
}
<|endoftext|>


<commit_before>package main

import (
	_ "crypto/sha512"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
	"html/template"
	"log"
	"net/http"
	"strings"
)

const (
	// Route names
	Index        = "/"
	Login        = "/login"
	SetAuthCode  = "/uber/setauthcode"
	ReceiptReady = "/uber/webooks/requests.receipt_ready"
	UberWebhook  = "/uber/webhook"
	MondoWebhook = "/mondo/webhook"
)

type session struct {
	sessionId        string
	mondoAccessToken string
	mondoAccountId   string
	mondoWebhookId   string
	uberAccessToken  string
}

var certFile = flag.String("certFile", "cert.pem", "SSL certificate")
var keyFile = flag.String("keyFile", "key.pem", "SSL certificate")
var addr = flag.String("addr", ":443", "https list addr")
var thisUrl = flag.String("url", "", "public url e.g. https://foo (required)")
var uberClientId = flag.String("uberClientId", "", "Uber client_id (required)")
var uberClientSecret = flag.String("uberClientSecret", "", "Uber client_secret (required)")
var uberApiHost = flag.String("uberApi", "https://api.uber.com/v1", "Uber API URL")
var mondoApiUrl = flag.String("mondoApi", "https://api.getmondo.co.uk", "Mondo API URL")

var indexTemplate = template.Must(template.ParseFiles("index.html"))
var pleaseWaitTemplate = template.Must(template.ParseFiles("pleasewait.html"))
var loginSuccessTemplate = template.Must(template.ParseFiles("loginsuccess.html"))

var sessions = make(map[string]*session)
var router = mux.NewRouter()
var uberApiClient *UberApiClient
var mondoApiClient *MondoApiClient

func indexGet(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	indexTemplate.Execute(w, r.Host)
}

func loginPost(w http.ResponseWriter, r *http.Request) {
	mondoAccessToken := r.FormValue("mondo-access-token")
	mondoAccountId := r.FormValue("mondo-account-id")

	if mondoAccessToken == "" || mondoAccountId == "" {
		http.Error(w, "required: mondo-access-token, mondo-account-id", http.StatusBadRequest)
		log.Printf("%s required: mondo-access-token, mondo-account-id", Login)
		return
	}

	// Register session
	uuid, err := uuid.NewV4()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s generate session id error: %s", Login, err.Error())
		return
	}

	sessionId := uuid.String()
	session := &session{
		sessionId:        sessionId,
		mondoAccessToken: mondoAccessToken,
		mondoAccountId:   mondoAccountId}

	sessions[sessionId] = session

	uberAuthorizeUrl := fmt.Sprintf("%s/oauth/authorize?response_type=code&client_id=%s&state=%s", UberAuthHost, *uberClientId, sessionId)
	log.Printf("redirecting to %s", uberAuthorizeUrl)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	data := struct{ UberAuthorizeUrl string }{UberAuthorizeUrl: uberAuthorizeUrl}
	pleaseWaitTemplate.Execute(w, data)
}

func uberSetAuthCodeGet(w http.ResponseWriter, r *http.Request) {
	sessionId := r.URL.Query()["state"][0]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	redirectUriPath, err := router.Get(SetAuthCode).URLPath()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	redirectUri := fmt.Sprintf("%s%s", *thisUrl, redirectUriPath)

	uberAuthorizationCode := r.URL.Query()["code"][0]
	uberTokenResponse, err := uberApiClient.GetOAuthToken(uberAuthorizationCode, redirectUri)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s uber oauth token error: %s", SetAuthCode, err.Error())
		return
	}

	session.uberAccessToken = uberTokenResponse.AccessToken
	log.Printf("%s assigned session id=%s Uber access_token=%s\n", SetAuthCode, sessionId, uberTokenResponse.AccessToken)

	// Register Mondo webhook
	mondoWebhookPath, err := router.Get(MondoWebhook).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	mondoWebhookUrl := fmt.Sprintf("%s%s", *thisUrl, mondoWebhookPath)
	log.Printf("%s registering mondo webhook url=%s", SetAuthCode, mondoWebhookUrl)
	mondoWebhookResponse, err := mondoApiClient.RegisterWebHook(session.mondoAccessToken, session.mondoAccountId, mondoWebhookUrl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s register mondo webhook error: %s", SetAuthCode, err.Error())
		return
	}

	session.mondoWebhookId = mondoWebhookResponse.Webhook.Id
	log.Printf("%s successfully registered mondo webhook id=%s", SetAuthCode, mondoWebhookResponse.Webhook.Id)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	loginSuccessTemplate.Execute(w, r)
}

func mondoWebhookPost(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	var request = &WebhookRequest{}
	err := json.NewDecoder(r.Body).Decode(request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Printf("%s json parse error: %s", MondoWebhook, err.Error())
		return
	}

	if !strings.Contains(strings.ToUpper(request.Data.Description), "UBER") {
		fmt.Printf("%s ignored transaction: %s", request.Data.Description)
		return
	}

	vars := mux.Vars(r)
	sessionId := vars["sessionId"]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	uberHistoryResponse, err := uberApiClient.GetHistory(session.uberAccessToken)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get history error: %s", SetAuthCode, err.Error())
		return
	}

	uberHistoryItem := uberHistoryResponse.History[0]
	requestId := uberHistoryItem.RequestId
	uberReceiptResponse, err := uberApiClient.GetReceipt(session.uberAccessToken, requestId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get receipt error: %s", SetAuthCode, err.Error())
		return
	}

	uberMapResponse, err := uberApiClient.GetMap(session.uberAccessToken, requestId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get map error: %s", SetAuthCode, err.Error())
		return
	}

	// Todo: look up Uber product types
	feedItemTitle := fmt.Sprintf("%s UberX %s", uberReceiptResponse.TotalCharged, uberHistoryItem.StartCity.DisplayName)

	err = mondoApiClient.CreateFeedItem(
		session.mondoAccessToken,
		session.mondoAccountId,
		"image",
		"Uber Receipt",
		uberMapResponse.Href,
		feedItemTitle)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s create feed item error: %s", SetAuthCode, err.Error())
		return
	}
}

func middleware(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	flag.Parse()
	if *uberClientId == "" || *uberClientSecret == "" || *thisUrl == "" {
		flag.PrintDefaults()
		return
	}
	uberApiClient = &UberApiClient{
		url: *uberApiHost,
		clientSecret: *uberClientSecret,
		clientId: *uberClientId,
	}

	mondoApiClient = &MondoApiClient{url: *mondoApiUrl}

	router.HandleFunc("/", indexGet).Methods("GET").Name(Index)
	router.HandleFunc("/login", loginPost).Methods("POST").Name(Login)
	router.HandleFunc("/uber/setauthcode", uberSetAuthCodeGet).Methods("GET").Name(SetAuthCode)
	router.HandleFunc("/mondo/webhook/{sessionId}", mondoWebhookPost).Methods("POST").Name(MondoWebhook)
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))
	log.Printf("Listening on %s\n", *addr)
	if strings.Contains(*addr, "443") {
		log.Fatal(http.ListenAndServeTLS(*addr, *certFile, *keyFile, middleware(router)))
	} else {
		log.Fatal(http.ListenAndServe(*addr, middleware(router)))
	}
}
<commit_msg>Fix URL<commit_after>package main

import (
	_ "crypto/sha512"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
	"html/template"
	"log"
	"net/http"
	"strings"
)

const (
	// Route names
	Index        = "/"
	Login        = "/login"
	SetAuthCode  = "/uber/setauthcode"
	ReceiptReady = "/uber/webooks/requests.receipt_ready"
	UberWebhook  = "/uber/webhook"
	MondoWebhook = "/mondo/webhook"
)

type session struct {
	sessionId        string
	mondoAccessToken string
	mondoAccountId   string
	mondoWebhookId   string
	uberAccessToken  string
}

var certFile = flag.String("certFile", "cert.pem", "SSL certificate")
var keyFile = flag.String("keyFile", "key.pem", "SSL certificate")
var addr = flag.String("addr", ":443", "https list addr")
var thisUrl = flag.String("url", "", "public url e.g. https://foo (required)")
var uberClientId = flag.String("uberClientId", "", "Uber client_id (required)")
var uberClientSecret = flag.String("uberClientSecret", "", "Uber client_secret (required)")
var uberApiHost = flag.String("uberApi", "https://api.uber.com", "Uber API URL (no trailing slash)")
var mondoApiUrl = flag.String("mondoApi", "https://api.getmondo.co.uk", "Mondo API URL")

var indexTemplate = template.Must(template.ParseFiles("index.html"))
var pleaseWaitTemplate = template.Must(template.ParseFiles("pleasewait.html"))
var loginSuccessTemplate = template.Must(template.ParseFiles("loginsuccess.html"))

var sessions = make(map[string]*session)
var router = mux.NewRouter()
var uberApiClient *UberApiClient
var mondoApiClient *MondoApiClient

func indexGet(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	indexTemplate.Execute(w, r.Host)
}

func loginPost(w http.ResponseWriter, r *http.Request) {
	mondoAccessToken := r.FormValue("mondo-access-token")
	mondoAccountId := r.FormValue("mondo-account-id")

	if mondoAccessToken == "" || mondoAccountId == "" {
		http.Error(w, "required: mondo-access-token, mondo-account-id", http.StatusBadRequest)
		log.Printf("%s required: mondo-access-token, mondo-account-id", Login)
		return
	}

	// Register session
	uuid, err := uuid.NewV4()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s generate session id error: %s", Login, err.Error())
		return
	}

	sessionId := uuid.String()
	session := &session{
		sessionId:        sessionId,
		mondoAccessToken: mondoAccessToken,
		mondoAccountId:   mondoAccountId}

	sessions[sessionId] = session

	uberAuthorizeUrl := fmt.Sprintf("%s/oauth/authorize?response_type=code&client_id=%s&state=%s", UberAuthHost, *uberClientId, sessionId)
	log.Printf("redirecting to %s", uberAuthorizeUrl)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	data := struct{ UberAuthorizeUrl string }{UberAuthorizeUrl: uberAuthorizeUrl}
	pleaseWaitTemplate.Execute(w, data)
}

func uberSetAuthCodeGet(w http.ResponseWriter, r *http.Request) {
	sessionId := r.URL.Query()["state"][0]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	redirectUriPath, err := router.Get(SetAuthCode).URLPath()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	redirectUri := fmt.Sprintf("%s%s", *thisUrl, redirectUriPath)

	uberAuthorizationCode := r.URL.Query()["code"][0]
	uberTokenResponse, err := uberApiClient.GetOAuthToken(uberAuthorizationCode, redirectUri)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s uber oauth token error: %s", SetAuthCode, err.Error())
		return
	}

	session.uberAccessToken = uberTokenResponse.AccessToken
	log.Printf("%s assigned session id=%s Uber access_token=%s\n", SetAuthCode, sessionId, uberTokenResponse.AccessToken)

	// Register Mondo webhook
	mondoWebhookPath, err := router.Get(MondoWebhook).URLPath("sessionId", sessionId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s error: %s", SetAuthCode, err.Error())
		return
	}
	mondoWebhookUrl := fmt.Sprintf("%s%s", *thisUrl, mondoWebhookPath)
	log.Printf("%s registering mondo webhook url=%s", SetAuthCode, mondoWebhookUrl)
	mondoWebhookResponse, err := mondoApiClient.RegisterWebHook(session.mondoAccessToken, session.mondoAccountId, mondoWebhookUrl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s register mondo webhook error: %s", SetAuthCode, err.Error())
		return
	}

	session.mondoWebhookId = mondoWebhookResponse.Webhook.Id
	log.Printf("%s successfully registered mondo webhook id=%s", SetAuthCode, mondoWebhookResponse.Webhook.Id)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	loginSuccessTemplate.Execute(w, r)
}

func mondoWebhookPost(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	var request = &WebhookRequest{}
	err := json.NewDecoder(r.Body).Decode(request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		log.Printf("%s json parse error: %s", MondoWebhook, err.Error())
		return
	}

	if !strings.Contains(strings.ToUpper(request.Data.Description), "UBER") {
		fmt.Printf("%s ignored transaction: %s", request.Data.Description)
		return
	}

	vars := mux.Vars(r)
	sessionId := vars["sessionId"]
	session, exists := sessions[sessionId]
	if !exists {
		http.Error(w, fmt.Sprintf("No such session %s", sessionId), http.StatusNotFound)
		return
	}

	uberHistoryResponse, err := uberApiClient.GetHistory(session.uberAccessToken)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get history error: %s", SetAuthCode, err.Error())
		return
	}

	uberHistoryItem := uberHistoryResponse.History[0]
	requestId := uberHistoryItem.RequestId
	uberReceiptResponse, err := uberApiClient.GetReceipt(session.uberAccessToken, requestId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get receipt error: %s", SetAuthCode, err.Error())
		return
	}

	uberMapResponse, err := uberApiClient.GetMap(session.uberAccessToken, requestId)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s get map error: %s", SetAuthCode, err.Error())
		return
	}

	// Todo: look up Uber product types
	feedItemTitle := fmt.Sprintf("%s UberX %s", uberReceiptResponse.TotalCharged, uberHistoryItem.StartCity.DisplayName)

	err = mondoApiClient.CreateFeedItem(
		session.mondoAccessToken,
		session.mondoAccountId,
		"image",
		"Uber Receipt",
		uberMapResponse.Href,
		feedItemTitle)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		log.Printf("%s create feed item error: %s", SetAuthCode, err.Error())
		return
	}
}

func middleware(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s %s\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	flag.Parse()
	if *uberClientId == "" || *uberClientSecret == "" || *thisUrl == "" {
		flag.PrintDefaults()
		return
	}
	uberApiClient = &UberApiClient{
		url: *uberApiHost,
		clientSecret: *uberClientSecret,
		clientId: *uberClientId,
	}

	mondoApiClient = &MondoApiClient{url: *mondoApiUrl}

	router.HandleFunc("/", indexGet).Methods("GET").Name(Index)
	router.HandleFunc("/login", loginPost).Methods("POST").Name(Login)
	router.HandleFunc("/uber/setauthcode", uberSetAuthCodeGet).Methods("GET").Name(SetAuthCode)
	router.HandleFunc("/mondo/webhook/{sessionId}", mondoWebhookPost).Methods("POST").Name(MondoWebhook)
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))
	log.Printf("Listening on %s\n", *addr)
	if strings.Contains(*addr, "443") {
		log.Fatal(http.ListenAndServeTLS(*addr, *certFile, *keyFile, middleware(router)))
	} else {
		log.Fatal(http.ListenAndServe(*addr, middleware(router)))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
	"path/filepath"

	rat "github.com/ericfreese/rat/lib"
)

var flags struct {
	cmd  string
	mode string
}

func init() {
	flag.StringVar(&flags.cmd, "cmd", "cat ~/.config/rat/ratrc", "command to run")
	flag.StringVar(&flags.mode, "mode", "default", "name of mode")

	flag.Parse()
}

func main() {
	var err error

	if err = rat.Init(); err != nil {
		panic(err)
	}

	defer rat.Close()

	if config, err := os.Open(filepath.Join(rat.ConfigDir, "ratrc")); err == nil {
		rat.LoadConfig(config)
		config.Close()
	}

	rat.PushPager(rat.NewCmdPager(flags.mode, flags.cmd, rat.Context{}))

	rat.Run()
}
<commit_msg>Add simple version check<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"

	rat "github.com/ericfreese/rat/lib"
)

var (
	RAT_VERSION = "0.0.2"
)

var flags struct {
	cmd     string
	mode    string
	version bool
}

func init() {
	flag.StringVar(&flags.cmd, "cmd", "cat ~/.config/rat/ratrc", "command to run")
	flag.StringVar(&flags.mode, "mode", "default", "name of mode")
	flag.BoolVar(&flags.version, "version", false, "display version and exit")

	flag.Parse()
}

func main() {
	var err error

	if flags.version {
		fmt.Println(RAT_VERSION)
		return
	}

	if err = rat.Init(); err != nil {
		panic(err)
	}

	defer rat.Close()

	if config, err := os.Open(filepath.Join(rat.ConfigDir, "ratrc")); err == nil {
		rat.LoadConfig(config)
		config.Close()
	}

	rat.PushPager(rat.NewCmdPager(flags.mode, flags.cmd, rat.Context{}))

	rat.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	gorillasession "github.com/gorilla/sessions"
	"github.com/ory-am/common/env"
	"github.com/ory-am/common/mgopath"
	"github.com/ory-am/event"
	"github.com/ory-am/gitdeploy/eco"
	"github.com/ory-am/gitdeploy/ip"
	"github.com/ory-am/gitdeploy/job"
	"github.com/ory-am/gitdeploy/job/deploy"
	gdLog "github.com/ory-am/gitdeploy/log"
	"github.com/ory-am/gitdeploy/public"
	"github.com/ory-am/gitdeploy/sse"
	"github.com/ory-am/gitdeploy/storage"
	"github.com/ory-am/gitdeploy/storage/mongo"
	"github.com/ory-am/gitdeploy/task"
	"github.com/ory-am/gitdeploy/task/flynn"
	"github.com/ory-am/google-json-style-response/responder"
	"gopkg.in/mgo.v2"
	"gopkg.in/validator.v2"
	"log"
	"net/http"
	"time"
)

const (
	sessionCurrentDeployment = "cdid"
	sessionName              = "gdp"
)

var (
	ApiVersion      = "1.0"
	host            = env.Getenv("HOST", "")
	port            = env.Getenv("PORT", "7654")
	envAppTtl       = env.Getenv("APP_TTL", "30m")
	envClusterConf  = env.Getenv("FLYNN_CLUSTER_CONFIG", "")
	corsAllowOrigin = env.Getenv("CORS_ALLOW_ORIGIN", "http://localhost:9000")
	sessionStore    = gorillasession.NewCookieStore([]byte(env.Getenv("SESSION_SECRET", "changme")))
	envMongoPath    = env.Getenv("MONGODB", "mongodb://localhost:27017/gitdeploy")
)

type deployRequest struct {
	Repository string `json:"repository",validate:"regex=^(https|http):\\/\\/github\\.com\\/[a-zA-Z0-9\\-\\_\\.]+/[a-zA-Z0-9\\-\\_\\.]+$"`
	Ref        string `json:"ref",validate:"regex=^(origin\\/.*|tags\\/.*|[a-z0-9]+)$"`
}

type appResponse struct {
	App string `json:"app"`
}

func main() {
	eco.IsGitAvailable()
	eco.IsFlynnAvailable()
	init := flag.Bool("init", false, "Initialize flynn")
	flag.Parse()
	if *init {
		eco.InitFlynn(envClusterConf)
		eco.InitGit()
	}

	db, dbName, err := mgopath.Connect(envMongoPath)
	if err != nil {
		log.Fatal(err)
	}
	eventManager := event.New()
	storage := mongo.New(db, dbName)
	sseBroker := sse.New(storage)
	eventManager.AttachListenerAggregate(storage)
	eventManager.AttachListenerAggregate(new(gdLog.Listener))

	// Mux router
	r := mux.NewRouter()
	r.HandleFunc("/config", configHandler).Methods("GET")
	r.HandleFunc("/deployments", deployWrapperAction(sseBroker, eventManager, storage)).Methods("POST")
	r.HandleFunc("/deployments", setCORSHeaders).Methods("OPTIONS")
	r.HandleFunc("/deployments/{app:.+}/events", eventWrapperAction(sseBroker)).Methods("GET")
	r.HandleFunc("/apps/{app:.+}", getAppHandler(storage)).Methods("GET")
	r.PathPrefix("/").HandlerFunc(public.HTML5ModeHandler("./app/dist", "index.html"))
	http.Handle("/", r)

	go job.KillAppsOnHitList(storage)

	listen := fmt.Sprintf("%s:%s", host, port)
	log.Printf("Listening on %s", listen)
	log.Fatal(http.ListenAndServe(listen, nil))
}

func eventWrapperAction(sseBroker *sse.Broker) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setCORSHeaders(w, r)
		sseBroker.EventHandler(w, r)
	}
}

func deployWrapperAction(sseBroker *sse.Broker, em *event.EventManager, store *mongo.MongoStorage) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setCORSHeaders(w, r)
		deployAction(w, r, sseBroker, em, store)
	}
}

func configHandler(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w, r)
	responseSuccess(w, struct {
		Now time.Time `json:"now"`
	}{time.Now()})
}

func getAppHandler(store *mongo.MongoStorage) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if cleanUpSession(w, r) != nil {
			return
		}
		setCORSHeaders(w, r)
		vars := mux.Vars(r)
		id := vars["app"]
		app, err := store.GetApp(id)
		if err == mgo.ErrNotFound {
			responseError(w, http.StatusNotFound, fmt.Sprintf("App %s does not exist.", id))
			return
		} else if app.Killed {
			responseError(w, http.StatusNotFound, "App timed out and is no longer available.")
			return
		} else if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		logs, err := flynn.GetLogs(app.ID)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		ps, err := flynn.GetProcs(app.ID)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		deployLogs, err := store.FindDeployLogsForApp(id)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		responseSuccess(w, struct {
			*storage.App
			Logs       string                 `json:"logs"`
			DeployLogs []*storage.DeployEvent `json:"deployLogs,inline"`
			PS         string                 `json:"ps"`
		}{app, logs, deployLogs, ps})
	}
}

func deployAction(w http.ResponseWriter, r *http.Request, sseBroker *sse.Broker, em *event.EventManager, store *mongo.MongoStorage) {
	app := uuid.NewRandom().String()
	log.Printf("Trying to fetch session: %s", app)
	session, err := sessionStore.Get(r, sessionName)
	if err != nil {
		responseError(w, http.StatusBadRequest, "Please delete your cookies.")
		return
	}

	// Check if the user is currently deploying an application and switch to that one.
	//	if v, ok := session.Values[sessionCurrentDeployment].(string); ok && len(v) > 0 {
	//		a, err := store.GetApp(v)
	//		if err != nil {
	//			cleanUpSession(w, r)
	//			log.Printf("Could not fetch app from cookie: %s", err.Error())
	//		} else if !sseBroker.IsChannelOpen(a.ID) {
	//			cleanUpSession(w, r)
	//			log.Printf("Channel %s does not exist any more", a.ID)
	//		} else if !a.Deployed {
	//			log.Printf("Channel %s found!", a.ID)
	//			responseSuccess(w, a)
	//			return
	//		}
	//	}

	log.Printf("No deployment active for this session, starting new one: %s", app)
	dr := new(deployRequest)
	ttl, err := time.ParseDuration(envAppTtl)
	if err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	} else if err := json.NewDecoder(r.Body).Decode(dr); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	} else if err := validator.Validate(dr); err != nil {
		responseError(w, http.StatusBadRequest, fmt.Sprintf("Validation failed: %s", err))
		return
	}

	log.Printf("Validation passed: %s", app)
	if dr.Repository[len(dr.Repository)-4:] != ".git" {
		dr.Repository = dr.Repository + ".git"
	}
	if len(dr.Ref) == 0 {
		dr.Ref = "master"
	}

	log.Printf("Storing app information: %s", app)
	appEntity, err := store.AddApp(app, time.Now().Add(ttl), dr.Repository, ip.GetRemoteAddr(r), dr.Ref)
	if err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	}

	session.Values[sessionCurrentDeployment] = appEntity.ID
	if err := session.Save(r, w); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	}

	log.Printf("Responding app information: %s", app)
	responseSuccess(w, appEntity)
	go func() {
		sseBroker.OpenChannel(app)
		sseBroker.Start(app)
		defer func() {
			log.Printf("Waiting for slow clients: %s", app)
			// Give the client the chance to read the output...
			time.Sleep(5 * time.Second)
			log.Printf("Timeout for slow clients: %s", app)
			//appEntity.Deployed = true;
			//if err := store.UpdateApp(appEntity); err != nil {
			//	log.Printf("Fatal error when trying to update app %s", app)
			//}
			sseBroker.CloseChannel(app)
		}()
		log.Printf("Creating job: %s", app)
		tasks := deploy.CreateJob(store, appEntity)
		log.Printf("Run job: %s", app)
		err := task.RunJob(app, em, tasks)
		if err != nil {
			log.Printf("Error in task.RunJob: %s", err)
		}
	}()
}

func cleanUpSession(w http.ResponseWriter, r *http.Request) error {
	session, err := sessionStore.Get(r, sessionName)
	if err != nil {
		responseError(w, http.StatusBadRequest, "Please delete your cookies.")
		return err
	}
	delete(session.Values, sessionCurrentDeployment)
	if err := session.Save(r, w); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return err
	}
	return nil
}

// Set the different CORS headers required for CORS request
func setCORSHeaders(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Origin", corsAllowOrigin)
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
}

func responseError(w http.ResponseWriter, code int, message string) {
	log.Printf("Error %d: %s", code, message)
	response := responder.New(ApiVersion)
	response.Write(w, response.Error(code, message))
}

func responseSuccess(w http.ResponseWriter, data interface{}) {
	response := responder.New(ApiVersion)
	response.Write(w, response.Success(data))
}
<commit_msg>main: increased channel timeout<commit_after>package main

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	gorillasession "github.com/gorilla/sessions"
	"github.com/ory-am/common/env"
	"github.com/ory-am/common/mgopath"
	"github.com/ory-am/event"
	"github.com/ory-am/gitdeploy/eco"
	"github.com/ory-am/gitdeploy/ip"
	"github.com/ory-am/gitdeploy/job"
	"github.com/ory-am/gitdeploy/job/deploy"
	gdLog "github.com/ory-am/gitdeploy/log"
	"github.com/ory-am/gitdeploy/public"
	"github.com/ory-am/gitdeploy/sse"
	"github.com/ory-am/gitdeploy/storage"
	"github.com/ory-am/gitdeploy/storage/mongo"
	"github.com/ory-am/gitdeploy/task"
	"github.com/ory-am/gitdeploy/task/flynn"
	"github.com/ory-am/google-json-style-response/responder"
	"gopkg.in/mgo.v2"
	"gopkg.in/validator.v2"
	"log"
	"net/http"
	"time"
)

const (
	sessionCurrentDeployment = "cdid"
	sessionName              = "gdp"
)

var (
	ApiVersion      = "1.0"
	host            = env.Getenv("HOST", "")
	port            = env.Getenv("PORT", "7654")
	envAppTtl       = env.Getenv("APP_TTL", "30m")
	envClusterConf  = env.Getenv("FLYNN_CLUSTER_CONFIG", "")
	corsAllowOrigin = env.Getenv("CORS_ALLOW_ORIGIN", "http://localhost:9000")
	sessionStore    = gorillasession.NewCookieStore([]byte(env.Getenv("SESSION_SECRET", "changme")))
	envMongoPath    = env.Getenv("MONGODB", "mongodb://localhost:27017/gitdeploy")
)

type deployRequest struct {
	Repository string `json:"repository",validate:"regex=^(https|http):\\/\\/github\\.com\\/[a-zA-Z0-9\\-\\_\\.]+/[a-zA-Z0-9\\-\\_\\.]+$"`
	Ref        string `json:"ref",validate:"regex=^(origin\\/.*|tags\\/.*|[a-z0-9]+)$"`
}

type appResponse struct {
	App string `json:"app"`
}

func main() {
	eco.IsGitAvailable()
	eco.IsFlynnAvailable()
	init := flag.Bool("init", false, "Initialize flynn")
	flag.Parse()
	if *init {
		eco.InitFlynn(envClusterConf)
		eco.InitGit()
	}

	db, dbName, err := mgopath.Connect(envMongoPath)
	if err != nil {
		log.Fatal(err)
	}
	eventManager := event.New()
	storage := mongo.New(db, dbName)
	sseBroker := sse.New(storage)
	eventManager.AttachListenerAggregate(storage)
	eventManager.AttachListenerAggregate(new(gdLog.Listener))

	// Mux router
	r := mux.NewRouter()
	r.HandleFunc("/config", configHandler).Methods("GET")
	r.HandleFunc("/deployments", deployWrapperAction(sseBroker, eventManager, storage)).Methods("POST")
	r.HandleFunc("/deployments", setCORSHeaders).Methods("OPTIONS")
	r.HandleFunc("/deployments/{app:.+}/events", eventWrapperAction(sseBroker)).Methods("GET")
	r.HandleFunc("/apps/{app:.+}", getAppHandler(storage)).Methods("GET")
	r.PathPrefix("/").HandlerFunc(public.HTML5ModeHandler("./app/dist", "index.html"))
	http.Handle("/", r)

	go job.KillAppsOnHitList(storage)

	listen := fmt.Sprintf("%s:%s", host, port)
	log.Printf("Listening on %s", listen)
	log.Fatal(http.ListenAndServe(listen, nil))
}

func eventWrapperAction(sseBroker *sse.Broker) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setCORSHeaders(w, r)
		sseBroker.EventHandler(w, r)
	}
}

func deployWrapperAction(sseBroker *sse.Broker, em *event.EventManager, store *mongo.MongoStorage) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setCORSHeaders(w, r)
		deployAction(w, r, sseBroker, em, store)
	}
}

func configHandler(w http.ResponseWriter, r *http.Request) {
	setCORSHeaders(w, r)
	responseSuccess(w, struct {
		Now time.Time `json:"now"`
	}{time.Now()})
}

func getAppHandler(store *mongo.MongoStorage) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if cleanUpSession(w, r) != nil {
			return
		}
		setCORSHeaders(w, r)
		vars := mux.Vars(r)
		id := vars["app"]
		app, err := store.GetApp(id)
		if err == mgo.ErrNotFound {
			responseError(w, http.StatusNotFound, fmt.Sprintf("App %s does not exist.", id))
			return
		} else if app.Killed {
			responseError(w, http.StatusNotFound, "App timed out and is no longer available.")
			return
		} else if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		logs, err := flynn.GetLogs(app.ID)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		ps, err := flynn.GetProcs(app.ID)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		deployLogs, err := store.FindDeployLogsForApp(id)
		if err != nil {
			responseError(w, http.StatusInternalServerError, err.Error())
			return
		}

		responseSuccess(w, struct {
			*storage.App
			Logs       string                 `json:"logs"`
			DeployLogs []*storage.DeployEvent `json:"deployLogs,inline"`
			PS         string                 `json:"ps"`
		}{app, logs, deployLogs, ps})
	}
}

func deployAction(w http.ResponseWriter, r *http.Request, sseBroker *sse.Broker, em *event.EventManager, store *mongo.MongoStorage) {
	app := uuid.NewRandom().String()
	log.Printf("Trying to fetch session: %s", app)
	session, err := sessionStore.Get(r, sessionName)
	if err != nil {
		responseError(w, http.StatusBadRequest, "Please delete your cookies.")
		return
	}

	// Check if the user is currently deploying an application and switch to that one.
	//	if v, ok := session.Values[sessionCurrentDeployment].(string); ok && len(v) > 0 {
	//		a, err := store.GetApp(v)
	//		if err != nil {
	//			cleanUpSession(w, r)
	//			log.Printf("Could not fetch app from cookie: %s", err.Error())
	//		} else if !sseBroker.IsChannelOpen(a.ID) {
	//			cleanUpSession(w, r)
	//			log.Printf("Channel %s does not exist any more", a.ID)
	//		} else if !a.Deployed {
	//			log.Printf("Channel %s found!", a.ID)
	//			responseSuccess(w, a)
	//			return
	//		}
	//	}

	log.Printf("No deployment active for this session, starting new one: %s", app)
	dr := new(deployRequest)
	ttl, err := time.ParseDuration(envAppTtl)
	if err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	} else if err := json.NewDecoder(r.Body).Decode(dr); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	} else if err := validator.Validate(dr); err != nil {
		responseError(w, http.StatusBadRequest, fmt.Sprintf("Validation failed: %s", err))
		return
	}

	log.Printf("Validation passed: %s", app)
	if dr.Repository[len(dr.Repository)-4:] != ".git" {
		dr.Repository = dr.Repository + ".git"
	}
	if len(dr.Ref) == 0 {
		dr.Ref = "master"
	}

	log.Printf("Storing app information: %s", app)
	appEntity, err := store.AddApp(app, time.Now().Add(ttl), dr.Repository, ip.GetRemoteAddr(r), dr.Ref)
	if err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	}

	session.Values[sessionCurrentDeployment] = appEntity.ID
	if err := session.Save(r, w); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return
	}

	log.Printf("Responding app information: %s", app)
	responseSuccess(w, appEntity)
	go func() {
		sseBroker.OpenChannel(app)
		sseBroker.Start(app)
		defer func() {
			log.Printf("Waiting for slow clients: %s", app)
			// Give the client the chance to read the output...
			time.Sleep(10 * time.Second)
			log.Printf("Timeout for slow clients: %s", app)
			//appEntity.Deployed = true;
			//if err := store.UpdateApp(appEntity); err != nil {
			//	log.Printf("Fatal error when trying to update app %s", app)
			//}
			sseBroker.CloseChannel(app)
		}()
		log.Printf("Creating job: %s", app)
		tasks := deploy.CreateJob(store, appEntity)
		log.Printf("Run job: %s", app)
		err := task.RunJob(app, em, tasks)
		if err != nil {
			log.Printf("Error in task.RunJob: %s", err)
		}
	}()
}

func cleanUpSession(w http.ResponseWriter, r *http.Request) error {
	session, err := sessionStore.Get(r, sessionName)
	if err != nil {
		responseError(w, http.StatusBadRequest, "Please delete your cookies.")
		return err
	}
	delete(session.Values, sessionCurrentDeployment)
	if err := session.Save(r, w); err != nil {
		responseError(w, http.StatusInternalServerError, err.Error())
		return err
	}
	return nil
}

// Set the different CORS headers required for CORS request
func setCORSHeaders(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
	w.Header().Set("Access-Control-Allow-Origin", corsAllowOrigin)
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
}

func responseError(w http.ResponseWriter, code int, message string) {
	log.Printf("Error %d: %s", code, message)
	response := responder.New(ApiVersion)
	response.Write(w, response.Error(code, message))
}

func responseSuccess(w http.ResponseWriter, data interface{}) {
	response := responder.New(ApiVersion)
	response.Write(w, response.Success(data))
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"github.com/bitmark-inc/exitwithstatus"
	"github.com/bitmark-inc/bitmark-mgmt/api"
	"github.com/bitmark-inc/bitmark-mgmt/configuration"
	"github.com/bitmark-inc/bitmark-mgmt/fault"
	"github.com/bitmark-inc/bitmark-mgmt/templates"
	"github.com/bitmark-inc/bitmark-mgmt/utils"
	"github.com/codegangsta/cli"
	"golang.org/x/crypto/bcrypt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"text/template"
	"time"
)

var GlobalConfig *configuration.Configuration
var BitmarkMgmtConfigFile string

func main() {
	// ensure exit handler is first
	defer exitwithstatus.Handler()

	var configDir string

	app := cli.NewApp()
	app.Name = "bitmark-mgmt"
	app.Usage = "Configuration program for bitmarkd"
	app.Version = Version()
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "config, c",
			Value:       "",
			Usage:       "*bitmark-mgmt config file",
			Destination: &configDir,
		},
	}
	app.Commands = []cli.Command{
		{
			Name:  "setup",
			Usage: "Initialise bitmark-mgmt configuration",
			Action: func(c *cli.Context) {
				runSetup(c, configDir)
			},
		},
		{
			Name:  "start",
			Usage: "start bitmark-mgmt",
			Action: func(c *cli.Context) {
				runStart(c, configDir)
			},
		},
	}
	app.Run(os.Args)

}

func runSetup(c *cli.Context, configDir string) {

	configDir, err := utils.CheckConfigDir(configDir)
	fmt.Println("configDir", configDir)

	if nil != err {
		exitwithstatus.Message("Error: %s\n", err)
	}

	if !utils.EnsureFileExists(configDir) {
		if err := os.MkdirAll(configDir, 0755); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}
	}

	configFile, err := configuration.GetConfigPath(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	}

	// Check if file exist
	if !utils.EnsureFileExists(configFile) {
		file, err := os.Create(configFile)
		if nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}

		encryptPassword, err := bcrypt.GenerateFromPassword([]byte("bitmark-mgmt"), bcrypt.DefaultCost)
		if nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}

		configData := configuration.Configuration{
			Port:              2150,
			Password:          string(encryptPassword),
			EnableHttps:       true,
			BitmarkConfigFile: "/etc/bitmarkd.conf",
		}

		confTemp := template.Must(template.New("config").Parse(templates.ConfigurationTemplate))
		if err := confTemp.Execute(file, configData); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}
	} else {
		exitwithstatus.Message("Error: %s existed\n", configFile)
	}

}

func runStart(c *cli.Context, configDir string) {

	configDir, err := utils.CheckConfigDir(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %s\n", err)
	}

	configFile, err := configuration.GetConfigPath(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	}
	BitmarkMgmtConfigFile = configFile

	// read bitmark-mgmt config file
	if configs, err := configuration.GetConfiguration(configFile); nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	} else {
		GlobalConfig = configs
		if err := startWebServer(GlobalConfig); err != nil {
			exitwithstatus.Message("Error: %v\n", err)
		}

	}
}

func startWebServer(configs *configuration.Configuration) error {
	fmt.Println("bitmark-mgmt web start...")

	host := "127.0.0.1"
	port := strconv.Itoa(configs.Port)

	// set up webpages config.js
	if err := setupWebpagesConfig(host, port, configs.EnableHttps); nil != err {
		return err
	}

	// serve web pages
	http.Handle("/lib/", http.StripPrefix("/lib/", http.FileServer(http.Dir("./webpages/lib/"))))
	http.Handle("/scripts/", http.StripPrefix("/scripts/", http.FileServer(http.Dir("./webpages/scripts/"))))
	http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("./webpages/images/"))))
	http.Handle("/styles/", http.StripPrefix("/styles/", http.FileServer(http.Dir("./webpages/styles/"))))
	http.Handle("/", http.FileServer(http.Dir("./webpages/")))

	// serve api
	http.HandleFunc("/api/config", handleConfig)
	http.HandleFunc("/api/password", handleSetPassword)
	http.HandleFunc("/api/login", handleLogin)
	http.HandleFunc("/api/logout", handleLogout)
	http.HandleFunc("/api/bitmarkd", handleBitmarkd)

	server := &http.Server{
		Addr:           host + ":" + port,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	if configs.EnableHttps {
		// TODO: gen certs
		cert, key, newCreate, err := utils.GetTLSCertFile()
		if nil != err {
			return err
		}

		if newCreate {
			if err := utils.MakeSelfSignedCertificate("bitmark-mgmt", cert, key, false, nil); nil != err {
				return err
			}
		}

		if err := server.ListenAndServeTLS(cert, key); nil != err {
			log.Fatal(err)
			return err
		}
	} else {
		if err := server.ListenAndServe(); nil != err {
			log.Fatal(err)
			return err
		}
	}

	return nil
}

type webPagesConfigType struct {
	Host        string
	Port        string
	EnableHttps bool
}

func setupWebpagesConfig(host string, port string, enableHttps bool) error {
	configFile := "./webpages/scripts/config.js"
	if !utils.EnsureFileExists(configFile) {
		if _, err := os.Create(configFile); nil != err {
			return err
		}
	}

	webPagesConfig := &webPagesConfigType{
		Host:        host,
		Port:        port,
		EnableHttps: enableHttps,
	}
	configTemp := template.Must(template.New("config").Parse(templates.WebpagesConfigTemplate))
	configBuffer := new(bytes.Buffer)
	if err := configTemp.Execute(configBuffer, webPagesConfig); nil != err {
		return err
	}
	if err := ioutil.WriteFile(configFile, []byte(configBuffer.String()), 0644); nil != err {
		return err
	}
	return nil
}

func checkAuthorization(w http.ResponseWriter, req *http.Request, writeHeader bool) bool {
	if GlobalConfig.EnableHttps {
		if err := api.GetAndCheckCookie(w, req); nil != err {
			fmt.Printf("Error: %v\n", err)
			if writeHeader {
				w.WriteHeader(http.StatusUnauthorized)
			}
			return false
		}
	}

	return true
}

func handleConfig(w http.ResponseWriter, req *http.Request) {

	api.SetCORSHeader(w, req)

	switch req.Method {
	case `GET`: // list bitmark config
		if !checkAuthorization(w, req, true) {
			return
		}
		api.ListConfig(w, req, GlobalConfig.BitmarkConfigFile)
	case `POST`:
		if !checkAuthorization(w, req, true) {
			return
		}
		api.UpdateConfig(w, req, GlobalConfig.BitmarkConfigFile)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleSetPassword(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		if !utils.EnsureFileExists(BitmarkMgmtConfigFile) {
			exitwithstatus.Message("Error: %s\n", fault.ErrNotFoundConfigFile)
		}
		if configs, err := configuration.GetConfiguration(BitmarkMgmtConfigFile); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		} else {
			GlobalConfig = configs
			api.SetBitmarkMgmtPassword(w, req, BitmarkMgmtConfigFile, GlobalConfig.Password)
		}
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleLogin(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	switch req.Method {
	case `GET`:
		if !checkAuthorization(w, req, true) {
			return
		}
		api.LoginStatus(w)
	case `POST`:
		if GlobalConfig.EnableHttps && checkAuthorization(w, req, false) {
			if err := api.WriteGlobalErrorResponse(w, fault.ApiErrAlreadyLoggedIn); nil != err {
				fmt.Printf("Error: %v\n", err)
			}
			return
		}
		api.LoginBitmarkMgmt(w, req, GlobalConfig.Password)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleLogout(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		api.LogoutBitmarkMgmt(w)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleBitmarkd(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		api.Bitmarkd(w, req, GlobalConfig.BitmarkConfigFile)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}
<commit_msg>make mgmt listen host<commit_after>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"github.com/bitmark-inc/exitwithstatus"
	"github.com/bitmark-inc/bitmark-mgmt/api"
	"github.com/bitmark-inc/bitmark-mgmt/configuration"
	"github.com/bitmark-inc/bitmark-mgmt/fault"
	"github.com/bitmark-inc/bitmark-mgmt/templates"
	"github.com/bitmark-inc/bitmark-mgmt/utils"
	"github.com/codegangsta/cli"
	"golang.org/x/crypto/bcrypt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"text/template"
	"time"
)

var GlobalConfig *configuration.Configuration
var BitmarkMgmtConfigFile string

func main() {
	// ensure exit handler is first
	defer exitwithstatus.Handler()

	var configDir string

	app := cli.NewApp()
	app.Name = "bitmark-mgmt"
	app.Usage = "Configuration program for bitmarkd"
	app.Version = Version()
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "config, c",
			Value:       "",
			Usage:       "*bitmark-mgmt config file",
			Destination: &configDir,
		},
	}
	app.Commands = []cli.Command{
		{
			Name:  "setup",
			Usage: "Initialise bitmark-mgmt configuration",
			Action: func(c *cli.Context) {
				runSetup(c, configDir)
			},
		},
		{
			Name:  "start",
			Usage: "start bitmark-mgmt",
			Action: func(c *cli.Context) {
				runStart(c, configDir)
			},
		},
	}
	app.Run(os.Args)

}

func runSetup(c *cli.Context, configDir string) {

	configDir, err := utils.CheckConfigDir(configDir)
	fmt.Println("configDir", configDir)

	if nil != err {
		exitwithstatus.Message("Error: %s\n", err)
	}

	if !utils.EnsureFileExists(configDir) {
		if err := os.MkdirAll(configDir, 0755); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}
	}

	configFile, err := configuration.GetConfigPath(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	}

	// Check if file exist
	if !utils.EnsureFileExists(configFile) {
		file, err := os.Create(configFile)
		if nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}

		encryptPassword, err := bcrypt.GenerateFromPassword([]byte("bitmark-mgmt"), bcrypt.DefaultCost)
		if nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}

		configData := configuration.Configuration{
			Port:              2150,
			Password:          string(encryptPassword),
			EnableHttps:       true,
			BitmarkConfigFile: "/etc/bitmarkd.conf",
		}

		confTemp := template.Must(template.New("config").Parse(templates.ConfigurationTemplate))
		if err := confTemp.Execute(file, configData); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		}
	} else {
		exitwithstatus.Message("Error: %s existed\n", configFile)
	}

}

func runStart(c *cli.Context, configDir string) {

	configDir, err := utils.CheckConfigDir(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %s\n", err)
	}

	configFile, err := configuration.GetConfigPath(configDir)
	if nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	}
	BitmarkMgmtConfigFile = configFile

	// read bitmark-mgmt config file
	if configs, err := configuration.GetConfiguration(configFile); nil != err {
		exitwithstatus.Message("Error: %v\n", err)
	} else {
		GlobalConfig = configs
		if err := startWebServer(GlobalConfig); err != nil {
			exitwithstatus.Message("Error: %v\n", err)
		}

	}
}

func startWebServer(configs *configuration.Configuration) error {
	fmt.Println("bitmark-mgmt web start...")

	host := "0.0.0.0"
	port := strconv.Itoa(configs.Port)

	// set up webpages config.js
	if err := setupWebpagesConfig(host, port, configs.EnableHttps); nil != err {
		return err
	}

	// serve web pages
	http.Handle("/lib/", http.StripPrefix("/lib/", http.FileServer(http.Dir("./webpages/lib/"))))
	http.Handle("/scripts/", http.StripPrefix("/scripts/", http.FileServer(http.Dir("./webpages/scripts/"))))
	http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("./webpages/images/"))))
	http.Handle("/styles/", http.StripPrefix("/styles/", http.FileServer(http.Dir("./webpages/styles/"))))
	http.Handle("/", http.FileServer(http.Dir("./webpages/")))

	// serve api
	http.HandleFunc("/api/config", handleConfig)
	http.HandleFunc("/api/password", handleSetPassword)
	http.HandleFunc("/api/login", handleLogin)
	http.HandleFunc("/api/logout", handleLogout)
	http.HandleFunc("/api/bitmarkd", handleBitmarkd)

	server := &http.Server{
		Addr:           host + ":" + port,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	if configs.EnableHttps {
		// TODO: gen certs
		cert, key, newCreate, err := utils.GetTLSCertFile()
		if nil != err {
			return err
		}

		if newCreate {
			if err := utils.MakeSelfSignedCertificate("bitmark-mgmt", cert, key, false, nil); nil != err {
				return err
			}
		}

		if err := server.ListenAndServeTLS(cert, key); nil != err {
			log.Fatal(err)
			return err
		}
	} else {
		if err := server.ListenAndServe(); nil != err {
			log.Fatal(err)
			return err
		}
	}

	return nil
}

type webPagesConfigType struct {
	Host        string
	Port        string
	EnableHttps bool
}

func setupWebpagesConfig(host string, port string, enableHttps bool) error {
	configFile := "./webpages/scripts/config.js"
	if !utils.EnsureFileExists(configFile) {
		if _, err := os.Create(configFile); nil != err {
			return err
		}
	}

	webPagesConfig := &webPagesConfigType{
		Host:        host,
		Port:        port,
		EnableHttps: enableHttps,
	}
	configTemp := template.Must(template.New("config").Parse(templates.WebpagesConfigTemplate))
	configBuffer := new(bytes.Buffer)
	if err := configTemp.Execute(configBuffer, webPagesConfig); nil != err {
		return err
	}
	if err := ioutil.WriteFile(configFile, []byte(configBuffer.String()), 0644); nil != err {
		return err
	}
	return nil
}

func checkAuthorization(w http.ResponseWriter, req *http.Request, writeHeader bool) bool {
	if GlobalConfig.EnableHttps {
		if err := api.GetAndCheckCookie(w, req); nil != err {
			fmt.Printf("Error: %v\n", err)
			if writeHeader {
				w.WriteHeader(http.StatusUnauthorized)
			}
			return false
		}
	}

	return true
}

func handleConfig(w http.ResponseWriter, req *http.Request) {

	api.SetCORSHeader(w, req)

	switch req.Method {
	case `GET`: // list bitmark config
		if !checkAuthorization(w, req, true) {
			return
		}
		api.ListConfig(w, req, GlobalConfig.BitmarkConfigFile)
	case `POST`:
		if !checkAuthorization(w, req, true) {
			return
		}
		api.UpdateConfig(w, req, GlobalConfig.BitmarkConfigFile)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleSetPassword(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		if !utils.EnsureFileExists(BitmarkMgmtConfigFile) {
			exitwithstatus.Message("Error: %s\n", fault.ErrNotFoundConfigFile)
		}
		if configs, err := configuration.GetConfiguration(BitmarkMgmtConfigFile); nil != err {
			exitwithstatus.Message("Error: %v\n", err)
		} else {
			GlobalConfig = configs
			api.SetBitmarkMgmtPassword(w, req, BitmarkMgmtConfigFile, GlobalConfig.Password)
		}
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleLogin(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	switch req.Method {
	case `GET`:
		if !checkAuthorization(w, req, true) {
			return
		}
		api.LoginStatus(w)
	case `POST`:
		if GlobalConfig.EnableHttps && checkAuthorization(w, req, false) {
			if err := api.WriteGlobalErrorResponse(w, fault.ApiErrAlreadyLoggedIn); nil != err {
				fmt.Printf("Error: %v\n", err)
			}
			return
		}
		api.LoginBitmarkMgmt(w, req, GlobalConfig.Password)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleLogout(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		api.LogoutBitmarkMgmt(w)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}

func handleBitmarkd(w http.ResponseWriter, req *http.Request) {
	api.SetCORSHeader(w, req)

	if req.Method == "OPTIONS" || !checkAuthorization(w, req, true) {
		return
	}

	switch req.Method {
	case `POST`:
		api.Bitmarkd(w, req, GlobalConfig.BitmarkConfigFile)
	case `OPTIONS`:
		return
	default:
		fmt.Println("Error: Unknow method")
	}
}
<|endoftext|>