<commit_before>package main

import (
	"errors"
	"flag"
	"github.com/golang/glog"
	"github.com/gorilla/handlers"
	leader_election "github.com/samitpal/consul-client-master-election/election_api"
	"github.com/samitpal/goProbe/conf"
	"github.com/samitpal/goProbe/log"
	"github.com/samitpal/goProbe/metric_export"
	"github.com/samitpal/goProbe/misc"
	"github.com/samitpal/goProbe/modules"
	"io/ioutil"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"os"
	"time"
)

var (
	listenAddress     = flag.String("listen-address", ":8080", "Address to listen on for web interface.")
	configFlag        = flag.String("config", "./probe_config.json", "Path to the probe json config.")
	probeSpaceOutTime = flag.Int("probe_space_out_time", 15, "Max sleep time between probes to allow spacing out of the probes at startup.")
	expositionType    = flag.String("exposition_type", "json", "Metric exposition format.")
	dryRun            = flag.Bool("dry_run", false, "Dry run mode where it does everything except running the probes.")
	metricsPath       = flag.String("metric_path", "/metrics", "Metric exposition path.")
	webLogDir         = flag.String("weblog_dir", "", "Directory path of the web log.")
	haMode            = flag.Bool("ha_mode", false, "Whether to use consul for High Availabity mode.")
)

func setupMetricExporter(s string) (metric_export.MetricExporter, error) {
	var mExp metric_export.MetricExporter
	if s == "prometheus" {
		mExp = metric_export.NewPrometheusExport()
	} else if s == "json" {
		mExp = metric_export.NewJSONExport()
	} else {
		return nil, errors.New("Unknown metric exporter, %s.")
	}
	mExp.Prepare()
	return mExp, nil
}

// runProbes actually runs the probes. This is the core.
func runProbes(probes []modules.Prober, mExp metric_export.MetricExporter, ps *misc.ProbesStatus, stopCh chan bool) {
	for _, p := range probes {
		// Add some randomness to space out the probes a bit at start up.
		r := rand.New(rand.NewSource(time.Now().UnixNano()))
		time.Sleep(time.Duration(r.Intn(*probeSpaceOutTime)) * time.Second)
		go func(p modules.Prober) {
			for {
				// Buffered channel so that the read happens even if there is nothing to receive it. Needed to
				// handle the timeout scenario as well as the situaion when the go routine has to return on stop
				// signal.
				respCh := make(chan *modules.ProbeData, 1)
				errCh := make(chan error, 1)

				pn := *p.Name()
				to := *p.TimeoutSecs()
				timer := time.NewTimer(time.Duration(*p.RunIntervalSecs()) * time.Second)

				glog.Infof("Launching new probe:%s", pn)
				startTime := time.Now().UnixNano()
				startTimeSecs := startTime / 1000000000 // used to expose time field in json metric expostion.
				go p.Run(respCh, errCh)

				select {
				case msg := <-respCh:
					err := misc.CheckProbeData(msg)
					mExp.IncProbeCount(pn, startTimeSecs)
					if err != nil {
						glog.Errorf("Error: %v", err)
						mExp.IncProbeErrorCount(pn, startTimeSecs)
						mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
						ps.WriteProbeErrorStatus(pn, startTime, time.Now().UnixNano())
					} else {
						mExp.SetFieldValues(pn, msg, startTimeSecs)
						ps.WriteProbeStatus(pn, msg, startTime, time.Now().UnixNano())
					}
				case err_msg := <-errCh:
					glog.Errorf("Probe %s error'ed out: %v", pn, err_msg)
					mExp.IncProbeCount(pn, startTimeSecs)
					mExp.IncProbeErrorCount(pn, startTimeSecs)
					mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
					ps.WriteProbeErrorStatus(pn, startTime, time.Now().UnixNano())
				case <-time.After(time.Duration(to) * time.Second):
					glog.Errorf("Timed out probe:%v ", pn)
					mExp.IncProbeCount(pn, startTimeSecs)
					mExp.IncProbeTimeoutCount(pn, startTimeSecs)
					mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
					ps.WriteProbeTimeoutStatus(pn, startTime, time.Now().UnixNano())
				case <-stopCh:
					glog.Info("Goroutine recieved stop signal. Returning.")
					return
				}
				<-timer.C
			}
		}(p)
	}
}

func main() {

	flag.Parse()
	config, err := ioutil.ReadFile(*configFlag)
	if err != nil {
		glog.Exitf("Error reading config file: %v", err)
	}
	probes, err := conf.SetupConfig(config)
	if err != nil {
		glog.Exitf("Error in config setup, exiting: %v", err)
	}
	err = misc.CheckProbeConfig(probes)
	if err != nil {
		glog.Exitf("Error in probe config, exiting: %v", err)
	}

	probeNames := conf.GetProbeNames(probes)
	mExp, err := setupMetricExporter(*expositionType)
	if err != nil {
		glog.Exitf("Error : %v", err)
	}

	var fh *os.File
	if *webLogDir != "" {
		fh, err = log.SetupWebLog(*webLogDir, time.Now())
		if err != nil {
			glog.Exitf("Failed to set up logging", err)
		}
	} else {
		fh = os.Stdout // logs web accesses to stdout. May not be thread safe.
	}

	ps := misc.NewProbesStatus(probeNames)
	http.Handle("/", handlers.CombinedLoggingHandler(fh, http.HandlerFunc(misc.HandleHomePage)))
	http.Handle("/status", handlers.CombinedLoggingHandler(fh, misc.HandleStatus(ps)))
	http.Handle("/config", handlers.CombinedLoggingHandler(fh, http.HandlerFunc(misc.HandleConfig(config))))
	http.Handle(*metricsPath, handlers.CombinedLoggingHandler(fh, mExp.MetricHttpHandler()))

	glog.Info("Starting goProbe server.")
	glog.Infof("Will expose metrics in %s format via %s http path.", *expositionType, *metricsPath)
	glog.Infof("/config shows current config, /status shows current probe status.")

	if !*dryRun {
		// Start probing.
		stopCh := make(chan bool)
		if *haMode {
			glog.Info("Running in HA mode..")
			client, err := getConsulClient()
			if err != nil {
				glog.Fatalf("Fatal error: %v", err)
			}
			job := NewDoJob(probes, mExp, ps)
			go leader_election.MaybeAcquireLeadership(client, "goProbe/leader", 20, 30, "goProbe", false, job)
		} else {
			go runProbes(probes, mExp, ps, stopCh)
		}
		if err = http.ListenAndServe(*listenAddress, nil); err != nil {
			panic(err)
		}
	} else {
		glog.Info("Dry run mode.")
	}
}
<commit_msg>When recieving the stop signal, print the go rotuine name that is returning.<commit_after>package main

import (
	"errors"
	"flag"
	"github.com/golang/glog"
	"github.com/gorilla/handlers"
	leader_election "github.com/samitpal/consul-client-master-election/election_api"
	"github.com/samitpal/goProbe/conf"
	"github.com/samitpal/goProbe/log"
	"github.com/samitpal/goProbe/metric_export"
	"github.com/samitpal/goProbe/misc"
	"github.com/samitpal/goProbe/modules"
	"io/ioutil"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"os"
	"time"
)

var (
	listenAddress     = flag.String("listen-address", ":8080", "Address to listen on for web interface.")
	configFlag        = flag.String("config", "./probe_config.json", "Path to the probe json config.")
	probeSpaceOutTime = flag.Int("probe_space_out_time", 15, "Max sleep time between probes to allow spacing out of the probes at startup.")
	expositionType    = flag.String("exposition_type", "json", "Metric exposition format.")
	dryRun            = flag.Bool("dry_run", false, "Dry run mode where it does everything except running the probes.")
	metricsPath       = flag.String("metric_path", "/metrics", "Metric exposition path.")
	webLogDir         = flag.String("weblog_dir", "", "Directory path of the web log.")
	haMode            = flag.Bool("ha_mode", false, "Whether to use consul for High Availabity mode.")
)

func setupMetricExporter(s string) (metric_export.MetricExporter, error) {
	var mExp metric_export.MetricExporter
	if s == "prometheus" {
		mExp = metric_export.NewPrometheusExport()
	} else if s == "json" {
		mExp = metric_export.NewJSONExport()
	} else {
		return nil, errors.New("Unknown metric exporter, %s.")
	}
	mExp.Prepare()
	return mExp, nil
}

// runProbes actually runs the probes. This is the core.
func runProbes(probes []modules.Prober, mExp metric_export.MetricExporter, ps *misc.ProbesStatus, stopCh chan bool) {
	for _, p := range probes {
		// Add some randomness to space out the probes a bit at start up.
		r := rand.New(rand.NewSource(time.Now().UnixNano()))
		time.Sleep(time.Duration(r.Intn(*probeSpaceOutTime)) * time.Second)
		go func(p modules.Prober) {
			for {
				// Buffered channel so that the read happens even if there is nothing to receive it. Needed to
				// handle the timeout scenario as well as the situaion when the go routine has to return on stop
				// signal.
				respCh := make(chan *modules.ProbeData, 1)
				errCh := make(chan error, 1)

				pn := *p.Name()
				to := *p.TimeoutSecs()
				timer := time.NewTimer(time.Duration(*p.RunIntervalSecs()) * time.Second)

				glog.Infof("Launching new probe:%s", pn)
				startTime := time.Now().UnixNano()
				startTimeSecs := startTime / 1000000000 // used to expose time field in json metric expostion.
				go p.Run(respCh, errCh)

				select {
				case msg := <-respCh:
					err := misc.CheckProbeData(msg)
					mExp.IncProbeCount(pn, startTimeSecs)
					if err != nil {
						glog.Errorf("Error: %v", err)
						mExp.IncProbeErrorCount(pn, startTimeSecs)
						mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
						ps.WriteProbeErrorStatus(pn, startTime, time.Now().UnixNano())
					} else {
						mExp.SetFieldValues(pn, msg, startTimeSecs)
						ps.WriteProbeStatus(pn, msg, startTime, time.Now().UnixNano())
					}
				case err_msg := <-errCh:
					glog.Errorf("Probe %s error'ed out: %v", pn, err_msg)
					mExp.IncProbeCount(pn, startTimeSecs)
					mExp.IncProbeErrorCount(pn, startTimeSecs)
					mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
					ps.WriteProbeErrorStatus(pn, startTime, time.Now().UnixNano())
				case <-time.After(time.Duration(to) * time.Second):
					glog.Errorf("Timed out probe:%v ", pn)
					mExp.IncProbeCount(pn, startTimeSecs)
					mExp.IncProbeTimeoutCount(pn, startTimeSecs)
					mExp.SetFieldValuesUnexpected(pn, startTimeSecs)
					ps.WriteProbeTimeoutStatus(pn, startTime, time.Now().UnixNano())
				case <-stopCh:
					glog.Infof("Goroutine probe named: %s recieved stop signal. Returning.", pn)
					return
				}
				<-timer.C
			}
		}(p)
	}
}

func main() {

	flag.Parse()
	config, err := ioutil.ReadFile(*configFlag)
	if err != nil {
		glog.Exitf("Error reading config file: %v", err)
	}
	probes, err := conf.SetupConfig(config)
	if err != nil {
		glog.Exitf("Error in config setup, exiting: %v", err)
	}
	err = misc.CheckProbeConfig(probes)
	if err != nil {
		glog.Exitf("Error in probe config, exiting: %v", err)
	}

	probeNames := conf.GetProbeNames(probes)
	mExp, err := setupMetricExporter(*expositionType)
	if err != nil {
		glog.Exitf("Error : %v", err)
	}

	var fh *os.File
	if *webLogDir != "" {
		fh, err = log.SetupWebLog(*webLogDir, time.Now())
		if err != nil {
			glog.Exitf("Failed to set up logging", err)
		}
	} else {
		fh = os.Stdout // logs web accesses to stdout. May not be thread safe.
	}

	ps := misc.NewProbesStatus(probeNames)
	http.Handle("/", handlers.CombinedLoggingHandler(fh, http.HandlerFunc(misc.HandleHomePage)))
	http.Handle("/status", handlers.CombinedLoggingHandler(fh, misc.HandleStatus(ps)))
	http.Handle("/config", handlers.CombinedLoggingHandler(fh, http.HandlerFunc(misc.HandleConfig(config))))
	http.Handle(*metricsPath, handlers.CombinedLoggingHandler(fh, mExp.MetricHttpHandler()))

	glog.Info("Starting goProbe server.")
	glog.Infof("Will expose metrics in %s format via %s http path.", *expositionType, *metricsPath)
	glog.Infof("/config shows current config, /status shows current probe status.")

	if !*dryRun {
		// Start probing.
		stopCh := make(chan bool)
		if *haMode {
			glog.Info("Running in HA mode..")
			client, err := getConsulClient()
			if err != nil {
				glog.Fatalf("Fatal error: %v", err)
			}
			job := NewDoJob(probes, mExp, ps)
			go leader_election.MaybeAcquireLeadership(client, "goProbe/leader", 20, 30, "goProbe", false, job)
		} else {
			go runProbes(probes, mExp, ps, stopCh)
		}
		if err = http.ListenAndServe(*listenAddress, nil); err != nil {
			panic(err)
		}
	} else {
		glog.Info("Dry run mode.")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/mjibson/moggio/server"

	// codecs
	_ "github.com/mjibson/moggio/codec/flac"
	_ "github.com/mjibson/moggio/codec/gme"
	_ "github.com/mjibson/moggio/codec/mpa"
	_ "github.com/mjibson/moggio/codec/nsf"
	_ "github.com/mjibson/moggio/codec/rar"
	_ "github.com/mjibson/moggio/codec/vorbis"
	_ "github.com/mjibson/moggio/codec/wav"

	// protocols
	// _ "github.com/mjibson/moggio/protocol/bandcamp"

	_ "github.com/mjibson/moggio/protocol/file"
	_ "github.com/mjibson/moggio/protocol/stream"
)

var (
	flagAddr  = flag.String("addr", ":6601", "listen address")
	flagDev   = flag.Bool("dev", false, "enable dev mode")
	stateFile = flag.String("state", "", "specify non-default statefile location")
)

func main() {
	flag.Parse()
	http.DefaultClient = &http.Client{
		Transport: &httpcontrol.Transport{
			ResponseHeaderTimeout: time.Second * 3,
			MaxTries:              3,
			RetryAfterTimeout:     true,
		},
	}
	redir := *flagAddr
	if strings.HasPrefix(redir, ":") {
		redir = "localhost" + redir
	}
	redir = "http://" + redir + "/api/oauth/"
	if *stateFile == "" {
		switch {
		case *flagDev:
			*stateFile = "moggio.state"
		case runtime.GOOS == "windows":
			dir := filepath.Join(os.Getenv("APPDATA"), "moggio")
			if err := os.MkdirAll(dir, 0600); err != nil {
				log.Fatal(err)
			}
			*stateFile = filepath.Join(dir, "moggio.state")
		default:
			*stateFile = filepath.Join(os.Getenv("HOME"), ".moggio.state")
		}
	}
	log.Fatal(server.ListenAndServe(*stateFile, *flagAddr, *flagDev))
}

//go:generate browserify -t [ reactify --es6 ] server/static/src/nav.js -o server/static/js/moggio.js
<commit_msg>remove some old server thing<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/mjibson/moggio/server"

	// codecs
	_ "github.com/mjibson/moggio/codec/flac"
	_ "github.com/mjibson/moggio/codec/gme"
	_ "github.com/mjibson/moggio/codec/mpa"
	_ "github.com/mjibson/moggio/codec/nsf"
	_ "github.com/mjibson/moggio/codec/rar"
	_ "github.com/mjibson/moggio/codec/vorbis"
	_ "github.com/mjibson/moggio/codec/wav"

	// protocols
	// _ "github.com/mjibson/moggio/protocol/bandcamp"

	_ "github.com/mjibson/moggio/protocol/file"
	_ "github.com/mjibson/moggio/protocol/stream"
)

var (
	flagAddr  = flag.String("addr", ":6601", "listen address")
	flagDev   = flag.Bool("dev", false, "enable dev mode")
	stateFile = flag.String("state", "", "specify non-default statefile location")
)

func main() {
	flag.Parse()
	http.DefaultClient = &http.Client{
		Transport: &httpcontrol.Transport{
			ResponseHeaderTimeout: time.Second * 3,
			MaxTries:              3,
			RetryAfterTimeout:     true,
		},
	}
	if *stateFile == "" {
		switch {
		case *flagDev:
			*stateFile = "moggio.state"
		case runtime.GOOS == "windows":
			dir := filepath.Join(os.Getenv("APPDATA"), "moggio")
			if err := os.MkdirAll(dir, 0600); err != nil {
				log.Fatal(err)
			}
			*stateFile = filepath.Join(dir, "moggio.state")
		default:
			*stateFile = filepath.Join(os.Getenv("HOME"), ".moggio.state")
		}
	}
	log.Fatal(server.ListenAndServe(*stateFile, *flagAddr, *flagDev))
}

//go:generate browserify -t [ reactify --es6 ] server/static/src/nav.js -o server/static/js/moggio.js
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// cputime runs its arguments as a command, then prints CPU usage information
// to stderr. It is like the shell builtin 'time' command, except with stable
// formatting that includes a total across user and system CPU time.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"syscall"
	"time"
)

func formatBytes(count int64) string {
	switch {
	case count < 1<<10:
		return fmt.Sprintf("%d bytes", count)

	case count < 1<<20:
		return fmt.Sprintf("%.2f KiB", float64(count)/(1<<10))

	case count < 1<<30:
		return fmt.Sprintf("%.2f MiB", float64(count)/(1<<20))

	default:
		fallthrough

	case count < 1<<40:
		return fmt.Sprintf("%.2f GiB", float64(count)/(1<<30))
	}
}

func main() {
	// Set up flags.
	flag.Usage = func() {
		fmt.Fprintf(
			os.Stderr,
			"Usage: %s [flags...] command [args...]\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}

	flag.Parse()

	// Check usage.
	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	// Run the command.
	args := flag.Args()

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	start := time.Now()
	err := cmd.Run()
	duration := time.Since(start)
	if err != nil {
		log.Fatalf("Run: %v", err)
		return
	}

	// Print usage info.
	rusage := cmd.ProcessState.SysUsage().(*syscall.Rusage)
	user := time.Duration(rusage.Utime.Nano()) * time.Nanosecond
	sys := time.Duration(rusage.Stime.Nano()) * time.Nanosecond

	fmt.Fprintf(
		os.Stderr,
		"\n"+
			"Max RSS:   %v\n"+
			"Wall time: %v\n"+
			"\n"+
			"User  CPU: %v\n"+
			"Sys   CPU: %v\n"+
			"Total CPU: %v\n",
		formatBytes(rusage.Maxrss*1024),
		duration,
		user,
		sys,
		user+sys)
}
<commit_msg>Include a banner in the output.<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// cputime runs its arguments as a command, then prints CPU usage information
// to stderr. It is like the shell builtin 'time' command, except with stable
// formatting that includes a total across user and system CPU time.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"syscall"
	"time"
)

func formatBytes(count int64) string {
	switch {
	case count < 1<<10:
		return fmt.Sprintf("%d bytes", count)

	case count < 1<<20:
		return fmt.Sprintf("%.2f KiB", float64(count)/(1<<10))

	case count < 1<<30:
		return fmt.Sprintf("%.2f MiB", float64(count)/(1<<20))

	default:
		fallthrough

	case count < 1<<40:
		return fmt.Sprintf("%.2f GiB", float64(count)/(1<<30))
	}
}

func main() {
	// Set up flags.
	flag.Usage = func() {
		fmt.Fprintf(
			os.Stderr,
			"Usage: %s [flags...] command [args...]\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintf(os.Stderr, "Flags:\n")
		flag.PrintDefaults()
	}

	flag.Parse()

	// Check usage.
	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(1)
	}

	// Run the command.
	args := flag.Args()

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	start := time.Now()
	err := cmd.Run()
	duration := time.Since(start)
	if err != nil {
		log.Fatalf("Run: %v", err)
		return
	}

	// Print usage info.
	rusage := cmd.ProcessState.SysUsage().(*syscall.Rusage)
	user := time.Duration(rusage.Utime.Nano()) * time.Nanosecond
	sys := time.Duration(rusage.Stime.Nano()) * time.Nanosecond

	fmt.Fprintf(
		os.Stderr,
		"\n"+
			"----------\n"+
			"Max RSS:   %v\n"+
			"Wall time: %v\n"+
			"\n"+
			"User  CPU: %v\n"+
			"Sys   CPU: %v\n"+
			"Total CPU: %v\n",
		formatBytes(rusage.Maxrss*1024),
		duration,
		user,
		sys,
		user+sys)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.tools/go/types"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
)

var (
	universe string
	own      string
)

func init() {
	flag.StringVar(&universe, "universe", "std", "Comma-separated list of Which packages to scan for interfaces. Defaults to std.")
	flag.StringVar(&own, "own", "", "Comma-separated list of packages whose types to check for implemented interfaces.")

	flag.Parse()
}

type Interface struct {
	Name       string
	Underlying *types.Interface
	Obj        types.Object
}

// getInterfaces extracts all the interfaces from the objects we
// parsed.
func getInterfaces(typs []types.Object) []Interface {
	var interfaces []Interface

	for _, obj := range typs {
		// Only types, not variables/constants
		if v, ok := obj.(*types.TypeName); ok {
			// Only interfaces
			if iface, ok := v.Type().Underlying().(*types.Interface); ok {
				interfaces = append(interfaces, Interface{obj.Name(), iface, obj})
			}
		}

	}

	return interfaces
}

func parseFile(fset *token.FileSet, fileName string) (f *ast.File, err error) {
	astFile, err := parser.ParseFile(fset, fileName, nil, 0)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	return astFile, nil
}

type Context struct {
	allImports map[string]*types.Package
	context    types.Context
}

func NewContext() *Context {
	ctx := &Context{
		allImports: make(map[string]*types.Package),
	}

	ctx.context = types.Context{
		Import: ctx.importer,
	}

	return ctx
}

func (ctx *Context) importer(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
	// types.Importer does not seem to be designed for recursive
	// parsing like we're doing here. Specifically, each nested import
	// will maintain its own imports map. This will lead to duplicate
	// imports and in turn packages, which will lead to funny errors
	// such as "cannot pass argument ip (variable of type net.IP) to
	// variable of type net.IP"
	//
	// To work around this, we keep a global imports map, allImports,
	// to which we add all nested imports, and which we use as the
	// cache, instead of imports.
	//
	// Since all nested imports will also use this importer, there
	// should be no way to end up with duplicate imports.

	// We first try to use GcImport directly. This has the downside of
	// using possibly out-of-date packages, but it has the upside of
	// not having to parse most of the Go standard library.

	buildPkg, buildErr := build.Import(path, ".", 0)
	// If we found no build dir, assume we're dealing with installed
	// but no source. If we found a build dir, only use GcImport if
	// it's in GOROOT. This way we always use up-to-date code for
	// normal packages but avoid parsing the standard library.
	if (buildErr == nil && buildPkg.Goroot) || buildErr != nil {
		pkg, err = types.GcImport(ctx.allImports, path)
		if err == nil {
			// We don't use imports, but per API we have to add the package.
			imports[pkg.Path()] = pkg
			ctx.allImports[pkg.Path()] = pkg
			return pkg, nil
		}
	}

	// See if we already imported this package
	if pkg = ctx.allImports[path]; pkg != nil && pkg.Complete() {
		return pkg, nil
	}

	// allImports failed, try to use go/build
	if buildErr != nil {
		return nil, buildErr
	}

	// TODO check if the .a file is up to date and use it instead
	fmt.Println("we have to build", path, "ourselves")
	fileSet := token.NewFileSet()

	isGoFile := func(d os.FileInfo) bool {
		allFiles := make([]string, 0, len(buildPkg.GoFiles)+len(buildPkg.CgoFiles))
		allFiles = append(allFiles, buildPkg.GoFiles...)
		allFiles = append(allFiles, buildPkg.CgoFiles...)

		for _, file := range allFiles {
			if file == d.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, isGoFile, 0)
	if err != nil {
		return nil, err
	}

	delete(pkgs, "documentation")
	var astPkg *ast.Package
	var name string
	for name, astPkg = range pkgs {
		// Use the first non-main package, or the only package we
		// found.
		//
		// NOTE(dh) I can't think of a reason why there should be
		// multiple packages in a single directory, but ParseDir
		// accommodates for that possibility.
		if len(pkgs) == 1 || name != "main" {
			break
		}
	}

	if astPkg == nil {
		return nil, fmt.Errorf("can't find import: %s", name)
	}

	var ff []*ast.File
	for _, f := range astPkg.Files {
		ff = append(ff, f)
	}

	context := types.Context{
		Import: ctx.importer,
	}

	pkg, err = context.Check(name, fileSet, ff...)
	if err != nil {
		return pkg, err
	}
	if !pkg.Complete() {
		pkg = types.NewPackage(pkg.Pos(), pkg.Path(), pkg.Name(), pkg.Scope(), pkg.Imports(), true)
	}

	imports[path] = pkg
	ctx.allImports[path] = pkg
	return pkg, nil
}

func (ctx *Context) getTypes(paths ...string) []types.Object {
	var typs []types.Object

	for _, path := range paths {
		buildPkg, err := build.Import(path, ".", 0)
		if err != nil {
			// FIXME better error handling
			fmt.Printf("Couldn't import %s: %s\n", path, err)
			continue
		}
		fset := token.NewFileSet()
		var astFiles []*ast.File
		var pkg *types.Package
		if buildPkg.Goroot {
			// TODO what if the compiled package in GoRoot is
			// outdated?
			fmt.Println("GcImport", path)
			pkg, err = types.GcImport(ctx.allImports, path)
			if err != nil {
				// TODO better error handling
				fmt.Printf("Couldn't import %s: %s\n", path, err)
				continue
			}
		} else {
			fmt.Println("Manual parsing", path)
			if len(buildPkg.GoFiles) == 0 {
				// TODO proper error handling
				fmt.Printf("Couldn't parse %s: No go files\n", path)
				continue
			}
			for _, file := range buildPkg.GoFiles {
				astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file))
				if err != nil {
					// TODO proper error handling
					fmt.Printf("Couldn't parse %s: %s", err)
					continue
				}
				astFiles = append(astFiles, astFile)
			}

			pkg, err = check(ctx, astFiles[0].Name.Name, fset, astFiles)
			if err != nil {
				// FIXME better error handling
				fmt.Printf("Couldn't parse %s: %s\n", path, err)
				continue
			}
			fmt.Println(pkg.Name(), pkg.Complete())
		}

		scope := pkg.Scope()
		for i := 0; i < scope.NumEntries(); i++ {
			obj := scope.At(i)

			// Only types, not variables/constants
			if _, ok := obj.(*types.TypeName); ok {
				typs = append(typs, obj)
			}

		}
	}
	return typs
}

func check(ctx *Context, name string, fset *token.FileSet, astFiles []*ast.File) (pkg *types.Package, err error) {
	return ctx.context.Check(name, fset, astFiles...)
}

func main() {
	if own == "" {
		flag.Usage()
		os.Exit(1)
	}

	ctx := NewContext()
	stdlib := ctx.getTypes(matchPackages(universe)...)
	toCheck := ctx.getTypes(matchPackages(own)...)

	interfaces := getInterfaces(stdlib)

	for _, typ := range toCheck {
		for _, iface := range interfaces {
			if iface.Underlying.NumMethods() == 0 {
				continue
			}

			if typ.Name() == iface.Name {
				continue
			}

			if fnc, _ := types.MissingMethod(typ.Type(), iface.Underlying); fnc == nil {
				fmt.Printf("%s.%s implements %s.%s\n",
					typ.(*types.TypeName).Pkg().Name(), typ.Name(),
					iface.Obj.Pkg().Name(), iface.Name)
			}
		}
	}
}
<commit_msg>fix filtering of interface == interface<commit_after>package main

import (
	"code.google.com/p/go.tools/go/types"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
)

var (
	universe string
	own      string
)

func init() {
	flag.StringVar(&universe, "universe", "std", "Comma-separated list of Which packages to scan for interfaces. Defaults to std.")
	flag.StringVar(&own, "own", "", "Comma-separated list of packages whose types to check for implemented interfaces.")

	flag.Parse()
}

type Interface struct {
	Name       string
	Underlying *types.Interface
	Obj        types.Object
}

// getInterfaces extracts all the interfaces from the objects we
// parsed.
func getInterfaces(typs []types.Object) []Interface {
	var interfaces []Interface

	for _, obj := range typs {
		// Only types, not variables/constants
		if v, ok := obj.(*types.TypeName); ok {
			// Only interfaces
			if iface, ok := v.Type().Underlying().(*types.Interface); ok {
				interfaces = append(interfaces, Interface{obj.Name(), iface, obj})
			}
		}

	}

	return interfaces
}

func parseFile(fset *token.FileSet, fileName string) (f *ast.File, err error) {
	astFile, err := parser.ParseFile(fset, fileName, nil, 0)
	if err != nil {
		return f, fmt.Errorf("could not parse: %s", err)
	}

	return astFile, nil
}

type Context struct {
	allImports map[string]*types.Package
	context    types.Context
}

func NewContext() *Context {
	ctx := &Context{
		allImports: make(map[string]*types.Package),
	}

	ctx.context = types.Context{
		Import: ctx.importer,
	}

	return ctx
}

func (ctx *Context) importer(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
	// types.Importer does not seem to be designed for recursive
	// parsing like we're doing here. Specifically, each nested import
	// will maintain its own imports map. This will lead to duplicate
	// imports and in turn packages, which will lead to funny errors
	// such as "cannot pass argument ip (variable of type net.IP) to
	// variable of type net.IP"
	//
	// To work around this, we keep a global imports map, allImports,
	// to which we add all nested imports, and which we use as the
	// cache, instead of imports.
	//
	// Since all nested imports will also use this importer, there
	// should be no way to end up with duplicate imports.

	// We first try to use GcImport directly. This has the downside of
	// using possibly out-of-date packages, but it has the upside of
	// not having to parse most of the Go standard library.

	buildPkg, buildErr := build.Import(path, ".", 0)
	// If we found no build dir, assume we're dealing with installed
	// but no source. If we found a build dir, only use GcImport if
	// it's in GOROOT. This way we always use up-to-date code for
	// normal packages but avoid parsing the standard library.
	if (buildErr == nil && buildPkg.Goroot) || buildErr != nil {
		pkg, err = types.GcImport(ctx.allImports, path)
		if err == nil {
			// We don't use imports, but per API we have to add the package.
			imports[pkg.Path()] = pkg
			ctx.allImports[pkg.Path()] = pkg
			return pkg, nil
		}
	}

	// See if we already imported this package
	if pkg = ctx.allImports[path]; pkg != nil && pkg.Complete() {
		return pkg, nil
	}

	// allImports failed, try to use go/build
	if buildErr != nil {
		return nil, buildErr
	}

	// TODO check if the .a file is up to date and use it instead
	fmt.Println("we have to build", path, "ourselves")
	fileSet := token.NewFileSet()

	isGoFile := func(d os.FileInfo) bool {
		allFiles := make([]string, 0, len(buildPkg.GoFiles)+len(buildPkg.CgoFiles))
		allFiles = append(allFiles, buildPkg.GoFiles...)
		allFiles = append(allFiles, buildPkg.CgoFiles...)

		for _, file := range allFiles {
			if file == d.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, isGoFile, 0)
	if err != nil {
		return nil, err
	}

	delete(pkgs, "documentation")
	var astPkg *ast.Package
	var name string
	for name, astPkg = range pkgs {
		// Use the first non-main package, or the only package we
		// found.
		//
		// NOTE(dh) I can't think of a reason why there should be
		// multiple packages in a single directory, but ParseDir
		// accommodates for that possibility.
		if len(pkgs) == 1 || name != "main" {
			break
		}
	}

	if astPkg == nil {
		return nil, fmt.Errorf("can't find import: %s", name)
	}

	var ff []*ast.File
	for _, f := range astPkg.Files {
		ff = append(ff, f)
	}

	context := types.Context{
		Import: ctx.importer,
	}

	pkg, err = context.Check(name, fileSet, ff...)
	if err != nil {
		return pkg, err
	}
	if !pkg.Complete() {
		pkg = types.NewPackage(pkg.Pos(), pkg.Path(), pkg.Name(), pkg.Scope(), pkg.Imports(), true)
	}

	imports[path] = pkg
	ctx.allImports[path] = pkg
	return pkg, nil
}

func (ctx *Context) getTypes(paths ...string) []types.Object {
	var typs []types.Object

	for _, path := range paths {
		buildPkg, err := build.Import(path, ".", 0)
		if err != nil {
			// FIXME better error handling
			fmt.Printf("Couldn't import %s: %s\n", path, err)
			continue
		}
		fset := token.NewFileSet()
		var astFiles []*ast.File
		var pkg *types.Package
		if buildPkg.Goroot {
			// TODO what if the compiled package in GoRoot is
			// outdated?
			fmt.Println("GcImport", path)
			pkg, err = types.GcImport(ctx.allImports, path)
			if err != nil {
				// TODO better error handling
				fmt.Printf("Couldn't import %s: %s\n", path, err)
				continue
			}
		} else {
			fmt.Println("Manual parsing", path)
			if len(buildPkg.GoFiles) == 0 {
				// TODO proper error handling
				fmt.Printf("Couldn't parse %s: No go files\n", path)
				continue
			}
			for _, file := range buildPkg.GoFiles {
				astFile, err := parseFile(fset, filepath.Join(buildPkg.Dir, file))
				if err != nil {
					// TODO proper error handling
					fmt.Printf("Couldn't parse %s: %s", err)
					continue
				}
				astFiles = append(astFiles, astFile)
			}

			pkg, err = check(ctx, astFiles[0].Name.Name, fset, astFiles)
			if err != nil {
				// FIXME better error handling
				fmt.Printf("Couldn't parse %s: %s\n", path, err)
				continue
			}
			fmt.Println(pkg.Name(), pkg.Complete())
		}

		scope := pkg.Scope()
		for i := 0; i < scope.NumEntries(); i++ {
			obj := scope.At(i)

			// Only types, not variables/constants
			if _, ok := obj.(*types.TypeName); ok {
				typs = append(typs, obj)
			}

		}
	}
	return typs
}

func check(ctx *Context, name string, fset *token.FileSet, astFiles []*ast.File) (pkg *types.Package, err error) {
	return ctx.context.Check(name, fset, astFiles...)
}

func main() {
	if own == "" {
		flag.Usage()
		os.Exit(1)
	}

	ctx := NewContext()
	stdlib := ctx.getTypes(matchPackages(universe)...)
	toCheck := ctx.getTypes(matchPackages(own)...)

	interfaces := getInterfaces(stdlib)

	for _, typ := range toCheck {
		for _, iface := range interfaces {
			if iface.Underlying.NumMethods() == 0 {
				continue
			}

			if typ.Object.Pkg() == iface.Obj.Pkg() && typ.Object.Name() == iface.Name {
				// An interface will always implement itself, so skip those
				continue
			}

			if fnc, _ := types.MissingMethod(typ.Type(), iface.Underlying); fnc == nil {
				fmt.Printf("%s.%s implements %s.%s\n",
					typ.(*types.TypeName).Pkg().Name(), typ.Name(),
					iface.Obj.Pkg().Name(), iface.Name)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"net/http/cgi"
	"net/http/fcgi"
	"os"
	"os/exec"
	"os/signal"
	"strings"
)

var (
	socketPath  = flag.String("socketpath", "/var/run/gobalt.socket", "path to listening socket")
	socketUser  = flag.String("socketuser", "www-data", "owner for socket")
	socketGroup = flag.String("socketgroup", "www-data", "owner for socket")
)

type Handler struct {
}

func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	log.Println(req.URL.String())
	url := req.URL
	path := url.Path

	slice := strings.Split(path, "/")
	filepath := strings.Join(slice[4:], "/")
	// We either execute "sh -c something" (when not root),
	// or "su -c something" (when root).
	cgipath := "sh"
	user, ok := req.Header["Cobalt-User"]
	if !ok {
		user = []string{"databox"}
	}
	// If path begins with /http, then serve a listing.
	if strings.HasSuffix(path, "/") && slice[3] == "http" {
		prefix := strings.Join(slice[:4], "/")
		root := http.Dir("/ebs/home/" + user[0] + "/http/")

		staticHandler := http.StripPrefix(prefix, http.FileServer(root))
		staticHandler.ServeHTTP(rw, req)
		return
	}
	// This setup prevents shell injection.
	// Try first /home/cgi-bin, then /home/tool/cgi-bin
	code := `
		if [ -x /home/cgi-bin/"$1" ]; then
			cd /home/cgi-bin && /home/cgi-bin/"$1"
		else
			cd /home/tool/cgi-bin && /home/tool/cgi-bin/"$1"
		fi
	`
	cgiargs := []string{"-c", code, user[0], "--", "-", filepath}
	if os.Getuid() == 0 {
		cgipath = "su"
	}
	var err error
	cgipath, err = exec.LookPath(cgipath)
	if err != nil {
		log.Panic(err)
	}
	log.Print(cgipath, cgiargs)
	// on Dir: In the usual case where we're su'ing into a
	// box, setting Dir has no effect because the PAM
	// chroot module changes the current directory
	// (to be / in the box's chrooted environment).
	// on $HOME: The cgi module only sets certain
	// environment variables, and leaves HOME unset.
	// We set the directory within the command.
	handler := &cgi.Handler{
		Path: cgipath,
		Args: cgiargs,
		Env: []string{
			"SCRIPT_NAME=" + path,
			"SCRIPT_FILENAME=" + "/home/cgi-bin/" + filepath,
			"SERVER_SOFTWARE=github.com/scraperwiki/gobalt",
		}}
	handler.ServeHTTP(rw, req)
}

func main() {
	flag.Parse()
	_ = os.Remove(*socketPath)
	l, err := net.Listen("unix", *socketPath)
	if err != nil {
		log.Panic(err)
	}
	defer l.Close()
	err = exec.Command("chown", *socketUser+":"+*socketGroup, *socketPath).Run()
	if err != nil {
		log.Panic(err)
	}
	handler := &Handler{}
	log.Println("Serving on", *socketPath)

	go func() {
		err = fcgi.Serve(l, handler)
		if err != nil {
			log.Panic(err)
		}
	}()

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	<-sig
}
<commit_msg>Show 404 if cgi script isn't executable<commit_after>package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"net/http/cgi"
	"net/http/fcgi"
	"os"
	"os/exec"
	"os/signal"
	"strings"
)

var (
	socketPath  = flag.String("socketpath", "/var/run/gobalt.socket", "path to listening socket")
	socketUser  = flag.String("socketuser", "www-data", "owner for socket")
	socketGroup = flag.String("socketgroup", "www-data", "owner for socket")
)

type Handler struct {
}

func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	log.Println(req.URL.String())
	url := req.URL
	path := url.Path

	slice := strings.Split(path, "/")
	filepath := strings.Join(slice[4:], "/")
	// We either execute "sh -c something" (when not root),
	// or "su -c something" (when root).
	cgipath := "sh"
	user, ok := req.Header["Cobalt-User"]
	if !ok {
		user = []string{"databox"}
	}
	// If path begins with /http, then serve a listing.
	if strings.HasSuffix(path, "/") && slice[3] == "http" {
		prefix := strings.Join(slice[:4], "/")
		root := http.Dir("/ebs/home/" + user[0] + "/http/")

		staticHandler := http.StripPrefix(prefix, http.FileServer(root))
		staticHandler.ServeHTTP(rw, req)
		return
	}
	// This setup prevents shell injection.
	// Try first /home/cgi-bin, then /home/tool/cgi-bin
	code := `
		if [ -x /home/cgi-bin/"$1" ]; then
			cd /home/cgi-bin && /home/cgi-bin/"$1"
		elif [ -x /home/tool/cgi-bin/"$1" ]; then
			cd /home/tool/cgi-bin && /home/tool/cgi-bin/"$1"
		else
			echo Status: 404 Not Found
		fi
	`
	cgiargs := []string{"-c", code, user[0], "--", "-", filepath}
	if os.Getuid() == 0 {
		cgipath = "su"
	}
	var err error
	cgipath, err = exec.LookPath(cgipath)
	if err != nil {
		log.Panic(err)
	}
	// on Dir: In the usual case where we're su'ing into a
	// box, setting Dir has no effect because the PAM
	// chroot module changes the current directory
	// (to be / in the box's chrooted environment).
	// on $HOME: The cgi module only sets certain
	// environment variables, and leaves HOME unset.
	// We set the directory within the command.
	handler := &cgi.Handler{
		Path: cgipath,
		Args: cgiargs,
		Env: []string{
			"SCRIPT_NAME=" + path,
			"SCRIPT_FILENAME=" + "/home/cgi-bin/" + filepath,
			"SERVER_SOFTWARE=github.com/scraperwiki/gobalt",
		}}
	handler.ServeHTTP(rw, req)
}

func main() {
	flag.Parse()
	_ = os.Remove(*socketPath)
	l, err := net.Listen("unix", *socketPath)
	if err != nil {
		log.Panic(err)
	}
	defer l.Close()
	err = exec.Command("chown", *socketUser+":"+*socketGroup, *socketPath).Run()
	if err != nil {
		log.Panic(err)
	}
	handler := &Handler{}
	log.Println("Serving on", *socketPath)

	go func() {
		err = fcgi.Serve(l, handler)
		if err != nil {
			log.Panic(err)
		}
	}()

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	<-sig
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// http://api.openweathermap.org/data/2.5/weather?q=Melbourne,au

func main() {

	http.HandleFunc("/", weatherHandler)

	http.ListenAndServe(":5000", nil)

}

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

	body, err := getWeatherResponseBody()

	if err != nil {
		panic(err)
	}

	melbourne := City{}

	err = json.Unmarshal(body, &melbourne)

	fmt.Fprintf(w, "The weather in %v is %v", melbourne.Name, melbourne.Weather.NormalisedCurrentTemp())

}

func getWeatherResponseBody() ([]byte, error) {

	resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?q=Melbourne,au")

	if err != nil {
		fmt.Printf("Error getting weather: %v", err)
		return []byte(""), err
	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Printf("Error reading weather: %v", err)
		return []byte(""), err
	}

	defer resp.Body.Close()

	return body, nil

}

type City struct {
	Weather Weather `json:"main"`
	Name    string  `json:"name"`
}

type Weather struct {
	CurrentTemp float64 `json:"temp"`
	MaxTemp     float64 `json:"mtepm_max"`
}

func (w Weather) NormalisedCurrentTemp() float64 {
	return w.CurrentTemp - 273.15
}
<commit_msg>handle unmarshal error<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// http://api.openweathermap.org/data/2.5/weather?q=Melbourne,au

func main() {

	http.HandleFunc("/", weatherHandler)

	http.ListenAndServe(":5000", nil)

}

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

	body, err := getWeatherResponseBody()

	if err != nil {
		panic(err)
	}

	melbourne := City{}

	err = json.Unmarshal(body, &melbourne)
	if err != nil {
		panic(err)
	}

	fmt.Fprintf(w, "The weather in %v is %v", melbourne.Name, melbourne.Weather.NormalisedCurrentTemp())

}

func getWeatherResponseBody() ([]byte, error) {

	resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?q=Melbourne,au")

	if err != nil {
		fmt.Printf("Error getting weather: %v", err)
		return []byte(""), err
	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Printf("Error reading weather: %v", err)
		return []byte(""), err
	}

	defer resp.Body.Close()

	return body, nil

}

type City struct {
	Weather Weather `json:"main"`
	Name    string  `json:"name"`
}

type Weather struct {
	CurrentTemp float64 `json:"temp"`
	MaxTemp     float64 `json:"mtepm_max"`
}

func (w Weather) NormalisedCurrentTemp() float64 {
	return w.CurrentTemp - 273.15
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"net/http"

	"github.com/teambrookie/movierss/dao"
	"github.com/teambrookie/movierss/handlers"
	"github.com/teambrookie/movierss/torrent"
	"github.com/teambrookie/movierss/trakt"
)

func worker(jobs <-chan dao.Movie, store dao.MovieStore) {
	for movie := range jobs {
		time.Sleep(2 * time.Second)
		log.Println("Processing : " + movie.Title)
		torrentLink, err := torrent.Search(movie.Ids.Imdb)
		log.Println("Result : " + torrentLink)
		if err != nil {
			log.Printf("Error processing %s : %s ...\n", movie.Title, err)
			continue
		}
		if torrentLink == "" {
			continue
		}
		movie.MagnetLink = torrentLink
		movie.LastModified = time.Now()
		err = store.UpdateMovie(movie)
		if err != nil {
			log.Printf("Error saving %s to DB ...\n", movie.Title)
		}
	}
}

func main() {
	var httpAddr = flag.String("http", "0.0.0.0:8000", "HTTP service address")
	var dbAddr = flag.String("db", "movierss.db", "DB address")
	flag.Parse()

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

	movieProvider := trakt.Trakt{APIKey: traktAPIKey}

	log.Println("Starting server ...")
	log.Printf("HTTP service listening on %s", *httpAddr)
	log.Println("Connecting to db ...")

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

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

	//Worker stuff
	log.Println("Starting worker ...")
	jobs := make(chan dao.Movie, 100)
	go worker(jobs, store)

	errChan := make(chan error, 10)

	mux := http.NewServeMux()
	mux.HandleFunc("/", handlers.HelloHandler)
	mux.Handle("/movies", handlers.MovieHandler(store))
	mux.Handle("/refresh", handlers.RefreshHandler(store, movieProvider, jobs))
	mux.Handle("/rss", handlers.RSSHandler(store, movieProvider))

	httpServer := http.Server{}
	httpServer.Addr = *httpAddr
	httpServer.Handler = handlers.LoggingHandler(mux)

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

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

	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Fatal(err)
			}
		case s := <-signalChan:
			log.Println(fmt.Sprintf("Captured %v. Exiting...", s))
			httpServer.Shutdown(context.Background())
			os.Exit(0)
		}
	}
}
<commit_msg>remove a magic number because i can<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"net/http"

	"github.com/teambrookie/movierss/dao"
	"github.com/teambrookie/movierss/handlers"
	"github.com/teambrookie/movierss/torrent"
	"github.com/teambrookie/movierss/trakt"
)

const apiRateLimit = 2

func worker(jobs <-chan dao.Movie, store dao.MovieStore) {
	for movie := range jobs {
		time.Sleep(apiRateLimit * time.Second)
		log.Println("Processing : " + movie.Title)
		torrentLink, err := torrent.Search(movie.Ids.Imdb)
		log.Println("Result : " + torrentLink)
		if err != nil {
			log.Printf("Error processing %s : %s ...\n", movie.Title, err)
			continue
		}
		if torrentLink == "" {
			continue
		}
		movie.MagnetLink = torrentLink
		movie.LastModified = time.Now()
		err = store.UpdateMovie(movie)
		if err != nil {
			log.Printf("Error saving %s to DB ...\n", movie.Title)
		}
	}
}

func main() {
	var httpAddr = flag.String("http", "0.0.0.0:8000", "HTTP service address")
	var dbAddr = flag.String("db", "movierss.db", "DB address")
	flag.Parse()

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

	movieProvider := trakt.Trakt{APIKey: traktAPIKey}

	log.Println("Starting server ...")
	log.Printf("HTTP service listening on %s", *httpAddr)
	log.Println("Connecting to db ...")

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

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

	//Worker stuff
	log.Println("Starting worker ...")
	jobs := make(chan dao.Movie, 100)
	go worker(jobs, store)

	errChan := make(chan error, 10)

	mux := http.NewServeMux()
	mux.HandleFunc("/", handlers.HelloHandler)
	mux.Handle("/movies", handlers.MovieHandler(store))
	mux.Handle("/refresh", handlers.RefreshHandler(store, movieProvider, jobs))
	mux.Handle("/rss", handlers.RSSHandler(store, movieProvider))

	httpServer := http.Server{}
	httpServer.Addr = *httpAddr
	httpServer.Handler = handlers.LoggingHandler(mux)

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

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

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


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/christophwitzko/github-release-download/release"
	"github.com/julienschmidt/httprouter"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

var bindAddress string = ":5000"
var client *release.GithubClient

func init() {
	if ba := os.Getenv("BIND_ADDRESS"); ba != "" {
		bindAddress = ba
	}
	client = release.NewClient(os.Getenv("GITHUB_TOKEN"))
}

func logger(router http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s - %s %s", r.RemoteAddr, r.Method, r.URL.EscapedPath())
		router.ServeHTTP(w, r)
	})
}

func doRedirect(w http.ResponseWriter, r *http.Request, url string, err error) {
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	if url == "" {
		http.NotFound(w, r)
		return
	}
	http.Redirect(w, r, url, 302)
}

func getLatestDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	url, err := client.GetLatestDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value)
	doRedirect(w, r, url, err)
}

func getMatchingDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	url, err := client.GetMatchingDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value, ps[4].Value)
	doRedirect(w, r, url, err)
}

func getVersions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if ps[0].Value == "_" && ps[1].Value == "go" {
		versions, err := client.GetGoVersions(ctx)
		if err != nil {
			log.Println(err)
			http.Error(w, "server error", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(versions)
		return
	}
	http.NotFound(w, r)
}

func usage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if ps[0].Value != "_usage" {
		http.NotFound(w, r)
		return
	}
	rl, _, err := client.Client.RateLimits(r.Context())
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(rl.Core)
}

func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintln(w, "https://get-release.xyz/:owner/:repo/:os/:arch{/:constraint}")
}

func main() {
	router := httprouter.New()
	router.GET("/", index)
	router.GET("/:owner", usage)
	router.GET("/:owner/:repo", getVersions)
	router.GET("/:owner/:repo/:os/:arch", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch/:constraint", getMatchingDownload)
	server := http.Server{
		Addr:    bindAddress,
		Handler: logger(router),
	}
	go func() {
		log.Printf("starting server on port %s...", bindAddress)
		if err := server.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()
	defer server.Shutdown(nil)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
	log.Println("server stopped")
}
<commit_msg>feat: add support for smart download urls<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/christophwitzko/github-release-download/release"
	"github.com/julienschmidt/httprouter"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

var bindAddress string = ":5000"
var client *release.GithubClient

func init() {
	if ba := os.Getenv("BIND_ADDRESS"); ba != "" {
		bindAddress = ba
	}
	client = release.NewClient(os.Getenv("GITHUB_TOKEN"))
}

func logger(router http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%s - %s %s", r.RemoteAddr, r.Method, r.URL.EscapedPath())
		router.ServeHTTP(w, r)
	})
}

func doRedirect(w http.ResponseWriter, r *http.Request, url string, err error) {
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	if url == "" {
		http.NotFound(w, r)
		return
	}
	http.Redirect(w, r, url, 302)
}

func getLatestDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if len(ps) == 3 {
		proj := "go-" + ps[0].Value
		url, err := client.GetLatestDownloadUrl(ctx, proj, proj, ps[1].Value, ps[2].Value)
		doRedirect(w, r, url, err)
		return
	}
	url, err := client.GetLatestDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value)
	doRedirect(w, r, url, err)
}

func getMatchingDownload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	url, err := client.GetMatchingDownloadUrl(ctx, ps[0].Value, ps[1].Value, ps[2].Value, ps[3].Value, ps[4].Value)
	doRedirect(w, r, url, err)
}

func getVersions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()
	if ps[0].Value == "_" && ps[1].Value == "go" {
		versions, err := client.GetGoVersions(ctx)
		if err != nil {
			log.Println(err)
			http.Error(w, "server error", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(versions)
		return
	}
	http.NotFound(w, r)
}

func usage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	if ps[0].Value != "_usage" {
		http.NotFound(w, r)
		return
	}
	rl, _, err := client.Client.RateLimits(r.Context())
	if err != nil {
		log.Println(err)
		http.Error(w, "server error", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(rl.Core)
}

func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintln(w, "https://get-release.xyz/:owner/:repo/:os/:arch{/:constraint}")
}

func main() {
	router := httprouter.New()
	router.GET("/", index)
	router.GET("/:owner", usage)
	router.GET("/:owner/:repo", getVersions)
	router.GET("/:owner/:repo/:os", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch", getLatestDownload)
	router.GET("/:owner/:repo/:os/:arch/:constraint", getMatchingDownload)
	server := http.Server{
		Addr:    bindAddress,
		Handler: logger(router),
	}
	go func() {
		log.Printf("starting server on port %s...", bindAddress)
		if err := server.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()
	defer server.Shutdown(nil)
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
	log.Println("server stopped")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"

	"github.com/urfave/cli"
)

const (
	banner = `
 _____ _____ _____
|   __|  _  |  _  |___ ___ ___
|__   |   __|     |  _| . | -_|
|_____|__|  |__|__|_| |_  |___| %s
                      |___|
Single Page Application server  ________
_______________________________/__\__\__\
                               \__/__/__/

`
)

// version set by LDFLAGS
var version string

func start(root string, port int, origins []string) {
	e := echo.New()
	e.HideBanner = true

	e.Use(middleware.Logger())

	e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
		Root:   root,
		Index:  "index.html",
		HTML5:  true,
		Browse: false,
	}))

	if len(origins) > 0 {
		e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
			AllowOrigins: origins,
		}))
	}

	fmt.Printf(banner, "v"+version)
	fmt.Printf("» http server started on port %d\n", port)

	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", port)))
}

func main() {
	app := cli.NewApp()
	app.Name = "sparge"
	app.Usage = "A SPA (single-page application) server"
	app.Version = version

	app.Flags = []cli.Flag{}

	app.Commands = []cli.Command{
		{
			Name:  "start",
			Usage: "Start the SPA server",
			Action: func(c *cli.Context) error {
				origins := c.StringSlice("allow-origins")
				fmt.Printf("%v\n", origins)
				start(c.String("dir"), c.Int("port"), c.StringSlice("allow-origins"))
				return nil
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "dir, d",
					Value: "./public",
					Usage: "Directory from which to serve files.",
				},
				cli.StringFlag{
					Name:  "port, p",
					Value: "8080",
					Usage: "Server port.",
				},
				cli.StringSliceFlag{
					Name:  "allow-origins, o",
					Usage: "Comma separated list of origins or set with multiple params.",
				},
			},
		},
	}

	// start()
	app.Run(os.Args)
}
<commit_msg>style: remove extraneous debug code<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"

	"github.com/urfave/cli"
)

const (
	banner = `
 _____ _____ _____
|   __|  _  |  _  |___ ___ ___
|__   |   __|     |  _| . | -_|
|_____|__|  |__|__|_| |_  |___| %s
                      |___|
Single Page Application server  ________
_______________________________/__\__\__\
                               \__/__/__/

`
)

// version set by LDFLAGS
var version string

func start(root string, port int, origins []string) {
	e := echo.New()
	e.HideBanner = true

	e.Use(middleware.Logger())

	e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
		Root:   root,
		Index:  "index.html",
		HTML5:  true,
		Browse: false,
	}))

	if len(origins) > 0 {
		e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
			AllowOrigins: origins,
		}))
	}

	fmt.Printf(banner, "v"+version)
	fmt.Printf("» http server started on port %d\n", port)

	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", port)))
}

func main() {
	app := cli.NewApp()
	app.Name = "sparge"
	app.Usage = "A SPA (single-page application) server"
	app.Version = version

	app.Flags = []cli.Flag{}

	app.Commands = []cli.Command{
		{
			Name:  "start",
			Usage: "Start the SPA server",
			Action: func(c *cli.Context) error {
				start(c.String("dir"), c.Int("port"), c.StringSlice("allow-origins"))
				return nil
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "dir, d",
					Value: "./public",
					Usage: "Directory from which to serve files.",
				},
				cli.StringFlag{
					Name:  "port, p",
					Value: "8080",
					Usage: "Server port.",
				},
				cli.StringSliceFlag{
					Name:  "allow-origins, o",
					Usage: "Comma separated list of origins or set with multiple params.",
				},
			},
		},
	}

	// start()
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>// tyu is a small command line utility to display basic system informations
// in the terminal.
package main

import (
	"strconv"

	ui "github.com/gizak/termui"
)

func main() {
	// init termui
	if err := ui.Init(); err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	defer ui.Close()

	// display physical RAM usage informations
	ramGauge := ui.NewGauge() //TODO try to draw the border around gauge, used, free and total
	ramGauge.BorderLabel = "RAM usage "
	ramGauge.BarColor = ui.ColorBlue
	ramGauge.Width = 39
	ramGauge.Height = 3
	ramGauge.X = 0
	ramGauge.Y = 0

	// display physical swap usage informations
	swapGauge := ui.NewGauge()
	swapGauge.BorderLabel = "Swap usage "
	swapGauge.BarColor = ui.ColorBlue
	swapGauge.Width = 39
	swapGauge.Height = 3
	swapGauge.X = 0
	swapGauge.Y = 3

	// display information about the CPU usage
	cpuGauge := ui.NewGauge()
	cpuGauge.BorderLabel = "CPU usage "
	cpuGauge.BarColor = ui.ColorBlue
	cpuGauge.Width = 39
	cpuGauge.Height = 3
	cpuGauge.X = 0
	cpuGauge.Y = 6

	// display informations about the physical disks
	diskGauges := make([]*ui.Gauge, 3) // 3 disks max
	for i := range diskGauges {        //TEMP range = 3
		diskGauges[i] = ui.NewGauge()
		diskGauges[i].BarColor = ui.ColorBlue
		diskGauges[i].Width = 39
		diskGauges[i].Height = 3
		diskGauges[i].X = 0
		diskGauges[i].Y = 9 + (i * 3)
	}

	// display information about the global network activity (all interfaces)
	netinfo := ui.NewList()
	netinfo.BorderLabel = "Network "
	netitems := []string{
		"[Up   ](fg-cyan)",
		"[Down ](fg-cyan)",
	}
	netinfo.Items = netitems
	netinfo.Width = 19
	netinfo.Height = 4
	netinfo.X = 0
	netinfo.Y = 18

	// display information about the processes
	procinfo := ui.NewList()
	procinfo.BorderLabel = "Processes "
	procitems := []string{
		"[Tasks   ](fg-cyan)",
		"[Running ](fg-cyan)",
	}
	procinfo.Items = procitems
	procinfo.Width = 19
	procinfo.Height = 4
	procinfo.X = 20
	procinfo.Y = 18

	// display system informations about the host
	host := getHostinfo()
	hostinfo := ui.NewList()
	hostinfo.BorderLabel = "Host "
	hostitems := []string{
		"[Hostname         ](fg-cyan)" + host.hostname,
		"[Domain           ](fg-cyan)" + host.domainname,
		"[OS               ](fg-cyan)" + host.os,
		"[OS version       ](fg-cyan)" + host.osRelease,
		"[Platform         ](fg-cyan)" + host.platform,
		"[Platform version ](fg-cyan)" + host.platformVersion,
		"[Architecture     ](fg-cyan)" + host.arch,
		"[Uptime           ](fg-cyan)",
	}
	hostinfo.Items = hostitems
	hostinfo.Width = 39
	hostinfo.Height = 10
	hostinfo.X = 40
	hostinfo.Y = 0

	// display informations about the CPUs
	cpu := getCPUinfo()
	cpuinfo := ui.NewList()
	cpuinfo.BorderLabel = "CPU "
	cpuitems := []string{
		"[CPUs        ](fg-cyan)" + cpu.count, //TODO review item names compared to other cpu utilities
		"[Vendor      ](fg-cyan)" + cpu.vendorID,
		"[Model       ](fg-cyan)" + cpu.modelName, //TODO use refreshing rate to display roll long text ?
		"[Frequency   ](fg-cyan)" + cpu.cpuMhz + " Mhz",
		"[Temperature ](fg-cyan)", //TODO
	}
	cpuinfo.Items = cpuitems
	cpuinfo.Width = 39
	cpuinfo.Height = 7
	cpuinfo.X = 40
	cpuinfo.Y = 10

	// display bios and motherboard informations
	bios := getBIOSinfo()
	biosinfo := ui.NewList()
	biosinfo.BorderLabel = "BIOS "
	biosinfo.Items = []string{
		"[Motherboard ](fg-cyan)" + bios.boardName,
		"[Vendor      ](fg-cyan)" + bios.boardVendor,
		"[BIOS        ](fg-cyan)" + bios.biosVendor,
		"[Version     ](fg-cyan)" + bios.biosVersion + "  " + bios.biosDate,
	}
	biosinfo.Width = 39
	biosinfo.Height = 6
	biosinfo.X = 40
	biosinfo.Y = 17

	// display a quit help text
	quit := ui.NewPar("[ Type 'q' to exit ](fg-white,bg-blue)")
	quit.Height = 1
	quit.Width = 20
	quit.X = 0
	quit.Y = 23
	quit.Border = false

	// variables to calculate network traffic (to avoid cumulative display)
	var networkOld, networkNew Netinfo

	// render the dashboard with 26x80 fixed size
	draw := func(t int) {
		// update memory usage gauges
		mem := getMeminfo()
		ramGauge.Percent = mem.ramUsedPercent
		ramGauge.Label = "{{percent}}% - " + mem.ramUsed + "/" + mem.ramTotal + " GiB"
		swapGauge.Percent = mem.swapUsedPercent
		swapGauge.Label = "{{percent}}% - " + mem.swapUsed + "/" + mem.swapTotal + " GiB"

		// update CPU usage gauge
		cpuGauge.Percent = getCPUpercent()

		// update disks usage gauges
		disk := getDiskinfo()
		for i := range disk {
			if i >= 3 { // display 3 disk max
				break
			}
			diskGauges[i].BorderLabel = disk[i].device + " disk usage "
			diskGauges[i].Percent = disk[i].usedPercent
			diskGauges[i].Label = "{{percent}}% - " + disk[i].used + "/" + disk[i].total + " GiB"
		}

		// update network informations
		net := getNetinfo()
		networkNew.up = net.up - networkOld.up
		networkNew.down = net.down - networkOld.down
		networkOld = net
		netitems[0] = "[Up   ](fg-cyan)" + strconv.FormatFloat(networkNew.up, 'f', 1, 64) + " KiB"
		netitems[1] = "[Down ](fg-cyan)" + strconv.FormatFloat(networkNew.down, 'f', 1, 64) + " KiB"

		// update processes informations
		procs := getProcinfo()
		procitems[0] = "[Tasks   ](fg-cyan)" + procs.total
		procitems[1] = "[Running ](fg-cyan)" + procs.running

		// update the host informations
		hostitems[7] = "[Uptime           ](fg-cyan)" + getUptime()

		// update the CPUs informations
		cpuitems[4] = "[Temperature ](fg-cyan)" + "--"

		// register the gauges and blocks to the renderer
		ui.Render(
			ramGauge,
			swapGauge,
			cpuGauge,
			diskGauges[0],
			diskGauges[1],
			diskGauges[2],
			netinfo,
			procinfo,
			hostinfo,
			cpuinfo,
			biosinfo,
			quit,
		)
	}

	// quit on `q` keystroke handler
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		ui.StopLoop()
	})
	// quit on `CTRL+c` keystroke handler
	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		ui.StopLoop()
	})
	// timer handler to refresh every second
	ui.Handle("/timer/1s", func(e ui.Event) {
		t := e.Data.(ui.EvtTimer)
		draw(int(t.Count))
	})
	ui.Loop()
}

// the dashboard is 26x80
<commit_msg>Add command line parser<commit_after>// tyu is a small command line utility to display basic system informations
// in the terminal.
package main

import (
	"fmt"
	"os"
	"strconv"

	ui "github.com/gizak/termui"
	flag "github.com/ogier/pflag"
)

// command line argument
var versionFlag bool

// command line arguments setup
func init() {
	flag.BoolVarP(&versionFlag, "version", "V", false, "show program's version number and exit")
	// command line help text
	help := "Usage:\n  tyu [-h] [-V]\n\n" +
		"Options:\n" +
		"  -h, --help            show this help message and exit\n" +
		"  -V, --version         show program's version number and exit\n\n"
	flag.Usage = func() { // overide the ugly default usage message
		fmt.Fprintf(os.Stderr, help)
	}
}

func main() {
	// command line arguments
	flag.Parse()
	// show program's version number and exit
	if versionFlag == true {
		fmt.Println("Tyu version " + tyuVersion)
		os.Exit(0)
	}

	// init termui
	if err := ui.Init(); err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	defer ui.Close()

	// display physical RAM usage informations
	ramGauge := ui.NewGauge() //TODO try to draw the border around gauge, used, free and total
	ramGauge.BorderLabel = "RAM usage "
	ramGauge.BarColor = ui.ColorBlue
	ramGauge.Width = 39
	ramGauge.Height = 3
	ramGauge.X = 0
	ramGauge.Y = 0

	// display physical swap usage informations
	swapGauge := ui.NewGauge()
	swapGauge.BorderLabel = "Swap usage "
	swapGauge.BarColor = ui.ColorBlue
	swapGauge.Width = 39
	swapGauge.Height = 3
	swapGauge.X = 0
	swapGauge.Y = 3

	// display information about the CPU usage
	cpuGauge := ui.NewGauge()
	cpuGauge.BorderLabel = "CPU usage "
	cpuGauge.BarColor = ui.ColorBlue
	cpuGauge.Width = 39
	cpuGauge.Height = 3
	cpuGauge.X = 0
	cpuGauge.Y = 6

	// display informations about the physical disks
	diskGauges := make([]*ui.Gauge, 3) // 3 disks max
	for i := range diskGauges {        //TEMP range = 3
		diskGauges[i] = ui.NewGauge()
		diskGauges[i].BarColor = ui.ColorBlue
		diskGauges[i].Width = 39
		diskGauges[i].Height = 3
		diskGauges[i].X = 0
		diskGauges[i].Y = 9 + (i * 3)
	}

	// display information about the global network activity (all interfaces)
	netinfo := ui.NewList()
	netinfo.BorderLabel = "Network "
	netitems := []string{
		"[Up   ](fg-cyan)",
		"[Down ](fg-cyan)",
	}
	netinfo.Items = netitems
	netinfo.Width = 19
	netinfo.Height = 4
	netinfo.X = 0
	netinfo.Y = 18

	// display information about the processes
	procinfo := ui.NewList()
	procinfo.BorderLabel = "Processes "
	procitems := []string{
		"[Tasks   ](fg-cyan)",
		"[Running ](fg-cyan)",
	}
	procinfo.Items = procitems
	procinfo.Width = 19
	procinfo.Height = 4
	procinfo.X = 20
	procinfo.Y = 18

	// display system informations about the host
	host := getHostinfo()
	hostinfo := ui.NewList()
	hostinfo.BorderLabel = "Host "
	hostitems := []string{
		"[Hostname         ](fg-cyan)" + host.hostname,
		"[Domain           ](fg-cyan)" + host.domainname,
		"[OS               ](fg-cyan)" + host.os,
		"[OS version       ](fg-cyan)" + host.osRelease,
		"[Platform         ](fg-cyan)" + host.platform,
		"[Platform version ](fg-cyan)" + host.platformVersion,
		"[Architecture     ](fg-cyan)" + host.arch,
		"[Uptime           ](fg-cyan)",
	}
	hostinfo.Items = hostitems
	hostinfo.Width = 39
	hostinfo.Height = 10
	hostinfo.X = 40
	hostinfo.Y = 0

	// display informations about the CPUs
	cpu := getCPUinfo()
	cpuinfo := ui.NewList()
	cpuinfo.BorderLabel = "CPU "
	cpuitems := []string{
		"[CPUs        ](fg-cyan)" + cpu.count, //TODO review item names compared to other cpu utilities
		"[Vendor      ](fg-cyan)" + cpu.vendorID,
		"[Model       ](fg-cyan)" + cpu.modelName, //TODO use refreshing rate to display roll long text ?
		"[Frequency   ](fg-cyan)" + cpu.cpuMhz + " Mhz",
		"[Temperature ](fg-cyan)", //TODO
	}
	cpuinfo.Items = cpuitems
	cpuinfo.Width = 39
	cpuinfo.Height = 7
	cpuinfo.X = 40
	cpuinfo.Y = 10

	// display bios and motherboard informations
	bios := getBIOSinfo()
	biosinfo := ui.NewList()
	biosinfo.BorderLabel = "BIOS "
	biosinfo.Items = []string{
		"[Motherboard ](fg-cyan)" + bios.boardName,
		"[Vendor      ](fg-cyan)" + bios.boardVendor,
		"[BIOS        ](fg-cyan)" + bios.biosVendor,
		"[Version     ](fg-cyan)" + bios.biosVersion + "  " + bios.biosDate,
	}
	biosinfo.Width = 39
	biosinfo.Height = 6
	biosinfo.X = 40
	biosinfo.Y = 17

	// display a quit help text
	quit := ui.NewPar("[ Type 'q' to exit ](fg-white,bg-blue)")
	quit.Height = 1
	quit.Width = 20
	quit.X = 0
	quit.Y = 23
	quit.Border = false

	// variables to calculate network traffic (to avoid cumulative display)
	var networkOld, networkNew Netinfo

	// render the dashboard with 26x80 fixed size
	draw := func(t int) {
		// update memory usage gauges
		mem := getMeminfo()
		ramGauge.Percent = mem.ramUsedPercent
		ramGauge.Label = "{{percent}}% - " + mem.ramUsed + "/" + mem.ramTotal + " GiB"
		swapGauge.Percent = mem.swapUsedPercent
		swapGauge.Label = "{{percent}}% - " + mem.swapUsed + "/" + mem.swapTotal + " GiB"

		// update CPU usage gauge
		cpuGauge.Percent = getCPUpercent()

		// update disks usage gauges
		disk := getDiskinfo()
		for i := range disk {
			if i >= 3 { // display 3 disk max
				break
			}
			diskGauges[i].BorderLabel = disk[i].device + " disk usage "
			diskGauges[i].Percent = disk[i].usedPercent
			diskGauges[i].Label = "{{percent}}% - " + disk[i].used + "/" + disk[i].total + " GiB"
		}

		// update network informations
		net := getNetinfo()
		networkNew.up = net.up - networkOld.up
		networkNew.down = net.down - networkOld.down
		networkOld = net
		netitems[0] = "[Up   ](fg-cyan)" + strconv.FormatFloat(networkNew.up, 'f', 1, 64) + " KiB"
		netitems[1] = "[Down ](fg-cyan)" + strconv.FormatFloat(networkNew.down, 'f', 1, 64) + " KiB"

		// update processes informations
		procs := getProcinfo()
		procitems[0] = "[Tasks   ](fg-cyan)" + procs.total
		procitems[1] = "[Running ](fg-cyan)" + procs.running

		// update the host informations
		hostitems[7] = "[Uptime           ](fg-cyan)" + getUptime()

		// update the CPUs informations
		cpuitems[4] = "[Temperature ](fg-cyan)" + "--"

		// register the gauges and blocks to the renderer
		ui.Render(
			ramGauge,
			swapGauge,
			cpuGauge,
			diskGauges[0],
			diskGauges[1],
			diskGauges[2],
			netinfo,
			procinfo,
			hostinfo,
			cpuinfo,
			biosinfo,
			quit,
		)
	}

	// quit on `q` keystroke handler
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		ui.StopLoop()
	})
	// quit on `CTRL+c` keystroke handler
	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		ui.StopLoop()
	})
	// timer handler to refresh every second
	ui.Handle("/timer/1s", func(e ui.Event) {
		t := e.Data.(ui.EvtTimer)
		draw(int(t.Count))
	})
	ui.Loop()
}

// the dashboard is 26x80
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"expvar"
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"

	"github.com/gorilla/mux"

	bleveHttp "github.com/blevesearch/bleve/http"

	log "github.com/couchbaselabs/clog"
	"github.com/couchbaselabs/go-couchbase"
)

var bindAddr = flag.String("addr", ":8095",
	"http listen [address]:port")
var dataDir = flag.String("dataDir", "data",
	"directory for index data")
var logFlags = flag.String("logFlags", "",
	"comma-separated clog flags, to control logging")
var staticDir = flag.String("staticDir", "static",
	"directory for static web UI content")
var staticEtag = flag.String("staticEtag", "",
	"static etag value")
var server = flag.String("server", "",
	"url to couchbase server, example: http://localhost:8091")
var wanted = flag.Bool("wanted", false,
	"force this node to be wanted as part of the cluster")
var cfgProvider = flag.String("cfgProvider", "simple",
	"provider/connection to cluster config")

var expvars = expvar.NewMap("stats")

func init() {
	expvar.Publish("cbft", expvars)
	expvars.Set("indexes", bleveHttp.IndexStats())
}

func main() {
	flag.Parse()

	go dumpOnSignalForPlatform()

	log.Printf("%s started", os.Args[0])
	if *logFlags != "" {
		log.ParseLogFlag(*logFlags)
	}
	flag.VisitAll(func(f *flag.Flag) { log.Printf("  -%s=%s\n", f.Name, f.Value) })
	log.Printf("  GOMAXPROCS=%d", runtime.GOMAXPROCS(-1))

	// TODO: If cfg goes down, should we stop?  How do we reconnect?

	cfg, err := MainCfg(*cfgProvider, *dataDir)
	if err != nil {
		log.Fatalf("error: could not start cfg, cfgProvider: %s, err: %v",
			*cfgProvider, err)
		return
	}

	router, err := MainStart(cfg, *bindAddr, NewUUID(),
		*dataDir, *staticDir, *server, *wanted)
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", router)
	log.Printf("listening on: %v", *bindAddr)
	log.Fatal(http.ListenAndServe(*bindAddr, nil))
}

func MainStart(cfg Cfg, uuid, bindAddr, dataDir, staticDir, server string, wanted bool) (
	*mux.Router, error) {
	if server == "" {
		return nil, fmt.Errorf("error: server URL required (-server)")
	}

	_, err := couchbase.Connect(server)
	if err != nil {
		return nil, fmt.Errorf("error: could not connect to server URL: %s, err: %v",
			server, err)
	}

	mgr := NewManager(VERSION, cfg, uuid, bindAddr, dataDir, server, &MainHandlers{})
	if err = mgr.Start(wanted); err != nil {
		return nil, err
	}

	return NewManagerRESTRouter(mgr, staticDir)
}

type MainHandlers struct{}

func (meh *MainHandlers) OnRegisterPIndex(pindex *PIndex) {
	bleveHttp.RegisterIndexName(pindex.Name, pindex.BIndex)
}

func (meh *MainHandlers) OnUnregisterPIndex(pindex *PIndex) {
	bleveHttp.UnregisterIndexByName(pindex.Name)
}

func dumpOnSignal(signals ...os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, signals...)
	for _ = range c {
		pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
	}
}
<commit_msg>MainUUID() function to generate or reload (from dataDir) a UUID<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"expvar"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strings"

	"github.com/gorilla/mux"

	bleveHttp "github.com/blevesearch/bleve/http"

	log "github.com/couchbaselabs/clog"
	"github.com/couchbaselabs/go-couchbase"
)

var bindAddr = flag.String("addr", ":8095",
	"http listen [address]:port")
var dataDir = flag.String("dataDir", "data",
	"directory for index data")
var logFlags = flag.String("logFlags", "",
	"comma-separated clog flags, to control logging")
var staticDir = flag.String("staticDir", "static",
	"directory for static web UI content")
var staticEtag = flag.String("staticEtag", "",
	"static etag value")
var server = flag.String("server", "",
	"url to couchbase server, example: http://localhost:8091")
var wanted = flag.Bool("wanted", false,
	"force this node to be wanted as part of the cluster")
var cfgProvider = flag.String("cfgProvider", "simple",
	"provider/connection to cluster config")

var expvars = expvar.NewMap("stats")

func init() {
	expvar.Publish("cbft", expvars)
	expvars.Set("indexes", bleveHttp.IndexStats())
}

func main() {
	flag.Parse()

	go dumpOnSignalForPlatform()

	log.Printf("%s started", os.Args[0])
	if *logFlags != "" {
		log.ParseLogFlag(*logFlags)
	}
	flag.VisitAll(func(f *flag.Flag) { log.Printf("  -%s=%s\n", f.Name, f.Value) })
	log.Printf("  GOMAXPROCS=%d", runtime.GOMAXPROCS(-1))

	// TODO: If cfg goes down, should we stop?  How do we reconnect?

	cfg, err := MainCfg(*cfgProvider, *dataDir)
	if err != nil {
		log.Fatalf("error: could not start cfg, cfgProvider: %s, err: %v",
			*cfgProvider, err)
		return
	}

	uuid, err := MainUUID(*dataDir)
	if err != nil {
		log.Fatalf(fmt.Sprintf("%v", err))
		return
	}

	router, err := MainStart(cfg, uuid, *bindAddr, *dataDir,
		*staticDir, *server, *wanted)
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", router)
	log.Printf("listening on: %v", *bindAddr)
	log.Fatal(http.ListenAndServe(*bindAddr, nil))
}

func MainUUID(dataDir string) (string, error) {
	uuid := NewUUID()
	uuidPath := dataDir + string(os.PathSeparator) + "cbft.uuid"
	uuidBuf, err := ioutil.ReadFile(uuidPath)
	if err == nil {
		uuid = strings.TrimSpace(string(uuidBuf))
		if uuid == "" {
			return "", fmt.Errorf("error: could not parse uuidPath: %s", uuidPath)
		}
		log.Printf("manager uuid: %s", uuid)
		log.Printf("manager uuid was reloaded")
	} else {
		log.Printf("manager uuid: %s", uuid)
		log.Printf("manager uuid was generated")
	}
	err = ioutil.WriteFile(uuidPath, []byte(uuid), 0600)
	if err != nil {
		return "", fmt.Errorf("error: could not write uuidPath: %s", uuidPath)
	}
	return uuid, nil
}

func MainStart(cfg Cfg, uuid, bindAddr, dataDir, staticDir, server string, wanted bool) (
	*mux.Router, error) {
	if server == "" {
		return nil, fmt.Errorf("error: server URL required (-server)")
	}

	_, err := couchbase.Connect(server)
	if err != nil {
		return nil, fmt.Errorf("error: could not connect to server URL: %s, err: %v",
			server, err)
	}

	mgr := NewManager(VERSION, cfg, uuid, bindAddr, dataDir, server, &MainHandlers{})
	if err = mgr.Start(wanted); err != nil {
		return nil, err
	}

	return NewManagerRESTRouter(mgr, staticDir)
}

type MainHandlers struct{}

func (meh *MainHandlers) OnRegisterPIndex(pindex *PIndex) {
	bleveHttp.RegisterIndexName(pindex.Name, pindex.BIndex)
}

func (meh *MainHandlers) OnUnregisterPIndex(pindex *PIndex) {
	bleveHttp.UnregisterIndexByName(pindex.Name)
}

func dumpOnSignal(signals ...os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, signals...)
	for _ = range c {
		pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"database/sql"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"

	"golang.org/x/net/context"

	"github.com/kusubooru/shimmie"
	"github.com/kusubooru/shimmie/store"
)

//go:generate go run generate/version.go

var (
	httpAddr = flag.String("http", "localhost:8080", "HTTP listen address")
	dbDriver = flag.String("dbdriver", "mysql", "database driver")
	dbConfig = flag.String("dbconfig", "", "username:password@(host:port)/database?parseTime=true")
	loginURL = flag.String("loginurl", "/kanri/login", "login URL path to redirect to")
	//version  = flag.Bool("v", false, "print program version")
	certFile = flag.String("tlscert", "", "TLS public key in PEM format.  Must be used together with -tlskey")
	keyFile  = flag.String("tlskey", "", "TLS private key in PEM format.  Must be used together with -tlscert")
	// Set after flag parsing based on certFile & keyFile.
	useTLS bool
)

const (
	description = `Usage: kanri [options]
  Management tools for shimmie.
Options:
`
)

func usage() {
	fmt.Fprintf(os.Stderr, description)
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}

func main() {
	flag.Usage = usage
	flag.Parse()
	useTLS = *certFile != "" && *keyFile != ""

	//if *version {
	//	// TheVersion is generated by go generate.
	//	fmt.Printf("teian%v\n", TheVersion)
	//	return
	//}

	// open store with new database connection and create new Shimmie
	shim := shimmie.New(store.Open(*dbDriver, *dbConfig))

	// get common conf
	common, cerr := shim.Store.GetCommon()
	if cerr != nil {
		log.Fatalln("could not get common conf:", cerr)
	}

	// app with Shimmie and common conf
	app := App{Shimmie: shim, Common: common}

	// new context
	ctx := context.Background()

	http.Handle("/kanri", shim.Auth(ctx, app.serveIndex, *loginURL))
	http.Handle("/kanri/safe", shim.Auth(ctx, app.serveSafe, *loginURL))
	http.Handle("/kanri/safe/rate", shim.Auth(ctx, app.handleSafeRate, *loginURL))
	http.Handle("/kanri/_image/", shim.Auth(ctx, app.serveImage, *loginURL))
	http.Handle("/kanri/_thumb/", shim.Auth(ctx, app.serveThumb, *loginURL))
	http.Handle("/kanri/login", newHandler(ctx, app.serveLogin))
	http.Handle("/kanri/login/submit", newHandler(ctx, app.handleLogin))
	http.Handle("/kanri/logout", http.HandlerFunc(handleLogout))

	if useTLS {
		if err := http.ListenAndServeTLS(*httpAddr, *certFile, *keyFile, nil); err != nil {
			log.Fatalf("Could not start listening (TLS) on %v: %v", *httpAddr, err)
		}
	} else {
		if err := http.ListenAndServe(*httpAddr, nil); err != nil {
			log.Fatalf("Could not start listening on %v: %v", *httpAddr, err)
		}
	}
}

type ctxHandlerFunc func(context.Context, http.ResponseWriter, *http.Request)

func newHandler(ctx context.Context, fn ctxHandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fn(ctx, w, r)
	}
}

type App struct {
	Shimmie *shimmie.Shimmie
	Common  *shimmie.Common
}

func (app *App) serveIndex(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.render(w, indexTmpl, nil)
}

func (app *App) serveSafe(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, ok := ctx.Value("user").(*shimmie.User)
	if !ok || user.Admin != "Y" {
		http.Error(w, "You are not authorized to view this page.", http.StatusUnauthorized)
		return
	}
	images, err := app.Shimmie.GetRatedImages(user.Name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	app.render(w, safeTmpl, images)
}

func (app *App) handleSafeRate(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// Only accept POST method.
	if r.Method != "POST" {
		http.Error(w, fmt.Sprintf("%v method not allowed", r.Method), http.StatusMethodNotAllowed)
		return
	}

	// Get user and user IP from context.
	user, ok := ctx.Value("user").(*shimmie.User)
	if !ok || user.Admin != "Y" {
		http.Error(w, "You are not authorized to view this page.", http.StatusUnauthorized)
		return
	}
	userIP := shimmie.GetOriginalIP(r)

	// Get image ID and rating from the HTTP request.
	id := r.PostFormValue("id")
	imgID, err := strconv.Atoi(id)
	if err != nil {
		http.Error(w, fmt.Sprintf("invalid image ID: %v", err), http.StatusBadRequest)
		return
	}
	imgRating := r.PostFormValue("rating")

	// Store the new image rating.
	err = app.Shimmie.RateImage(imgID, imgRating)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Write the rating change to the shimmie log.
	err = app.Shimmie.LogRating(imgID, imgRating, user.Name, userIP)
	if err != nil {
		log.Printf("Failed to log rating %q of image %d for username %q (%s) in score_log.",
			imgRating, imgID, user.Name, userIP)
	}

	// Serve again the safe approval template.
	app.serveSafe(ctx, w, r)
}

func (app *App) serveImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.serveImageFile(ctx, w, r, app.Shimmie.ImagePath)
}

func (app *App) serveThumb(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.serveImageFile(ctx, w, r, app.Shimmie.ThumbPath)
}

func (app *App) serveImageFile(ctx context.Context, w http.ResponseWriter, r *http.Request, path string) {
	hash := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]

	err := app.Shimmie.WriteImageFile(w, path, hash)
	if err != nil {
		http.Error(w, fmt.Sprintf("could not write image file: %v", err), http.StatusInternalServerError)
		return
	}
}

func (app *App) serveLogin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.render(w, loginTmpl, nil)
}

func (app *App) handleLogin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// only accept POST method
	if r.Method != "POST" {
		http.Error(w, fmt.Sprintf("%v method not allowed", r.Method), http.StatusMethodNotAllowed)
		return
	}
	username := r.PostFormValue("username")
	password := r.PostFormValue("password")
	user, err := app.Shimmie.GetUser(username)
	if err != nil {
		if err == sql.ErrNoRows {
			app.render(w, loginTmpl, "User does not exist.")
			return
		}
		msg := fmt.Sprintf("get user %q failed: %v", username, err.Error())
		log.Print(msg)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
	hash := md5.Sum([]byte(username + password))
	passwordHash := fmt.Sprintf("%x", hash)
	if user.Pass != passwordHash {
		app.render(w, loginTmpl, "Username and password do not match.")
		return
	}
	addr := strings.Split(r.RemoteAddr, ":")[0]
	cookieValue := shimmie.CookieValue(passwordHash, addr)
	shimmie.SetCookie(w, "shm_user", username)
	shimmie.SetCookie(w, "shm_session", cookieValue)
	http.Redirect(w, r, "/kanri", http.StatusFound)
}

func handleLogout(w http.ResponseWriter, r *http.Request) {
	shimmie.SetCookie(w, "shm_user", "")
	shimmie.SetCookie(w, "shm_session", "")
	http.Redirect(w, r, "/kanri", http.StatusFound)
}

func render(w http.ResponseWriter, t *template.Template, data interface{}) {
	if err := t.Execute(w, data); err != nil {
		msg := fmt.Sprintln("could not render template:", err)
		log.Print(msg)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
}

func (app *App) render(w http.ResponseWriter, t *template.Template, data interface{}) {
	render(w, t, struct {
		Data   interface{}
		Common *shimmie.Common
	}{
		Data:   data,
		Common: app.Common,
	})
}
<commit_msg>Change shimmie to receive image and thumb path<commit_after>package main

import (
	"crypto/md5"
	"database/sql"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"

	"golang.org/x/net/context"

	"github.com/kusubooru/shimmie"
	"github.com/kusubooru/shimmie/store"
)

//go:generate go run generate/version.go

var (
	httpAddr = flag.String("http", "localhost:8080", "HTTP listen address")
	dbDriver = flag.String("dbdriver", "mysql", "database driver")
	dbConfig = flag.String("dbconfig", "", "username:password@(host:port)/database?parseTime=true")
	loginURL = flag.String("loginurl", "/kanri/login", "login URL path to redirect to")
	//version  = flag.Bool("v", false, "print program version")
	certFile = flag.String("tlscert", "", "TLS public key in PEM format.  Must be used together with -tlskey")
	keyFile  = flag.String("tlskey", "", "TLS private key in PEM format.  Must be used together with -tlscert")
	// Set after flag parsing based on certFile & keyFile.
	useTLS bool
)

const (
	description = `Usage: kanri [options]
  Management tools for shimmie.
Options:
`
)

func usage() {
	fmt.Fprintf(os.Stderr, description)
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}

func main() {
	flag.Usage = usage
	flag.Parse()
	useTLS = *certFile != "" && *keyFile != ""

	//if *version {
	//	// TheVersion is generated by go generate.
	//	fmt.Printf("teian%v\n", TheVersion)
	//	return
	//}

	// open store with new database connection and create new Shimmie
	shim := shimmie.New(*imagePath, *thumbPath, store.Open(*dbDriver, *dbConfig))

	// get common conf
	common, cerr := shim.Store.GetCommon()
	if cerr != nil {
		log.Fatalln("could not get common conf:", cerr)
	}

	// app with Shimmie and common conf
	app := App{Shimmie: shim, Common: common}

	// new context
	ctx := context.Background()

	http.Handle("/kanri", shim.Auth(ctx, app.serveIndex, *loginURL))
	http.Handle("/kanri/safe", shim.Auth(ctx, app.serveSafe, *loginURL))
	http.Handle("/kanri/safe/rate", shim.Auth(ctx, app.handleSafeRate, *loginURL))
	http.Handle("/kanri/_image/", shim.Auth(ctx, app.serveImage, *loginURL))
	http.Handle("/kanri/_thumb/", shim.Auth(ctx, app.serveThumb, *loginURL))
	http.Handle("/kanri/login", newHandler(ctx, app.serveLogin))
	http.Handle("/kanri/login/submit", newHandler(ctx, app.handleLogin))
	http.Handle("/kanri/logout", http.HandlerFunc(handleLogout))

	if useTLS {
		if err := http.ListenAndServeTLS(*httpAddr, *certFile, *keyFile, nil); err != nil {
			log.Fatalf("Could not start listening (TLS) on %v: %v", *httpAddr, err)
		}
	} else {
		if err := http.ListenAndServe(*httpAddr, nil); err != nil {
			log.Fatalf("Could not start listening on %v: %v", *httpAddr, err)
		}
	}
}

type ctxHandlerFunc func(context.Context, http.ResponseWriter, *http.Request)

func newHandler(ctx context.Context, fn ctxHandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fn(ctx, w, r)
	}
}

type App struct {
	Shimmie *shimmie.Shimmie
	Common  *shimmie.Common
}

func (app *App) serveIndex(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.render(w, indexTmpl, nil)
}

func (app *App) serveSafe(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	user, ok := ctx.Value("user").(*shimmie.User)
	if !ok || user.Admin != "Y" {
		http.Error(w, "You are not authorized to view this page.", http.StatusUnauthorized)
		return
	}
	images, err := app.Shimmie.GetRatedImages(user.Name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	app.render(w, safeTmpl, images)
}

func (app *App) handleSafeRate(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// Only accept POST method.
	if r.Method != "POST" {
		http.Error(w, fmt.Sprintf("%v method not allowed", r.Method), http.StatusMethodNotAllowed)
		return
	}

	// Get user and user IP from context.
	user, ok := ctx.Value("user").(*shimmie.User)
	if !ok || user.Admin != "Y" {
		http.Error(w, "You are not authorized to view this page.", http.StatusUnauthorized)
		return
	}
	userIP := shimmie.GetOriginalIP(r)

	// Get image ID and rating from the HTTP request.
	id := r.PostFormValue("id")
	imgID, err := strconv.Atoi(id)
	if err != nil {
		http.Error(w, fmt.Sprintf("invalid image ID: %v", err), http.StatusBadRequest)
		return
	}
	imgRating := r.PostFormValue("rating")

	// Store the new image rating.
	err = app.Shimmie.RateImage(imgID, imgRating)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Write the rating change to the shimmie log.
	err = app.Shimmie.LogRating(imgID, imgRating, user.Name, userIP)
	if err != nil {
		log.Printf("Failed to log rating %q of image %d for username %q (%s) in score_log.",
			imgRating, imgID, user.Name, userIP)
	}

	// Serve again the safe approval template.
	app.serveSafe(ctx, w, r)
}

func (app *App) serveImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.serveImageFile(ctx, w, r, app.Shimmie.ImagePath)
}

func (app *App) serveThumb(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.serveImageFile(ctx, w, r, app.Shimmie.ThumbPath)
}

func (app *App) serveImageFile(ctx context.Context, w http.ResponseWriter, r *http.Request, path string) {
	hash := r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]

	err := app.Shimmie.WriteImageFile(w, path, hash)
	if err != nil {
		http.Error(w, fmt.Sprintf("could not write image file: %v", err), http.StatusInternalServerError)
		return
	}
}

func (app *App) serveLogin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	app.render(w, loginTmpl, nil)
}

func (app *App) handleLogin(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// only accept POST method
	if r.Method != "POST" {
		http.Error(w, fmt.Sprintf("%v method not allowed", r.Method), http.StatusMethodNotAllowed)
		return
	}
	username := r.PostFormValue("username")
	password := r.PostFormValue("password")
	user, err := app.Shimmie.GetUser(username)
	if err != nil {
		if err == sql.ErrNoRows {
			app.render(w, loginTmpl, "User does not exist.")
			return
		}
		msg := fmt.Sprintf("get user %q failed: %v", username, err.Error())
		log.Print(msg)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
	hash := md5.Sum([]byte(username + password))
	passwordHash := fmt.Sprintf("%x", hash)
	if user.Pass != passwordHash {
		app.render(w, loginTmpl, "Username and password do not match.")
		return
	}
	addr := strings.Split(r.RemoteAddr, ":")[0]
	cookieValue := shimmie.CookieValue(passwordHash, addr)
	shimmie.SetCookie(w, "shm_user", username)
	shimmie.SetCookie(w, "shm_session", cookieValue)
	http.Redirect(w, r, "/kanri", http.StatusFound)
}

func handleLogout(w http.ResponseWriter, r *http.Request) {
	shimmie.SetCookie(w, "shm_user", "")
	shimmie.SetCookie(w, "shm_session", "")
	http.Redirect(w, r, "/kanri", http.StatusFound)
}

func render(w http.ResponseWriter, t *template.Template, data interface{}) {
	if err := t.Execute(w, data); err != nil {
		msg := fmt.Sprintln("could not render template:", err)
		log.Print(msg)
		http.Error(w, msg, http.StatusInternalServerError)
		return
	}
}

func (app *App) render(w http.ResponseWriter, t *template.Template, data interface{}) {
	render(w, t, struct {
		Data   interface{}
		Common *shimmie.Common
	}{
		Data:   data,
		Common: app.Common,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/mattn/go-tty"
)

type ActionType int

const (
	LABEL_AS_POSITIVE ActionType = iota
	LABEL_AS_NEGATIVE
	SAVE
	HELP
	SKIP
	EXIT
)

func input2ActionType() (ActionType, error) {
	t, err := tty.Open()
	defer t.Close()
	if err != nil {
		return EXIT, err
	}
	var r rune
	for r == 0 {
		r, err = t.ReadRune()
		if err != nil {
			return SKIP, err
		}
	}
	switch r {
	case 'p':
		return LABEL_AS_POSITIVE, nil
	case 'n':
		return LABEL_AS_NEGATIVE, nil
	case 's':
		return SAVE, nil
	case 'h':
		return HELP, nil
	case 'e':
		return EXIT, nil
	default:
		return SKIP, nil
	}
}

func main() {
	cacheFilename := "cache.bin"

	cache, _ := LoadCache(cacheFilename)
	examples, _ := ReadExamples(os.Args[1])
	for _, e := range examples {
		if title, ok := cache.cache[e.url]; ok {
			e.title = title
		} else {
			title = GetTitle(e.url)
			fmt.Println("Fetching: " + e.url)
			e.title = title
			cache.Add(*e)
		}
		e.fv = ExtractFeatures(e.title)
	}
	model := TrainedModel(examples)

annotationLoop:
	for {
		unlabeledExamples := model.SortByScore(examples)
		if len(unlabeledExamples) == 0 {
			break
		}
		e := unlabeledExamples[0]
		if e == nil {
			break
		}
		fmt.Println("Label this example (score: " + fmt.Sprintf("%0.03f", e.score) + "): " + e.url + " (" + e.title + ")")
		cache.Add(*e)

		act, err := input2ActionType()
		if err != nil {
			return
		}
		switch act {
		case LABEL_AS_POSITIVE:
			fmt.Println("Labeled as positive")
			e.Annotate(POSITIVE)
		case LABEL_AS_NEGATIVE:
			fmt.Println("Labeled as negative")
			e.Annotate(NEGATIVE)
		case SKIP:
			fmt.Println("Skiped this example")
			continue
		case SAVE:
			fmt.Println("Saved labeld examples")
		case HELP:
			fmt.Println("ToDo: SHOW HELP")
		case EXIT:
			fmt.Println("EXIT")
			break annotationLoop
		default:
			break annotationLoop
		}
		model = TrainedModel(examples)
	}

	WriteExamples(examples, os.Args[2])
	cache.Save(cacheFilename)
}
<commit_msg>シャッフルする<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/mattn/go-tty"
)

type ActionType int

const (
	LABEL_AS_POSITIVE ActionType = iota
	LABEL_AS_NEGATIVE
	SAVE
	HELP
	SKIP
	EXIT
)

func input2ActionType() (ActionType, error) {
	t, err := tty.Open()
	defer t.Close()
	if err != nil {
		return EXIT, err
	}
	var r rune
	for r == 0 {
		r, err = t.ReadRune()
		if err != nil {
			return SKIP, err
		}
	}
	switch r {
	case 'p':
		return LABEL_AS_POSITIVE, nil
	case 'n':
		return LABEL_AS_NEGATIVE, nil
	case 's':
		return SAVE, nil
	case 'h':
		return HELP, nil
	case 'e':
		return EXIT, nil
	default:
		return SKIP, nil
	}
}

func main() {
	cacheFilename := "cache.bin"

	cache, _ := LoadCache(cacheFilename)
	examples, _ := ReadExamples(os.Args[1])
	shuffle(examples)
	for _, e := range examples {
		if title, ok := cache.cache[e.url]; ok {
			e.title = title
		} else {
			title = GetTitle(e.url)
			fmt.Println("Fetching: " + e.url)
			e.title = title
			cache.Add(*e)
		}
		e.fv = ExtractFeatures(e.title)
	}
	model := TrainedModel(examples)

annotationLoop:
	for {
		unlabeledExamples := model.SortByScore(examples)
		if len(unlabeledExamples) == 0 {
			break
		}
		e := unlabeledExamples[0]
		if e == nil {
			break
		}
		fmt.Println("Label this example (score: " + fmt.Sprintf("%0.03f", e.score) + "): " + e.url + " (" + e.title + ")")
		cache.Add(*e)

		act, err := input2ActionType()
		if err != nil {
			return
		}
		switch act {
		case LABEL_AS_POSITIVE:
			fmt.Println("Labeled as positive")
			e.Annotate(POSITIVE)
		case LABEL_AS_NEGATIVE:
			fmt.Println("Labeled as negative")
			e.Annotate(NEGATIVE)
		case SKIP:
			fmt.Println("Skiped this example")
			continue
		case SAVE:
			fmt.Println("Saved labeld examples")
		case HELP:
			fmt.Println("ToDo: SHOW HELP")
		case EXIT:
			fmt.Println("EXIT")
			break annotationLoop
		default:
			break annotationLoop
		}
		model = TrainedModel(examples)
	}

	WriteExamples(examples, os.Args[2])
	cache.Save(cacheFilename)
}
<|endoftext|>


<commit_before>package main

import "github.com/gerow/boop"

func main() {
  boop.BoopMain()
}
<commit_msg>Updated main.go in order to use the correct import path<commit_after>package main

import "github.com/gerow/boop/boop"

func main() {
  boop.BoopMain()
}
<|endoftext|>