<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"time"

	"context"

	"github.com/go-kit/kit/log/level"
	"github.com/justwatchcom/elasticsearch_exporter/collector"
	"github.com/justwatchcom/elasticsearch_exporter/pkg/clusterinfo"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
	"gopkg.in/alecthomas/kingpin.v2"
)

func main() {
	var (
		Name          = "elasticsearch_exporter"
		listenAddress = kingpin.Flag("web.listen-address",
			"Address to listen on for web interface and telemetry.").
			Default(":9114").Envar("WEB_LISTEN_ADDRESS").String()
		metricsPath = kingpin.Flag("web.telemetry-path",
			"Path under which to expose metrics.").
			Default("/metrics").Envar("WEB_TELEMETRY_PATH").String()
		esURI = kingpin.Flag("es.uri",
			"HTTP API address of an Elasticsearch node.").
			Default("http://localhost:9200").Envar("ES_URI").String()
		esTimeout = kingpin.Flag("es.timeout",
			"Timeout for trying to get stats from Elasticsearch.").
			Default("5s").Envar("ES_TIMEOUT").Duration()
		esAllNodes = kingpin.Flag("es.all",
			"Export stats for all nodes in the cluster. If used, this flag will override the flag es.node.").
			Default("false").Envar("ES_ALL").Bool()
		esNode = kingpin.Flag("es.node",
			"Node's name of which metrics should be exposed.").
			Default("_local").Envar("ES_NODE").String()
		esExportIndices = kingpin.Flag("es.indices",
			"Export stats for indices in the cluster.").
			Default("false").Envar("ES_INDICES").Bool()
		esExportIndicesSettings = kingpin.Flag("es.indices_settings",
			"Export stats for settings of all indices of the cluster.").
			Default("false").Envar("ES_INDICES_SETTINGS").Bool()
		esExportClusterSettings = kingpin.Flag("es.cluster_settings",
			"Export stats for cluster settings.").
			Default("false").Envar("ES_CLUSTER_SETTINGS").Bool()
		esExportShards = kingpin.Flag("es.shards",
			"Export stats for shards in the cluster (implies --es.indices).").
			Default("false").Envar("ES_SHARDS").Bool()
		esExportSnapshots = kingpin.Flag("es.snapshots",
			"Export stats for the cluster snapshots.").
			Default("false").Envar("ES_SNAPSHOTS").Bool()
		esClusterInfoInterval = kingpin.Flag("es.clusterinfo.interval",
			"Cluster info update interval for the cluster label").
			Default("5m").Envar("ES_CLUSTERINFO_INTERVAL").Duration()
		esCA = kingpin.Flag("es.ca",
			"Path to PEM file that contains trusted Certificate Authorities for the Elasticsearch connection.").
			Default("").Envar("ES_CA").String()
		esClientPrivateKey = kingpin.Flag("es.client-private-key",
			"Path to PEM file that contains the private key for client auth when connecting to Elasticsearch.").
			Default("").Envar("ES_CLIENT_PRIVATE_KEY").String()
		esClientCert = kingpin.Flag("es.client-cert",
			"Path to PEM file that contains the corresponding cert for the private key to connect to Elasticsearch.").
			Default("").Envar("ES_CLIENT_CERT").String()
		esInsecureSkipVerify = kingpin.Flag("es.ssl-skip-verify",
			"Skip SSL verification when connecting to Elasticsearch.").
			Default("false").Envar("ES_SSL_SKIP_VERIFY").Bool()
		logLevel = kingpin.Flag("log.level",
			"Sets the loglevel. Valid levels are debug, info, warn, error").
			Default("info").Envar("LOG_LEVEL").String()
		logFormat = kingpin.Flag("log.format",
			"Sets the log format. Valid formats are json and logfmt").
			Default("logfmt").Envar("LOG_FMT").String()
		logOutput = kingpin.Flag("log.output",
			"Sets the log output. Valid outputs are stdout and stderr").
			Default("stdout").Envar("LOG_OUTPUT").String()
	)

	if *showVersion {
		fmt.Print(version.Print(Name))
		os.Exit(0)
	}

	logger := getLogger(*logLevel, *logOutput, *logFormat)

	esURL, err := url.Parse(*esURI)
	if err != nil {
		_ = level.Error(logger).Log(
			"msg", "failed to parse es.uri",
			"err", err,
		)
		os.Exit(1)
	}

	// returns nil if not provided and falls back to simple TCP.
	tlsConfig := createTLSConfig(*esCA, *esClientCert, *esClientPrivateKey, *esInsecureSkipVerify)

	httpClient := &http.Client{
		Timeout: *esTimeout,
		Transport: &http.Transport{
			TLSClientConfig: tlsConfig,
			Proxy:           http.ProxyFromEnvironment,
		},
	}

	// version metric
	versionMetric := version.NewCollector(Name)
	prometheus.MustRegister(versionMetric)

	// cluster info retriever
	clusterInfoRetriever := clusterinfo.New(logger, httpClient, esURL, *esClusterInfoInterval)

	prometheus.MustRegister(collector.NewClusterHealth(logger, httpClient, esURL))
	prometheus.MustRegister(collector.NewNodes(logger, httpClient, esURL, *esAllNodes, *esNode))

	if *esExportIndices || *esExportShards {
		indicesCollector := collector.NewIndices(logger, httpClient, esURL, *esExportShards)
		prometheus.MustRegister(indicesCollector)
		if err := clusterInfoRetriever.RegisterConsumer(indicesCollector); err != nil {
			level.Error(logger).Log("msg", "failed to register indices collector in cluster info")
			os.Exit(1)
		}
	}

	if *esExportSnapshots {
		prometheus.MustRegister(collector.NewSnapshots(logger, httpClient, esURL))
	}

	// create a http server
	server := &http.Server{}

	// create a context that is cancelled on SIGKILL
	ctx, cancel := context.WithCancel(context.Background())

	// start the cluster info retriever
	switch runErr := clusterInfoRetriever.Run(ctx); runErr {
	case nil:
		_ = level.Info(logger).Log(
			"msg", "started cluster info retriever",
			"interval", (*esClusterInfoInterval).String(),
		)
	case clusterinfo.ErrInitialCallTimeout:
		_ = level.Info(logger).Log("msg", "initial cluster info call timed out")
	default:
		_ = level.Error(logger).Log("msg", "failed to run cluster info retriever", "err", err)
		os.Exit(1)
	}

	// register cluster info retriever as prometheus collector
	prometheus.MustRegister(clusterInfoRetriever)

	mux := http.DefaultServeMux
	mux.Handle(*metricsPath, prometheus.Handler())
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, err = w.Write([]byte(`
			<title>Elasticsearch Exporter</title>

Elasticsearch Exporter

<a href="` + *metricsPath + `">Metrics

			`))
		if err != nil {
			_ = level.Error(logger).Log(
				"msg", "failed handling writer",
				"err", err,
			)
		}
	})

	server.Handler = mux
	server.Addr = *listenAddress

	_ = level.Info(logger).Log(
		"msg", "starting elasticsearch_exporter",
		"addr", *listenAddress,
	)

	go func() {
		if err := server.ListenAndServe(); err != nil {
			_ = level.Error(logger).Log(
				"msg", "http server quit",
				"err", err,
			)
		}
	}()

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

	// create a context for graceful http server shutdown
	srvCtx, srvCancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer srvCancel()
	<-c
	_ = level.Info(logger).Log("msg", "shutting down")
	_ = server.Shutdown(srvCtx)
	cancel()
}
<commit_msg>fix rebase accident, fmt<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"time"

	"context"

	"github.com/go-kit/kit/log/level"
	"github.com/justwatchcom/elasticsearch_exporter/collector"
	"github.com/justwatchcom/elasticsearch_exporter/pkg/clusterinfo"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
	"gopkg.in/alecthomas/kingpin.v2"
)

func main() {
	var (
		Name          = "elasticsearch_exporter"
		listenAddress = kingpin.Flag("web.listen-address",
			"Address to listen on for web interface and telemetry.").
			Default(":9114").Envar("WEB_LISTEN_ADDRESS").String()
		metricsPath = kingpin.Flag("web.telemetry-path",
			"Path under which to expose metrics.").
			Default("/metrics").Envar("WEB_TELEMETRY_PATH").String()
		esURI = kingpin.Flag("es.uri",
			"HTTP API address of an Elasticsearch node.").
			Default("http://localhost:9200").Envar("ES_URI").String()
		esTimeout = kingpin.Flag("es.timeout",
			"Timeout for trying to get stats from Elasticsearch.").
			Default("5s").Envar("ES_TIMEOUT").Duration()
		esAllNodes = kingpin.Flag("es.all",
			"Export stats for all nodes in the cluster. If used, this flag will override the flag es.node.").
			Default("false").Envar("ES_ALL").Bool()
		esNode = kingpin.Flag("es.node",
			"Node's name of which metrics should be exposed.").
			Default("_local").Envar("ES_NODE").String()
		esExportIndices = kingpin.Flag("es.indices",
			"Export stats for indices in the cluster.").
			Default("false").Envar("ES_INDICES").Bool()
		esExportIndicesSettings = kingpin.Flag("es.indices_settings",
			"Export stats for settings of all indices of the cluster.").
			Default("false").Envar("ES_INDICES_SETTINGS").Bool()
		esExportClusterSettings = kingpin.Flag("es.cluster_settings",
			"Export stats for cluster settings.").
			Default("false").Envar("ES_CLUSTER_SETTINGS").Bool()
		esExportShards = kingpin.Flag("es.shards",
			"Export stats for shards in the cluster (implies --es.indices).").
			Default("false").Envar("ES_SHARDS").Bool()
		esExportSnapshots = kingpin.Flag("es.snapshots",
			"Export stats for the cluster snapshots.").
			Default("false").Envar("ES_SNAPSHOTS").Bool()
		esClusterInfoInterval = kingpin.Flag("es.clusterinfo.interval",
			"Cluster info update interval for the cluster label").
			Default("5m").Envar("ES_CLUSTERINFO_INTERVAL").Duration()
		esCA = kingpin.Flag("es.ca",
			"Path to PEM file that contains trusted Certificate Authorities for the Elasticsearch connection.").
			Default("").Envar("ES_CA").String()
		esClientPrivateKey = kingpin.Flag("es.client-private-key",
			"Path to PEM file that contains the private key for client auth when connecting to Elasticsearch.").
			Default("").Envar("ES_CLIENT_PRIVATE_KEY").String()
		esClientCert = kingpin.Flag("es.client-cert",
			"Path to PEM file that contains the corresponding cert for the private key to connect to Elasticsearch.").
			Default("").Envar("ES_CLIENT_CERT").String()
		esInsecureSkipVerify = kingpin.Flag("es.ssl-skip-verify",
			"Skip SSL verification when connecting to Elasticsearch.").
			Default("false").Envar("ES_SSL_SKIP_VERIFY").Bool()
		logLevel = kingpin.Flag("log.level",
			"Sets the loglevel. Valid levels are debug, info, warn, error").
			Default("info").Envar("LOG_LEVEL").String()
		logFormat = kingpin.Flag("log.format",
			"Sets the log format. Valid formats are json and logfmt").
			Default("logfmt").Envar("LOG_FMT").String()
		logOutput = kingpin.Flag("log.output",
			"Sets the log output. Valid outputs are stdout and stderr").
			Default("stdout").Envar("LOG_OUTPUT").String()
	)

	if *showVersion {
		fmt.Print(version.Print(Name))
		os.Exit(0)
	}

	logger := getLogger(*logLevel, *logOutput, *logFormat)

	esURL, err := url.Parse(*esURI)
	if err != nil {
		_ = level.Error(logger).Log(
			"msg", "failed to parse es.uri",
			"err", err,
		)
		os.Exit(1)
	}

	// returns nil if not provided and falls back to simple TCP.
	tlsConfig := createTLSConfig(*esCA, *esClientCert, *esClientPrivateKey, *esInsecureSkipVerify)

	httpClient := &http.Client{
		Timeout: *esTimeout,
		Transport: &http.Transport{
			TLSClientConfig: tlsConfig,
			Proxy:           http.ProxyFromEnvironment,
		},
	}

	// version metric
	versionMetric := version.NewCollector(Name)
	prometheus.MustRegister(versionMetric)

	// cluster info retriever
	clusterInfoRetriever := clusterinfo.New(logger, httpClient, esURL, *esClusterInfoInterval)

	prometheus.MustRegister(collector.NewClusterHealth(logger, httpClient, esURL))
	prometheus.MustRegister(collector.NewNodes(logger, httpClient, esURL, *esAllNodes, *esNode))

	if *esExportIndices || *esExportShards {
		iC := collector.NewIndices(logger, httpClient, esURL, *esExportShards)
		prometheus.MustRegister(iC)
		if registerErr := clusterInfoRetriever.RegisterConsumer(iC); registerErr != nil {
			_ = level.Error(logger).Log("msg", "failed to register indices collector in cluster info")
			os.Exit(1)
		}
	}

	if *esExportClusterSettings {
		prometheus.MustRegister(collector.NewClusterSettings(logger, httpClient, esURL))
	}

	if *esExportSnapshots {
		prometheus.MustRegister(collector.NewSnapshots(logger, httpClient, esURL))
	}

	// create a http server
	server := &http.Server{}

	// create a context that is cancelled on SIGKILL
	ctx, cancel := context.WithCancel(context.Background())

	// start the cluster info retriever
	switch runErr := clusterInfoRetriever.Run(ctx); runErr {
	case nil:
		_ = level.Info(logger).Log(
			"msg", "started cluster info retriever",
			"interval", (*esClusterInfoInterval).String(),
		)
	case clusterinfo.ErrInitialCallTimeout:
		_ = level.Info(logger).Log("msg", "initial cluster info call timed out")
	default:
		_ = level.Error(logger).Log("msg", "failed to run cluster info retriever", "err", err)
		os.Exit(1)
	}

	// register cluster info retriever as prometheus collector
	prometheus.MustRegister(clusterInfoRetriever)

	mux := http.DefaultServeMux
	mux.Handle(*metricsPath, prometheus.Handler())
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, err = w.Write([]byte(`
			<title>Elasticsearch Exporter</title>

Elasticsearch Exporter

<a href="` + *metricsPath + `">Metrics

			`))
		if err != nil {
			_ = level.Error(logger).Log(
				"msg", "failed handling writer",
				"err", err,
			)
		}
	})

	server.Handler = mux
	server.Addr = *listenAddress

	_ = level.Info(logger).Log(
		"msg", "starting elasticsearch_exporter",
		"addr", *listenAddress,
	)

	go func() {
		if err := server.ListenAndServe(); err != nil {
			_ = level.Error(logger).Log(
				"msg", "http server quit",
				"err", err,
			)
		}
	}()

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

	// create a context for graceful http server shutdown
	srvCtx, srvCancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer srvCancel()
	<-c
	_ = level.Info(logger).Log("msg", "shutting down")
	_ = server.Shutdown(srvCtx)
	cancel()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/mgutz/logxi/v1"
)

var (
	arduinos      = flag.String("arduinos", "", "A list of the preferred arduino devices to be used")
	tecthulhus    = flag.String("tecthulhus", "http://127.0.0.1:12345", "A list of either a serial devices usb://dev/ttyAMA10, or http://IP:port numbers/ for the tecthulhu REST/JSon servers to watch")
	concAddress   = flag.String("concentrator", "", "The ZTCP/IP address of a Niantic concetrator if available")
	homeTecthulhu = flag.String("home", "Team NorCal", "The name of the portal which we wish to subscribe to and use to drive our arduinos")
	logLevel      = flag.String("loglevel", "warning", "Set the desired log level")
)

// create Logger interface
var logW = log.NewLogger(log.NewConcurrentWriter(os.Stdout), "pi-gateway")

func main() {

	flag.Parse()

	if len(*tecthulhus) == 0 {
		logW.Fatal("No tecthulhu TCP/IP or Serial USB modules were specified")
		os.Exit(-1)
	}

	// Wait until intialization is over before applying the log level
	logW.SetLevel(log.LevelInfo)

	switch strings.ToLower(*logLevel) {
	case "trace":
		logW.SetLevel(log.LevelTrace)
	case "debug":
		logW.SetLevel(log.LevelDebug)
	case "info":
		logW.SetLevel(log.LevelInfo)
	case "warning", "warn":
		logW.SetLevel(log.LevelWarn)
	case "error", "err":
		logW.SetLevel(log.LevelError)
	case "fatal":
		logW.SetLevel(log.LevelFatal)
	default:
		logW.Error("unrecognized log level specified")
	}

	quitC := make(chan bool, 1)

	// AUdio comes with 2 mixed channels of audio, ambientC is a looped
	// playback that will interrupt ambient playback as a new file name
	// is recieved, and sfxC is a single effect that will interrupt
	// any other playing sfx file
	ambientC := make(chan string, 1)
	sfxC := make(chan []string, 1)

	initAudio(ambientC, sfxC, quitC)

	// portals encapsulate a JSon data feed from ingress techthulu nodes
	//
	tectC := make(chan *portalStatus, 3)
	errorC := make(chan error, 1)

	portals := strings.Split(*tecthulhus, ",")

	if len(*concAddress) != 0 {
		conc := &concentrator{
			url:     *concAddress,
			statusC: tectC,
			errorC:  errorC,
		}
		go conc.startPortals(quitC)
	} else {
		tec := &tecthulhu{
			url:     portals[0],
			statusC: tectC,
			errorC:  errorC,
		}
		go tec.startPortals(quitC)
	}

	// Create a channel over which notifications will be sent for new
	// arduino devices that are detected, the gateway listens
	// for these and uses them for sending updates to the portal state
	//
	go plugAndPlay(quitC)

	// The gateway bridges the status reports from portals down to arduinos
	// using the serial protocols defined by the arduino team
	//
	go startGateway(*homeTecthulhu, tectC, ambientC, sfxC, quitC)

	// If someone presses ctrl C then close our quitc channel to shutdown the system
	// in an orderly way especially when dealing with device handles for the serial IO
	//
	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		select {
		case <-quitC:
		case <-sigC:
			close(quitC)
		}
	}()

	// Having started all of the IO interfaces concurrently simply loop
	// waiting for any changes in state while the processing occurs
	// in other threads
	for {
		select {
		case err := <-errorC:
			logW.Warn(err.Error())
		case <-quitC:
			for _, dev := range getRunningDevices(*homeTecthulhu) {
				stopRunningDevice(*homeTecthulhu, dev.devName)
				logW.Warn(fmt.Sprintf("closing portal %s attached to device %s acting as a %s", *homeTecthulhu, dev.devName, dev.role))
			}
			return
		}
	}
}
<commit_msg>Very minor typos<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/mgutz/logxi/v1"
)

var (
	arduinos      = flag.String("arduinos", "", "A list of the preferred arduino devices to be used")
	tecthulhus    = flag.String("tecthulhus", "http://127.0.0.1:12345", "A list of either a serial devices usb://dev/ttyAMA10, or http://IP:port numbers/ for the tecthulhu REST/JSon servers to watch")
	concAddress   = flag.String("concentrator", "", "The TCP/IP address of a Niantic concetrator if available")
	homeTecthulhu = flag.String("home", "Team NorCal", "The name of the portal which we wish to subscribe to and use to drive our arduinos")
	logLevel      = flag.String("loglevel", "warning", "Set the desired log level")
)

// create Logger interface
var logW = log.NewLogger(log.NewConcurrentWriter(os.Stdout), "pi-gateway")

func main() {

	flag.Parse()

	if len(*tecthulhus) == 0 {
		logW.Fatal("No tecthulhu TCP/IP or Serial USB modules were specified")
		os.Exit(-1)
	}

	// Wait until intialization is over before applying the log level
	logW.SetLevel(log.LevelInfo)

	// Retrieve the log level from the command line and translate it into the internal format
	switch strings.ToLower(*logLevel) {
	case "trace":
		logW.SetLevel(log.LevelTrace)
	case "debug":
		logW.SetLevel(log.LevelDebug)
	case "info":
		logW.SetLevel(log.LevelInfo)
	case "warning", "warn":
		logW.SetLevel(log.LevelWarn)
	case "error", "err":
		logW.SetLevel(log.LevelError)
	case "fatal":
		logW.SetLevel(log.LevelFatal)
	default:
		logW.Error("unrecognized log level specified")
	}

	quitC := make(chan bool, 1)

	// AUdio comes with 2 mixed channels of audio, ambientC is a looped
	// playback that will interrupt ambient playback as a new file name
	// is recieved, and sfxC is a single effect that will interrupt
	// any other playing sfx file
	ambientC := make(chan string, 1)
	sfxC := make(chan []string, 1)

	initAudio(ambientC, sfxC, quitC)

	// portals encapsulate a JSon data feed from ingress techthulu nodes
	//
	tectC := make(chan *portalStatus, 3)
	errorC := make(chan error, 1)

	portals := strings.Split(*tecthulhus, ",")

	if len(*concAddress) != 0 {
		conc := &concentrator{
			url:     *concAddress,
			statusC: tectC,
			errorC:  errorC,
		}
		go conc.startPortals(quitC)
	} else {
		tec := &tecthulhu{
			url:     portals[0],
			statusC: tectC,
			errorC:  errorC,
		}
		go tec.startPortals(quitC)
	}

	// Create a channel over which notifications will be sent for new
	// arduino devices that are detected, the gateway listens
	// for these and uses them for sending updates to the portal state
	//
	go plugAndPlay(quitC)

	// The gateway bridges the status reports from portals down to arduinos
	// using the serial protocols defined by the arduino team
	//
	go startGateway(*homeTecthulhu, tectC, ambientC, sfxC, quitC)

	// If someone presses ctrl C then close our quitc channel to shutdown the system
	// in an orderly way especially when dealing with device handles for the serial IO
	//
	sigC := make(chan os.Signal, 1)
	signal.Notify(sigC, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		select {
		case <-quitC:
		case <-sigC:
			close(quitC)
		}
	}()

	// Having started all of the IO interfaces concurrently simply loop
	// waiting for any changes in state while the processing occurs
	// in other threads
	for {
		select {
		case err := <-errorC:
			logW.Warn(err.Error())
		case <-quitC:
			for _, dev := range getRunningDevices(*homeTecthulhu) {
				stopRunningDevice(*homeTecthulhu, dev.devName)
				logW.Warn(fmt.Sprintf("closing portal %s attached to device %s acting as a %s", *homeTecthulhu, dev.devName, dev.role))
			}
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/asuleymanov/golos-go/client"
	"gopkg.in/telegram-bot-api.v4"

	"github.com/Chiliec/golos-vote-bot/db"
	"github.com/Chiliec/golos-vote-bot/models"
)

var (
	database *sql.DB
	logins   map[int]string
)

const (
	rpc   = "wss://ws.golos.io"
	chain = "golos"

	keyButtonText   = "🔑 Ключница"
	aboutButtonText = "🐞 О боте"

	groupLink = "https://t.me/joinchat/AlKeQUQpN8-9oShtaTcY7Q"
	groupID   = -1001143551951

	waitMinutes       = 5
	minimumVotesCount = 0
	defaultRating     = 10
)

var alreadyVotedError = errors.New("Уже проголосовали!")

func init() {
	db, err := db.InitDB("./db/database.db")
	if err != nil {
		log.Panic(err)
	}
	database = db
	logins = map[int]string{}
}

func main() {
	token := os.Getenv("TELEGRAM_TOKEN")
	if token == "" {
		log.Panic(errors.New("Нет токена"))
	}
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = false

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}
	for update := range updates {
		err := processMessage(bot, update)
		if err != nil {
			log.Println(err)
		}
	}
}

func processMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update) error {
	var chatID int64
	if update.Message != nil {
		chatID = update.Message.Chat.ID
	} else if update.CallbackQuery != nil {
		chatID = update.CallbackQuery.Message.Chat.ID
	} else {
		return errors.New("Не получили ID чата")
	}
	msg := tgbotapi.NewMessage(chatID, "")
	if update.Message != nil {
		regexp, err := regexp.Compile("https://golos.io/([-a-zA-Z0-9@:%_+.~#?&//=]{2,256})/@([-a-zA-Z0-9.]{2,256})/([-a-zA-Z0-9@:%_+.~#?&=]{2,256})")
		if err != nil {
			return err
		}
		switch {
		case update.Message.IsCommand():
			switch update.Message.Command() {
			case "start":
				keyButton := tgbotapi.NewKeyboardButton(keyButtonText)
				aboutButton := tgbotapi.NewKeyboardButton(aboutButtonText)
				buttons := []tgbotapi.KeyboardButton{keyButton, aboutButton}
				keyboard := tgbotapi.NewReplyKeyboard(buttons)
				msg.ReplyMarkup = keyboard
				msg.Text = fmt.Sprintf("Привет, %s!", update.Message.From.FirstName)
			}
		case update.Message.Text == keyButtonText:
			msg.Text = "Введите логин на Голосе"
			setWaitLogin(update.Message.From.ID)
		case update.Message.Text == aboutButtonText:
			msg.Text = "Бот для блого-социальной сети на блокчейне \"Голос\"\n" +
				"Нет времени голосовать, но хочется зарабатывать? Добавьте приватный постинг ключ и мы распорядимся вашей Силой голоса наилучшим образом!\n" +
				"Автор: @babin"
			forgetLogin(update.Message.From.ID)
		case regexp.MatchString(update.Message.Text):
			msg.ReplyToMessageID = update.Message.MessageID

			if update.Message.Chat.Type == "private" {
				msg.Text = "Присоединяйтесь к нашей группе: " + groupLink
				break
			}

			matched := regexp.FindStringSubmatch(update.Message.Text)
			author, permalink := matched[2], matched[3]

			percent := 5
			if update.Message.Chat.ID == groupID {
				percent = 100
			}

			voteModel := models.Vote{
				UserID:    update.Message.From.ID,
				Author:    author,
				Permalink: permalink,
				Percent:   percent,
			}

			if voteModel.Exists(database) {
				msg.Text = "Уже голосовал за этот пост!"
				break
			}

			voteID, err := voteModel.Save(database)
			if err != nil {
				log.Println("Error save vote model: " + err.Error())
				msg.Text = "Не смог проголосовать за пост"
				break
			}

			stringVoteID := strconv.Itoa(int(voteID))
			msg.Text = fmt.Sprintf("Голосование открыто. Завершение через %d минут", waitMinutes)
			goodButton := tgbotapi.NewInlineKeyboardButtonData("Хороший пост", stringVoteID+"_good")
			badButton := tgbotapi.NewInlineKeyboardButtonData("Плохой пост", stringVoteID+"_bad")
			buttons := []tgbotapi.InlineKeyboardButton{}
			buttons = append(buttons, goodButton)
			row := []tgbotapi.InlineKeyboardButton{goodButton, badButton}
			markup := tgbotapi.InlineKeyboardMarkup{}
			markup.InlineKeyboard = append(markup.InlineKeyboard, row)
			msg.ReplyMarkup = markup

			go func(voteModel models.Vote, chatID int64, userID int, messageID int, voteID int64) {
				select {
				case <-time.After(time.Second * 60 * waitMinutes):
					responses, err := models.GetAllResponsesForVoteID(voteID, database)
					if err != nil {
						log.Println("Ошибка получения голосований: " + err.Error())
					}
					var positives int
					var negatives int
					for _, response := range responses {
						if response.Result {
							positives = positives + 1
						} else {
							negatives = negatives + 1
						}
					}

					msg := tgbotapi.NewMessage(chatID, "")
					msg.ReplyToMessageID = messageID
					credential := models.Credential{UserID: update.Message.From.ID}

					if positives+negatives > minimumVotesCount {
						if positives > negatives {
							credential.IncrementRating(database)
							successVotes := vote(voteModel)
							msg.Text = fmt.Sprintf("Проголосовал с силой %d%% c %d аккаунтов", percent, successVotes)
						} else {
							credential.DecrementRating(database)
							rating, err := credential.GetRating(database)
							if err != nil {
								log.Println(err.Error())
							}
							if rating < 1 {
								memberConfig := tgbotapi.KickChatMemberConfig{
									ChatMemberConfig: tgbotapi.ChatMemberConfig{
										ChatID: chatID,
										UserID: userID,
									},
									UntilDate: 0,
								}
								bot.KickChatMember(memberConfig)
							}
							msg.Text = "Пост отклонен, рейтинг предлагающего снижен"
						}
					} else {
						msg.Text = "Недостаточно голосов для решения"
						// TODO: возможно стоит очистить голосование для возможности предложить заново
					}
					bot.Send(msg)
				}
			}(voteModel, update.Message.Chat.ID, update.Message.From.ID, update.Message.MessageID, voteID)
		default:
			if wait, login := isWaitingKey(update.Message.From.ID); wait {
				if login == "" {
					msg.Text = "Введите приватный ключ"
					setWaitKey(update.Message.From.ID, update.Message.Text)
				} else {
					credential := models.Credential{
						UserID:     update.Message.From.ID,
						UserName:   login,
						PostingKey: update.Message.Text,
						Rating:     defaultRating,
					}

					golos := client.NewApi(rpc, chain)
					if golos.Login(credential.UserName, credential.PostingKey) {
						result, err := credential.Save(database)
						if err != nil {
							log.Println(err.Error())
						}
						if result {
							msg.Text = "Логин и приватный ключ успешно сохранён! " +
								"Присоединяйтесь к нашей группе для участия в курировании: " + groupLink
						} else {
							msg.Text = "Не смог сохранить логин и приватный ключ :("
						}
					} else {
						msg.Text = "Логин и приватный ключ не совпадают :("
					}

					forgetLogin(update.Message.From.ID)
				}
			} else if update.Message.Chat.Type == "private" {
				msg.Text = "Не понимаю"
			}
		}
	} else if update.CallbackQuery != nil {
		log.Println(update.CallbackQuery)
		arr := strings.Split(update.CallbackQuery.Data, "_")
		voteID, err := strconv.Atoi(arr[0])
		if err != nil {
			return err
		}
		var result bool
		if arr[1] == "good" {
			result = true
		} else {
			result = false
		}
		response := models.Response{
			UserID: update.CallbackQuery.From.ID,
			VoteID: voteID,
			Result: result,
		}
		if response.Exists(database) {
			config := tgbotapi.CallbackConfig{
				CallbackQueryID: update.CallbackQuery.ID,
				Text:            "Вы уже голосовали!",
				ShowAlert:       true,
			}
			bot.AnswerCallbackQuery(config)
		} else {
			_, err := response.Save(database)
			if err != nil {
				return err
			}
			config := tgbotapi.CallbackConfig{
				CallbackQueryID: update.CallbackQuery.ID,
				Text:            "Голос принят",
				ShowAlert:       true,
			}
			bot.AnswerCallbackQuery(config)
		}
	}
	if msg.Text != "" {
		bot.Send(msg)
	}
	return nil
}

func forgetLogin(userID int) {
	delete(logins, userID)
}

func setWaitLogin(userID int) {
	logins[userID] = ""
}

func setWaitKey(userID int, login string) {
	logins[userID] = login
}

func isWaitingKey(userID int) (bool, string) {
	for id, login := range logins {
		if userID == id {
			return true, login
		}
	}
	return false, ""
}

func vote(vote models.Vote) int {
	credentials, err := models.GetAllCredentials(database)
	if err != nil {
		log.Println("Не смогли извлечь ключи из базы")
		return 0
	}
	for _, credential := range credentials {
		client.Key_List[credential.UserName] = client.Keys{PKey: credential.PostingKey}
	}
	log.Printf("Загружено %d аккаунтов", len(credentials))

	var errors []error
	var wg sync.WaitGroup
	wg.Add(len(credentials))
	for _, credential := range credentials {
		client.Key_List[credential.UserName] = client.Keys{PKey: credential.PostingKey}
		go func(credential models.Credential) {
			defer wg.Done()
			weight := vote.Percent * 100
			golos := client.NewApi(rpc, chain)
			err := golos.Vote(credential.UserName, vote.Author, vote.Permalink, weight)
			if err != nil {
				errors = append(errors, err)
			}
		}(credential)
	}
	wg.Wait()
	return len(credentials) - len(errors)
}
<commit_msg> Kick chat members when rating got down (#7)<commit_after>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/asuleymanov/golos-go/client"
	"github.com/go-telegram-bot-api/telegram-bot-api"

	"github.com/Chiliec/golos-vote-bot/db"
	"github.com/Chiliec/golos-vote-bot/models"
)

var (
	database *sql.DB
	logins   map[int]string
)

const (
	rpc   = "wss://ws.golos.io"
	chain = "golos"

	keyButtonText   = "🔑 Ключница"
	aboutButtonText = "🐞 О боте"

	groupLink = "https://t.me/joinchat/AlKeQUQpN8-9oShtaTcY7Q"
	groupID   = -1001143551951

	waitMinutes       = 5
	minimumVotesCount = 0
	defaultRating     = 10
)

var alreadyVotedError = errors.New("Уже проголосовали!")

func init() {
	db, err := db.InitDB("./db/database.db")
	if err != nil {
		log.Panic(err)
	}
	database = db
	logins = map[int]string{}
}

func main() {
	token := os.Getenv("TELEGRAM_TOKEN")
	if token == "" {
		log.Panic(errors.New("Нет токена"))
	}
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = false

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}
	for update := range updates {
		err := processMessage(bot, update)
		if err != nil {
			log.Println(err)
		}
	}
}

func processMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update) error {
	var chatID int64
	if update.Message != nil {
		chatID = update.Message.Chat.ID
	} else if update.CallbackQuery != nil {
		chatID = update.CallbackQuery.Message.Chat.ID
	} else {
		return errors.New("Не получили ID чата")
	}
	msg := tgbotapi.NewMessage(chatID, "")
	if update.Message != nil {
		regexp, err := regexp.Compile("https://golos.io/([-a-zA-Z0-9@:%_+.~#?&//=]{2,256})/@([-a-zA-Z0-9.]{2,256})/([-a-zA-Z0-9@:%_+.~#?&=]{2,256})")
		if err != nil {
			return err
		}
		switch {
		case update.Message.IsCommand():
			switch update.Message.Command() {
			case "start":
				keyButton := tgbotapi.NewKeyboardButton(keyButtonText)
				aboutButton := tgbotapi.NewKeyboardButton(aboutButtonText)
				buttons := []tgbotapi.KeyboardButton{keyButton, aboutButton}
				keyboard := tgbotapi.NewReplyKeyboard(buttons)
				msg.ReplyMarkup = keyboard
				msg.Text = fmt.Sprintf("Привет, %s!", update.Message.From.FirstName)
			}
		case update.Message.Text == keyButtonText:
			msg.Text = "Введите логин на Голосе"
			setWaitLogin(update.Message.From.ID)
		case update.Message.Text == aboutButtonText:
			msg.Text = "Бот для блого-социальной сети на блокчейне \"Голос\"\n" +
				"Нет времени голосовать, но хочется зарабатывать? Добавьте приватный постинг ключ и мы распорядимся вашей Силой голоса наилучшим образом!\n" +
				"Автор: @babin"
			forgetLogin(update.Message.From.ID)
		case regexp.MatchString(update.Message.Text):
			msg.ReplyToMessageID = update.Message.MessageID

			if update.Message.Chat.Type == "private" {
				msg.Text = "Присоединяйтесь к нашей группе: " + groupLink
				break
			}

			matched := regexp.FindStringSubmatch(update.Message.Text)
			author, permalink := matched[2], matched[3]

			percent := 5
			if update.Message.Chat.ID == groupID {
				percent = 100
			}

			voteModel := models.Vote{
				UserID:    update.Message.From.ID,
				Author:    author,
				Permalink: permalink,
				Percent:   percent,
			}

			if voteModel.Exists(database) {
				msg.Text = "Уже голосовал за этот пост!"
				break
			}

			voteID, err := voteModel.Save(database)
			if err != nil {
				log.Println("Error save vote model: " + err.Error())
				msg.Text = "Не смог проголосовать за пост"
				break
			}

			stringVoteID := strconv.Itoa(int(voteID))
			msg.Text = fmt.Sprintf("Голосование открыто. Завершение через %d минут", waitMinutes)
			goodButton := tgbotapi.NewInlineKeyboardButtonData("Хороший пост", stringVoteID+"_good")
			badButton := tgbotapi.NewInlineKeyboardButtonData("Плохой пост", stringVoteID+"_bad")
			buttons := []tgbotapi.InlineKeyboardButton{}
			buttons = append(buttons, goodButton)
			row := []tgbotapi.InlineKeyboardButton{goodButton, badButton}
			markup := tgbotapi.InlineKeyboardMarkup{}
			markup.InlineKeyboard = append(markup.InlineKeyboard, row)
			msg.ReplyMarkup = markup

			go func(voteModel models.Vote, chatID int64, userID int, messageID int, voteID int64) {
				select {
				case <-time.After(time.Second * 60 * waitMinutes):
					responses, err := models.GetAllResponsesForVoteID(voteID, database)
					if err != nil {
						log.Println("Ошибка получения голосований: " + err.Error())
					}
					var positives int
					var negatives int
					for _, response := range responses {
						if response.Result {
							positives = positives + 1
						} else {
							negatives = negatives + 1
						}
					}

					msg := tgbotapi.NewMessage(chatID, "")
					msg.ReplyToMessageID = messageID
					credential := models.Credential{UserID: update.Message.From.ID}

					if positives+negatives > minimumVotesCount {
						if positives > negatives {
							credential.IncrementRating(database)
							successVotes := vote(voteModel)
							msg.Text = fmt.Sprintf("Проголосовал с силой %d%% c %d аккаунтов", percent, successVotes)
						} else {
							credential.DecrementRating(database)
							rating, err := credential.GetRating(database)
							if err != nil {
								log.Println(err.Error())
							}
							if rating < 1 {
								memberConfig := tgbotapi.KickChatMemberConfig{
									ChatMemberConfig: tgbotapi.ChatMemberConfig{
										ChatID: chatID,
										UserID: userID,
									},
									UntilDate: 0,
								}
								bot.KickChatMember(memberConfig)
							}
							msg.Text = "Пост отклонен, рейтинг предлагающего снижен"
						}
					} else {
						msg.Text = "Недостаточно голосов для решения"
						// TODO: возможно стоит очистить голосование для возможности предложить заново
					}
					bot.Send(msg)
				}
			}(voteModel, update.Message.Chat.ID, update.Message.From.ID, update.Message.MessageID, voteID)
		default:
			if wait, login := isWaitingKey(update.Message.From.ID); wait {
				if login == "" {
					msg.Text = "Введите приватный ключ"
					setWaitKey(update.Message.From.ID, update.Message.Text)
				} else {
					credential := models.Credential{
						UserID:     update.Message.From.ID,
						UserName:   login,
						PostingKey: update.Message.Text,
						Rating:     defaultRating,
					}

					golos := client.NewApi(rpc, chain)
					if golos.Login(credential.UserName, credential.PostingKey) {
						result, err := credential.Save(database)
						if err != nil {
							log.Println(err.Error())
						}
						if result {
							msg.Text = "Логин и приватный ключ успешно сохранён! " +
								"Присоединяйтесь к нашей группе для участия в курировании: " + groupLink
						} else {
							msg.Text = "Не смог сохранить логин и приватный ключ :("
						}
					} else {
						msg.Text = "Логин и приватный ключ не совпадают :("
					}

					forgetLogin(update.Message.From.ID)
				}
			} else if update.Message.Chat.Type == "private" {
				msg.Text = "Не понимаю"
			}
		}
	} else if update.CallbackQuery != nil {
		log.Println(update.CallbackQuery)
		arr := strings.Split(update.CallbackQuery.Data, "_")
		voteID, err := strconv.Atoi(arr[0])
		if err != nil {
			return err
		}
		var result bool
		if arr[1] == "good" {
			result = true
		} else {
			result = false
		}
		response := models.Response{
			UserID: update.CallbackQuery.From.ID,
			VoteID: voteID,
			Result: result,
		}
		if response.Exists(database) {
			config := tgbotapi.CallbackConfig{
				CallbackQueryID: update.CallbackQuery.ID,
				Text:            "Вы уже голосовали!",
				ShowAlert:       true,
			}
			bot.AnswerCallbackQuery(config)
		} else {
			_, err := response.Save(database)
			if err != nil {
				return err
			}
			config := tgbotapi.CallbackConfig{
				CallbackQueryID: update.CallbackQuery.ID,
				Text:            "Голос принят",
				ShowAlert:       true,
			}
			bot.AnswerCallbackQuery(config)
		}
	}
	if msg.Text != "" {
		bot.Send(msg)
	}
	return nil
}

func forgetLogin(userID int) {
	delete(logins, userID)
}

func setWaitLogin(userID int) {
	logins[userID] = ""
}

func setWaitKey(userID int, login string) {
	logins[userID] = login
}

func isWaitingKey(userID int) (bool, string) {
	for id, login := range logins {
		if userID == id {
			return true, login
		}
	}
	return false, ""
}

func vote(vote models.Vote) int {
	credentials, err := models.GetAllCredentials(database)
	if err != nil {
		log.Println("Не смогли извлечь ключи из базы")
		return 0
	}
	for _, credential := range credentials {
		client.Key_List[credential.UserName] = client.Keys{PKey: credential.PostingKey}
	}
	log.Printf("Загружено %d аккаунтов", len(credentials))

	var errors []error
	var wg sync.WaitGroup
	wg.Add(len(credentials))
	for _, credential := range credentials {
		client.Key_List[credential.UserName] = client.Keys{PKey: credential.PostingKey}
		go func(credential models.Credential) {
			defer wg.Done()
			weight := vote.Percent * 100
			golos := client.NewApi(rpc, chain)
			err := golos.Vote(credential.UserName, vote.Author, vote.Permalink, weight)
			if err != nil {
				errors = append(errors, err)
			}
		}(credential)
	}
	wg.Wait()
	return len(credentials) - len(errors)
}
<|endoftext|>


<commit_before>// Copyright 2014 Prometheus Team
// 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 (
	"flag"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/prometheus/pushgateway/handler"
	"github.com/prometheus/pushgateway/storage"
)

var (
	listenAddress       = flag.String("web.listen-address", ":9091", "Address to listen on for the web interface, API, and telemetry.")
	metricsPath         = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	persistenceFile     = flag.String("persistence.file", "", "File to persist metrics. If empty, metrics are only kept in memory.")
	persistenceInterval = flag.Duration("persistence.interval", 5*time.Minute, "The minimum interval at which to write out the persistence file.")

	im = internalMetrics{
		{
			desc: prometheus.NewDesc(
				"runtime_goroutines_count",
				"Number of goroutines that currently exist.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(runtime.NumGoroutine()) },
			valType: prometheus.GaugeValue,
			// Not a counter, despite the name... It can go up and down.
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_allocated_bytes",
				"Bytes allocated and still in use.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_allocated_bytes_total",
				"Total bytes ever allocated (even if freed).",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
			valType: prometheus.CounterValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_heap_allocated_bytes",
				"Heap bytes allocated and still in use.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_high_watermark_bytes",
				"Next run in HeapAlloc time (bytes).",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_pause_ns",
				"Total GC pause time.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.PauseTotalNs) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_total",
				"Total number of GC runs.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NumGC) },
			valType: prometheus.CounterValue,
		},
	}
)

type internalMetrics []struct {
	desc    *prometheus.Desc
	eval    func(*runtime.MemStats) float64
	valType prometheus.ValueType
}

func (im internalMetrics) Describe(ch chan<- *prometheus.Desc) {
	for _, i := range im {
		ch <- i.desc
	}
}

func (im internalMetrics) Collect(ch chan<- prometheus.Metric) {
	memStats := &runtime.MemStats{}
	runtime.ReadMemStats(memStats)
	for _, i := range im {
		ch <- prometheus.MustNewConstMetric(i.desc, i.valType, i.eval(memStats))
	}
}

func main() {
	flag.Parse()
	versionInfoTmpl.Execute(os.Stdout, BuildInfo)
	flags := map[string]string{}
	flag.VisitAll(func(f *flag.Flag) {
		flags[f.Name] = f.Value.String()
	})

	ms := storage.NewDiskMetricStore(*persistenceFile, *persistenceInterval)
	prometheus.SetMetricFamilyInjectionHook(ms.GetMetricFamilies)

	prometheus.MustRegister(im)

	r := httprouter.New()
	r.Handler("GET", *metricsPath, prometheus.Handler())
	r.PUT("/metrics/jobs/:job/instances/:instance", handler.Push(ms, true))
	r.POST("/metrics/jobs/:job/instances/:instance", handler.Push(ms, false))
	r.DELETE("/metrics/jobs/:job/instances/:instance", handler.Delete(ms))
	r.PUT("/metrics/jobs/:job", handler.Push(ms, true))
	r.POST("/metrics/jobs/:job", handler.Push(ms, false))
	r.DELETE("/metrics/jobs/:job", handler.Delete(ms))
	r.Handler("GET", "/functions.js", prometheus.InstrumentHandlerFunc(
		"static",
		func(w http.ResponseWriter, _ *http.Request) {
			if b, err := Asset("resources/functions.js"); err == nil {
				w.Write(b)
			} else {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
		},
	))
	statusHandler := prometheus.InstrumentHandlerFunc("status", handler.Status(ms, Asset, flags, BuildInfo))
	r.Handler("GET", "/status", statusHandler)
	r.Handler("GET", "/", statusHandler)

	// Re-enable pprof.
	r.GET("/debug/pprof/*pprof", handlePprof)

	log.Printf("Listening on %s.\n", *addr)
	l, err := net.Listen("tcp", *addr)
	if err != nil {
		log.Fatal(err)
	}
	go interruptHandler(l)
	err = (&http.Server{Addr: *addr, Handler: r}).Serve(l)
	log.Print("HTTP server stopped: ", err)
	// To give running connections a chance to submit their payload, we wait
	// for 1sec, but we don't want to wait long (e.g. until all connections
	// are done) to not delay the shutdown.
	time.Sleep(time.Second)
	if err := ms.Shutdown(); err != nil {
		log.Print("Problem shutting down metric storage: ", err)
	}
}

func handlePprof(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	switch p.ByName("pprof") {
	case "/cmdline":
		pprof.Cmdline(w, r)
	case "/profile":
		pprof.Profile(w, r)
	case "/symbol":
		pprof.Symbol(w, r)
	default:
		pprof.Index(w, r)
	}
}

func interruptHandler(l net.Listener) {
	notifier := make(chan os.Signal)
	signal.Notify(notifier, os.Interrupt, syscall.SIGTERM)
	<-notifier
	log.Print("Received SIGINT/SIGTERM; exiting gracefully...")
	l.Close()
}
<commit_msg>Fix listenAddress variable references.<commit_after>// Copyright 2014 Prometheus Team
// 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 (
	"flag"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	"github.com/julienschmidt/httprouter"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/prometheus/pushgateway/handler"
	"github.com/prometheus/pushgateway/storage"
)

var (
	listenAddress       = flag.String("web.listen-address", ":9091", "Address to listen on for the web interface, API, and telemetry.")
	metricsPath         = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	persistenceFile     = flag.String("persistence.file", "", "File to persist metrics. If empty, metrics are only kept in memory.")
	persistenceInterval = flag.Duration("persistence.interval", 5*time.Minute, "The minimum interval at which to write out the persistence file.")

	im = internalMetrics{
		{
			desc: prometheus.NewDesc(
				"runtime_goroutines_count",
				"Number of goroutines that currently exist.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(runtime.NumGoroutine()) },
			valType: prometheus.GaugeValue,
			// Not a counter, despite the name... It can go up and down.
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_allocated_bytes",
				"Bytes allocated and still in use.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_allocated_bytes_total",
				"Total bytes ever allocated (even if freed).",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
			valType: prometheus.CounterValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_memory_heap_allocated_bytes",
				"Heap bytes allocated and still in use.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_high_watermark_bytes",
				"Next run in HeapAlloc time (bytes).",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_pause_ns",
				"Total GC pause time.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.PauseTotalNs) },
			valType: prometheus.GaugeValue,
		},
		{
			desc: prometheus.NewDesc(
				"runtime_gc_total",
				"Total number of GC runs.",
				nil, nil,
			),
			eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NumGC) },
			valType: prometheus.CounterValue,
		},
	}
)

type internalMetrics []struct {
	desc    *prometheus.Desc
	eval    func(*runtime.MemStats) float64
	valType prometheus.ValueType
}

func (im internalMetrics) Describe(ch chan<- *prometheus.Desc) {
	for _, i := range im {
		ch <- i.desc
	}
}

func (im internalMetrics) Collect(ch chan<- prometheus.Metric) {
	memStats := &runtime.MemStats{}
	runtime.ReadMemStats(memStats)
	for _, i := range im {
		ch <- prometheus.MustNewConstMetric(i.desc, i.valType, i.eval(memStats))
	}
}

func main() {
	flag.Parse()
	versionInfoTmpl.Execute(os.Stdout, BuildInfo)
	flags := map[string]string{}
	flag.VisitAll(func(f *flag.Flag) {
		flags[f.Name] = f.Value.String()
	})

	ms := storage.NewDiskMetricStore(*persistenceFile, *persistenceInterval)
	prometheus.SetMetricFamilyInjectionHook(ms.GetMetricFamilies)

	prometheus.MustRegister(im)

	r := httprouter.New()
	r.Handler("GET", *metricsPath, prometheus.Handler())
	r.PUT("/metrics/jobs/:job/instances/:instance", handler.Push(ms, true))
	r.POST("/metrics/jobs/:job/instances/:instance", handler.Push(ms, false))
	r.DELETE("/metrics/jobs/:job/instances/:instance", handler.Delete(ms))
	r.PUT("/metrics/jobs/:job", handler.Push(ms, true))
	r.POST("/metrics/jobs/:job", handler.Push(ms, false))
	r.DELETE("/metrics/jobs/:job", handler.Delete(ms))
	r.Handler("GET", "/functions.js", prometheus.InstrumentHandlerFunc(
		"static",
		func(w http.ResponseWriter, _ *http.Request) {
			if b, err := Asset("resources/functions.js"); err == nil {
				w.Write(b)
			} else {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
		},
	))
	statusHandler := prometheus.InstrumentHandlerFunc("status", handler.Status(ms, Asset, flags, BuildInfo))
	r.Handler("GET", "/status", statusHandler)
	r.Handler("GET", "/", statusHandler)

	// Re-enable pprof.
	r.GET("/debug/pprof/*pprof", handlePprof)

	log.Printf("Listening on %s.\n", *listenAddress)
	l, err := net.Listen("tcp", *listenAddress)
	if err != nil {
		log.Fatal(err)
	}
	go interruptHandler(l)
	err = (&http.Server{Addr: *listenAddress, Handler: r}).Serve(l)
	log.Print("HTTP server stopped: ", err)
	// To give running connections a chance to submit their payload, we wait
	// for 1sec, but we don't want to wait long (e.g. until all connections
	// are done) to not delay the shutdown.
	time.Sleep(time.Second)
	if err := ms.Shutdown(); err != nil {
		log.Print("Problem shutting down metric storage: ", err)
	}
}

func handlePprof(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	switch p.ByName("pprof") {
	case "/cmdline":
		pprof.Cmdline(w, r)
	case "/profile":
		pprof.Profile(w, r)
	case "/symbol":
		pprof.Symbol(w, r)
	default:
		pprof.Index(w, r)
	}
}

func interruptHandler(l net.Listener) {
	notifier := make(chan os.Signal)
	signal.Notify(notifier, os.Interrupt, syscall.SIGTERM)
	<-notifier
	log.Print("Received SIGINT/SIGTERM; exiting gracefully...")
	l.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
	"html"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

var dbHandle *sql.DB
var templates = template.Must(template.ParseFiles("index.html"))
var debugLogger *log.Logger

type Record struct {
	Category         string    `json: "category"`
	Records          []Records `json: "records"`
	QueryRecordCount int       `json: "queryRecordCount"`
	TotalRecordCount int       `json: "totalRecordCount"`
}

type Records struct {
	Id     string `json: "id"`
	Name   string `json: "name"`
	Status int    `json: "status"`
	Hash   string `json: "hash"`
	Magnet string `json: "magnet"`
}

func getDBHandle() *sql.DB {
	db, err := sql.Open("sqlite3", "./nyaa.db")
	checkErr(err)
	return db
}

func checkErr(err error) {
	if err != nil {
		debugLogger.Println("   " + err.Error())
		os.Exit(1)
	}
}

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

	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
func singleapiHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	id := vars["id"]
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents where torrent_id = ? ORDER BY torrent_id DESC", html.EscapeString(id))
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 1
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

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

func searchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	param1 := r.URL.Query().Get("q")
	cat := r.URL.Query().Get("c")
	param2 := strings.Split(cat, "_")[0]
	param3 := strings.Split(cat, "_")[1]
	b := Record{Category: cat, Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents "+
		"where torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ? "+
		"ORDER BY torrent_id DESC LIMIT 50 offset ?",
		"%"+html.EscapeString(param1)+"%", html.EscapeString(param2)+"%", html.EscapeString(param3)+"%", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	rows.Close()

	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Category: "_", Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

func main() {

	dbHandle = getDBHandle()
	router := mux.NewRouter()

	// Routes,
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/page/{page}", rootHandler)
	router.HandleFunc("/search", searchHandler)
	router.HandleFunc("/search/{page}", searchHandler)
	router.HandleFunc("/api/{page}", apiHandler).Methods("GET")
	router.HandleFunc("/api/torrent/{id}", singleapiHandler).Methods("GET")
	// Set up server,
	srv := &http.Server{
		Handler:      router,
		Addr:         "localhost:9999",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	err := srv.ListenAndServe()
	checkErr(err)
}
<commit_msg>fuck git<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
	"html"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

var dbHandle *sql.DB
var templates = template.Must(template.ParseFiles("index.html"))
var debugLogger *log.Logger

type Record struct {
	Category         string    `json: "category"`
	Records          []Records `json: "records"`
	QueryRecordCount int       `json: "queryRecordCount"`
	TotalRecordCount int       `json: "totalRecordCount"`
}

type Records struct {
	Id     string `json: "id"`
	Name   string `json: "name"`
	Status int    `json: "status"`
	Hash   string `json: "hash"`
	Magnet string `json: "magnet"`
}

func getDBHandle() *sql.DB {
	db, err := sql.Open("sqlite3", "./nyaa.db")
	checkErr(err)
	return db
}

func checkErr(err error) {
	if err != nil {
		debugLogger.Println("   " + err.Error())
		os.Exit(1)
	}
}

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

	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
func singleapiHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	id := vars["id"]
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents where torrent_id = ? ORDER BY torrent_id DESC", html.EscapeString(id))
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 1
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

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

func searchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	param1 := r.URL.Query().Get("q")
	cat := r.URL.Query().Get("c")
	param2 := strings.Split(cat, "_")[0]
	param3 := strings.Split(cat, "_")[1]
	b := Record{Category: cat, Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents "+
		"where torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ? "+
		"ORDER BY torrent_id DESC LIMIT 50 offset ?",
		"%"+html.EscapeString(param1)+"%", html.EscapeString(param2)+"%", html.EscapeString(param3)+"%", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	rows.Close()

	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Category: "_", Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

func main() {

	dbHandle = getDBHandle()
	router := mux.NewRouter()

	// Routes,
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/page/{page}", rootHandler)
	router.HandleFunc("/search", searchHandler)
	router.HandleFunc("/search/{page}", searchHandler)
	router.HandleFunc("/api/{page}", apiHandler).Methods("GET")
	router.HandleFunc("/api/torrent/{id}", singleapiHandler).Methods("GET")
	// Set up server,
	srv := &http.Server{
		Handler:      router,
		Addr:         "localhost:9999",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	err := srv.ListenAndServe()
	checkErr(err)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Brian McCallister
 *
 * 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 (
	"github.com/codegangsta/martini"
	"github.com/martini-contrib/render"
)

func main() {
	m := martini.Classic()
	m.Use(render.Renderer())

	m.Get("/", func(r render.Render) {
		r.JSON(200, person{
			Name: "World",
			Age:  6,
		})
	})

	m.Get("/:name", func(p martini.Params, r render.Render) {
		r.JSON(200, person{
			Name: p["name"],
			Age:  39,
		})
	})

	m.Run()
}

type person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}
<commit_msg>actually proxy :-)<commit_after>/*
 * Copyright 2014 Brian McCallister
 *
 * 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 (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)

func main() {
	http.HandleFunc("/", Proxy)
	err := http.ListenAndServe(":12345", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func Proxy(rw http.ResponseWriter, req *http.Request) {
	log.Printf("got request!")
	url, err := url.Parse("http://127.0.0.1:4001/")
	if err != nil {
		log.Fatalf("Error parsing url: %s", err)
	}
	rp := httputil.NewSingleHostReverseProxy(url)
	rp.ServeHTTP(rw, req)
}
<|endoftext|>


<commit_before>/* ELF tree - Tree viewer for ELF library dependency */
package main

import (
	"bufio"
	"debug/elf"
	"encoding/binary"
	"flag"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
)

type DepsNode struct {
	name   string
	parent *DepsNode
	child  []*DepsNode
	depth  int
}

type DepsInfo struct {
	path   string
	mach   elf.Machine
	bits   elf.Class
	endian binary.ByteOrder
	kind   elf.Type
	abi    elf.OSABI
	ver    uint8

	libs []string
	dsym []elf.ImportedSymbol
	syms []elf.Symbol
	prog []*elf.Prog
}

var (
	deps      map[string]DepsInfo
	deps_list []*DepsNode
	deps_root *DepsNode
	deflib    []string
	envlib    string
	conflib   []string
)

// command-line options
var (
	verbose  bool
	showPath bool
	showTui  bool
)

func readLdSoConf(name string, libpath []string) {
	f, err := os.Open(name)
	if err != nil {
		return
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		t := s.Text()

		if len(strings.TrimSpace(t)) == 0 {
			continue
		}
		if strings.HasPrefix(t, "#") {
			continue
		}

		if strings.HasPrefix(t, "include") {
			libs, err := filepath.Glob(t[8:])
			if err != nil {
				continue
			}
			for _, l := range libs {
				readLdSoConf(l, libpath)
			}
		} else {
			libpath = append(libpath, t)
		}
	}
}

func init() {
	deps = make(map[string]DepsInfo)
	deflib = []string{"/lib/", "/usr/lib/"}
	envlib = os.Getenv("LD_LIBRARY_PATH")
	readLdSoConf("/etc/ld.so.conf", conflib)

	flag.BoolVar(&verbose, "v", false, "Show binary info")
	flag.BoolVar(&showPath, "p", false, "Show library path")
	flag.BoolVar(&showTui, "tui", false, "Show it with TUI")
}

func findLib(name string) string {
	if strings.Contains(name, "/") {
		return name
	}

	// check LD_LIBRARY_PATH environ
	for _, libpath := range strings.Split(envlib, ":") {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check libraries in /etc/ld.so.conf
	for _, libpath := range conflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check default library directories
	for _, libpath := range deflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}
	return ""
}

func realPath(pathname string) string {
	if pathname == "" {
		return ""
	}

	relpath, _ := filepath.EvalSymlinks(pathname)
	abspath, _ := filepath.Abs(relpath)

	return abspath
}

func processDep(dep *DepsNode) {
	// skip duplicate libraries
	if _, ok := deps[dep.name]; ok {
		return
	}

	info := DepsInfo{path: realPath(findLib(dep.name))}

	if dep.parent == nil {
		info.path = realPath(flag.Args()[0])
	}

	f, err := elf.Open(info.path)
	if err != nil {
		fmt.Printf("%v: %s\n", err, info.path)
		os.Exit(1)
	}
	defer f.Close()

	info.mach = f.Machine
	info.bits = f.Class
	info.kind = f.Type
	info.abi = f.OSABI
	info.ver = f.ABIVersion
	info.endian = f.ByteOrder

	info.prog = f.Progs

	libs, err := f.ImportedLibraries()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	dsym, err := f.ImportedSymbols()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	syms, err := f.Symbols()
	if err == nil {
		info.syms = syms
	}

	info.libs = libs
	info.dsym = dsym

	var L []*DepsNode
	for _, soname := range libs {
		N := new(DepsNode)
		N.name = soname
		N.parent = dep
		N.depth = dep.depth + 1

		L = append(L, N)
		dep.child = append(dep.child, N)
	}

	deps_list = append(L, deps_list...)
	deps[dep.name] = info
}

func printDepTree(n *DepsNode, f *elf.File) {
	for i := 0; i < n.depth; i++ {
		fmt.Printf("   ")
	}

	if showPath {
		fmt.Printf("%s  => %s\n", n.name, deps[n.name].path)
	} else {
		fmt.Println(n.name)
	}

	for _, v := range n.child {
		printDepTree(v, f)
	}

	if verbose && n.parent == nil {
		showDetails(f, deps[n.name].path)
	}
}

func showDetails(f *elf.File, pathname string) {
	s := f.Section(".interp")
	if s == nil {
		fmt.Printf("static linked executable: %s\n", pathname)
		os.Exit(1)
	}
	interp, err := s.Data()
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}

	di_deps, err := f.ImportedLibraries()
	if err != nil {
		fmt.Printf("imported libraries: %v\n", err)
		os.Exit(1)
	}

	fmt.Println()
	fmt.Printf("%s: %s\n", path.Base(pathname), realPath(pathname))
	fmt.Printf("  type:                     %s  (%s / %s / %s)\n",
		f.Type, f.Machine, f.Class, f.ByteOrder)
	fmt.Printf("  interpreter:              %s\n", string(interp))
	fmt.Printf("  total dependency:         %d\n", len(deps)-1) // exclude itself
	fmt.Printf("  direct dependency:        %d\n", len(di_deps))
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		fmt.Println("Usage: elftree [<options>] <executable>")
		os.Exit(1)
	}

	pathname := args[0]
	f, err := elf.Open(pathname)
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}
	defer f.Close()

	deps_root = new(DepsNode)
	deps_root.name = path.Base(pathname)

	deps_list = append(deps_list, deps_root)
	for len(deps_list) > 0 {
		// pop first element
		dep := deps_list[0]
		deps_list = deps_list[1:]

		processDep(dep)
	}

	if showTui {
		ShowWithTUI(deps_root)
	} else {
		printDepTree(deps_root, f)
	}
}
<commit_msg>Show filename when it fails to open for processing<commit_after>/* ELF tree - Tree viewer for ELF library dependency */
package main

import (
	"bufio"
	"debug/elf"
	"encoding/binary"
	"flag"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
)

type DepsNode struct {
	name   string
	parent *DepsNode
	child  []*DepsNode
	depth  int
}

type DepsInfo struct {
	path   string
	mach   elf.Machine
	bits   elf.Class
	endian binary.ByteOrder
	kind   elf.Type
	abi    elf.OSABI
	ver    uint8

	libs []string
	dsym []elf.ImportedSymbol
	syms []elf.Symbol
	prog []*elf.Prog
}

var (
	deps      map[string]DepsInfo
	deps_list []*DepsNode
	deps_root *DepsNode
	deflib    []string
	envlib    string
	conflib   []string
)

// command-line options
var (
	verbose  bool
	showPath bool
	showTui  bool
)

func readLdSoConf(name string, libpath []string) {
	f, err := os.Open(name)
	if err != nil {
		return
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		t := s.Text()

		if len(strings.TrimSpace(t)) == 0 {
			continue
		}
		if strings.HasPrefix(t, "#") {
			continue
		}

		if strings.HasPrefix(t, "include") {
			libs, err := filepath.Glob(t[8:])
			if err != nil {
				continue
			}
			for _, l := range libs {
				readLdSoConf(l, libpath)
			}
		} else {
			libpath = append(libpath, t)
		}
	}
}

func init() {
	deps = make(map[string]DepsInfo)
	deflib = []string{"/lib/", "/usr/lib/"}
	envlib = os.Getenv("LD_LIBRARY_PATH")
	readLdSoConf("/etc/ld.so.conf", conflib)

	flag.BoolVar(&verbose, "v", false, "Show binary info")
	flag.BoolVar(&showPath, "p", false, "Show library path")
	flag.BoolVar(&showTui, "tui", false, "Show it with TUI")
}

func findLib(name string) string {
	if strings.Contains(name, "/") {
		return name
	}

	// check LD_LIBRARY_PATH environ
	for _, libpath := range strings.Split(envlib, ":") {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check libraries in /etc/ld.so.conf
	for _, libpath := range conflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}

	// check default library directories
	for _, libpath := range deflib {
		fullpath := path.Join(libpath, name)
		if _, err := os.Stat(fullpath); err == nil {
			return fullpath
		}
	}
	return ""
}

func realPath(pathname string) string {
	if pathname == "" {
		return ""
	}

	relpath, _ := filepath.EvalSymlinks(pathname)
	abspath, _ := filepath.Abs(relpath)

	return abspath
}

func processDep(dep *DepsNode) {
	// skip duplicate libraries
	if _, ok := deps[dep.name]; ok {
		return
	}

	info := DepsInfo{path: realPath(findLib(dep.name))}

	if dep.parent == nil {
		info.path = realPath(flag.Args()[0])
	}

	f, err := elf.Open(info.path)
	if err != nil {
		fmt.Printf("%v: %s (%s)\n", err, info.path, dep.name)
		os.Exit(1)
	}
	defer f.Close()

	info.mach = f.Machine
	info.bits = f.Class
	info.kind = f.Type
	info.abi = f.OSABI
	info.ver = f.ABIVersion
	info.endian = f.ByteOrder

	info.prog = f.Progs

	libs, err := f.ImportedLibraries()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	dsym, err := f.ImportedSymbols()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	syms, err := f.Symbols()
	if err == nil {
		info.syms = syms
	}

	info.libs = libs
	info.dsym = dsym

	var L []*DepsNode
	for _, soname := range libs {
		N := new(DepsNode)
		N.name = soname
		N.parent = dep
		N.depth = dep.depth + 1

		L = append(L, N)
		dep.child = append(dep.child, N)
	}

	deps_list = append(L, deps_list...)
	deps[dep.name] = info
}

func printDepTree(n *DepsNode, f *elf.File) {
	for i := 0; i < n.depth; i++ {
		fmt.Printf("   ")
	}

	if showPath {
		fmt.Printf("%s  => %s\n", n.name, deps[n.name].path)
	} else {
		fmt.Println(n.name)
	}

	for _, v := range n.child {
		printDepTree(v, f)
	}

	if verbose && n.parent == nil {
		showDetails(f, deps[n.name].path)
	}
}

func showDetails(f *elf.File, pathname string) {
	s := f.Section(".interp")
	if s == nil {
		fmt.Printf("static linked executable: %s\n", pathname)
		os.Exit(1)
	}
	interp, err := s.Data()
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}

	di_deps, err := f.ImportedLibraries()
	if err != nil {
		fmt.Printf("imported libraries: %v\n", err)
		os.Exit(1)
	}

	fmt.Println()
	fmt.Printf("%s: %s\n", path.Base(pathname), realPath(pathname))
	fmt.Printf("  type:                     %s  (%s / %s / %s)\n",
		f.Type, f.Machine, f.Class, f.ByteOrder)
	fmt.Printf("  interpreter:              %s\n", string(interp))
	fmt.Printf("  total dependency:         %d\n", len(deps)-1) // exclude itself
	fmt.Printf("  direct dependency:        %d\n", len(di_deps))
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		fmt.Println("Usage: elftree [<options>] <executable>")
		os.Exit(1)
	}

	pathname := args[0]
	f, err := elf.Open(pathname)
	if err != nil {
		fmt.Printf("%v: %s\n", err, pathname)
		os.Exit(1)
	}
	defer f.Close()

	deps_root = new(DepsNode)
	deps_root.name = path.Base(pathname)

	deps_list = append(deps_list, deps_root)
	for len(deps_list) > 0 {
		// pop first element
		dep := deps_list[0]
		deps_list = deps_list[1:]

		processDep(dep)
	}

	if showTui {
		ShowWithTUI(deps_root)
	} else {
		printDepTree(deps_root, f)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"

	"github.com/Sirupsen/logrus"
	flags "github.com/jessevdk/go-flags"
)

type GlobalOptions struct {
	Quiet   func(string) `env:"HLN_QUIET" short:"q" long:"quiet" description:"Show as little information as possible."`
	Verbose func(string) `env:"HLN_VERBOSE" short:"v" long:"verbose" description:"Show verbose debug information."`
	LogJSON func(string) `env:"HLN_LOG_JSON" short:"j" long:"log-json" description:"Log in JSON format."`
}

type InlineOptions struct {
	Verbose func(string) `env:"HLN_VERBOSE" long:"hln-verbose" description:"Show verbose debug information."`
	LogJSON func(string) `env:"HLN_LOG_JSON" long:"hln-log-json" description:"Log in JSON format."`
}

var globalOptions GlobalOptions
var inlineOptions InlineOptions

var parser = flags.NewParser(&globalOptions, flags.Default)
var inlineParser = flags.NewParser(&inlineOptions, flags.PrintErrors|flags.IgnoreUnknown)
var originalArgs []string

func main() {
	basename := path.Base(os.Args[0])
	utilityNameOverride := os.Getenv("HLN_UTILITY")

	logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
	if (basename == "holen" || basename == "hln") && len(utilityNameOverride) == 0 {

		// configure logging
		logrus.SetLevel(logrus.InfoLevel)

		// options to change log level
		globalOptions.Quiet = func(v string) {
			logrus.SetLevel(logrus.WarnLevel)
		}
		globalOptions.Verbose = func(v string) {
			logrus.SetLevel(logrus.DebugLevel)
		}
		globalOptions.LogJSON = func(v string) {
			logrus.SetFormatter(&logrus.JSONFormatter{})
		}

		if _, err := parser.Parse(); err != nil {
			os.Exit(1)
		}
	} else {

		// configure logging
		logrus.SetLevel(logrus.WarnLevel)

		// options to change log level
		inlineOptions.Verbose = func(v string) {
			logrus.SetLevel(logrus.DebugLevel)
		}
		inlineOptions.LogJSON = func(v string) {
			logrus.SetFormatter(&logrus.JSONFormatter{})
		}

		args, err := inlineParser.Parse()
		if err != nil {
			os.Exit(1)
		}

		if len(utilityNameOverride) > 0 {
			basename = utilityNameOverride
		}

		err = RunUtility(basename, args)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<commit_msg>make top level error message a little friendlier<commit_after>package main

import (
	"fmt"
	"os"
	"path"

	"github.com/Sirupsen/logrus"
	flags "github.com/jessevdk/go-flags"
)

type GlobalOptions struct {
	Quiet   func(string) `env:"HLN_QUIET" short:"q" long:"quiet" description:"Show as little information as possible."`
	Verbose func(string) `env:"HLN_VERBOSE" short:"v" long:"verbose" description:"Show verbose debug information."`
	LogJSON func(string) `env:"HLN_LOG_JSON" short:"j" long:"log-json" description:"Log in JSON format."`
}

type InlineOptions struct {
	Verbose func(string) `env:"HLN_VERBOSE" long:"hln-verbose" description:"Show verbose debug information."`
	LogJSON func(string) `env:"HLN_LOG_JSON" long:"hln-log-json" description:"Log in JSON format."`
}

var globalOptions GlobalOptions
var inlineOptions InlineOptions

var parser = flags.NewParser(&globalOptions, flags.Default)
var inlineParser = flags.NewParser(&inlineOptions, flags.PrintErrors|flags.IgnoreUnknown)
var originalArgs []string

func main() {
	basename := path.Base(os.Args[0])
	utilityNameOverride := os.Getenv("HLN_UTILITY")

	logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
	if (basename == "holen" || basename == "hln") && len(utilityNameOverride) == 0 {

		// configure logging
		logrus.SetLevel(logrus.InfoLevel)

		// options to change log level
		globalOptions.Quiet = func(v string) {
			logrus.SetLevel(logrus.WarnLevel)
		}
		globalOptions.Verbose = func(v string) {
			logrus.SetLevel(logrus.DebugLevel)
		}
		globalOptions.LogJSON = func(v string) {
			logrus.SetFormatter(&logrus.JSONFormatter{})
		}

		if _, err := parser.Parse(); err != nil {
			os.Exit(1)
		}
	} else {

		// configure logging
		logrus.SetLevel(logrus.WarnLevel)

		// options to change log level
		inlineOptions.Verbose = func(v string) {
			logrus.SetLevel(logrus.DebugLevel)
		}
		inlineOptions.LogJSON = func(v string) {
			logrus.SetFormatter(&logrus.JSONFormatter{})
		}

		args, err := inlineParser.Parse()
		if err != nil {
			os.Exit(1)
		}

		if len(utilityNameOverride) > 0 {
			basename = utilityNameOverride
		}

		err = RunUtility(basename, args)
		if err != nil {
			fmt.Printf("Unable to run %s: %s\n", basename, err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"os/signal"
	"time"

	pb "github.com/noffle/ipget/Godeps/_workspace/src/github.com/cheggaaa/pb"
	humanize "github.com/noffle/ipget/Godeps/_workspace/src/github.com/dustin/go-humanize"
	core "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/core"
	path "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/path"
	uarchive "github.com/noffle/ipget/Godeps/_workspace/src/github.com/ipfs/go-ipfs/unixfs/archive"
	cli "github.com/noffle/ipget/Godeps/_workspace/src/github.com/jawher/mow.cli"
	tar "github.com/noffle/ipget/Godeps/_workspace/src/github.com/whyrusleeping/tar-utils"
	context "github.com/noffle/ipget/Godeps/_workspace/src/golang.org/x/net/context"
)

func main() {
	cmd := cli.App("ipget", "Retrieve and save IPFS objects.")
	cmd.Spec = "IPFS_PATH [-o]"

	hash := cmd.String(cli.StringArg{
		Name:  "IPFS_PATH",
		Value: "",
		Desc:  "the IPFS object path",
	})

	outFile := cmd.StringOpt("o output", "", "output file path")

	cmd.Action = func() {
		// Use the final segment of the object's path if no path was given.
		if *outFile == "" {
			ipfsPath, err := path.ParsePath(*hash)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ParsePath failure: %s", err)
				os.Exit(1)
			}
			segments := ipfsPath.Segments()
			*outFile = segments[len(segments)-1]
		}

		if err := get(*hash, *outFile); err != nil {
			os.Remove(*outFile)
			fmt.Fprintf(os.Stderr, "ipget failed: %s\n", err)
			os.Exit(2)
		}
	}
	cmd.Run(os.Args)
}

func get(path, outFile string) error {
	start := time.Now()
	ctx, cancel := context.WithCancel(context.Background())

	// Cancel the ipfs node context if the process gets interrupted or killed.
	go func() {
		interrupts := make(chan os.Signal, 1)
		signal.Notify(interrupts, os.Interrupt, os.Kill)
		<-interrupts
		cancel()
	}()

	// Create the ipfs node.
	node, err := core.NewNode(ctx, &core.BuildCfg{
		Online: true,
	})
	if err != nil {
		return fmt.Errorf("ipfs NewNode() failed: %s", err)
	}

	// Bootstrap.
	err = node.Bootstrap(core.DefaultBootstrapConfig)
	if err != nil {
		return fmt.Errorf("node Bootstrap() failed: %s", err)
	}
	fmt.Fprintf(os.Stderr, "IPFS Node bootstrapping (took %v)\n", time.Since(start))

	// Get a reader for downloading the object content.
	reader, length, err := cat(node.Context(), node, path)
	if err != nil {
		return fmt.Errorf("cat failed: %s", err)
	}

	bar, barR := progressBarForReader(os.Stderr, reader, int(length))
	bar.ShowSpeed = false
	bar.Start()

	// Stream the file content from the IPFS node to the output file.
	extractor := &tar.Extractor{outFile}
	if err := extractor.Extract(barR); err != nil {
		return fmt.Errorf("copy failed: %s", err)
	}

	// Done!
	bar.Finish()
	fmt.Fprintf(os.Stderr, "Wrote %q to %q (%s) (took %v)\n", path, outFile,
		humanize.Bytes(length), time.Since(start))

	return nil
}

func cat(ctx context.Context, node *core.IpfsNode, fpath string) (io.Reader, uint64, error) {
	dagnode, err := core.Resolve(ctx, node, path.Path(fpath))
	if err != nil {
		return nil, 0, err
	}

	reader, err := uarchive.DagArchive(node.Context(), dagnode, fpath, node.DAG, false, 0)
	if err != nil {
		return nil, 0, err
	}

	// TODO: modify uarchive.DagArchive to output pb size
	length, err := dagnode.Size()
	if err != nil {
		return nil, 0, err
	}
	return reader, length, nil
}

func progressBarForReader(out io.Writer, r io.Reader, l int) (*pb.ProgressBar, *pb.Reader) {
	// setup bar reader
	bar := pb.New(l).SetUnits(pb.U_BYTES)
	bar.Output = out
	barR := bar.NewProxyReader(r)
	return bar, barR
}
<commit_msg>Uses noffle/fallback-ipfs-shell for get'ting.<commit_after>package main

import (
	"fmt"
	"os"

	path "github.com/ipfs/go-ipfs/path"
	cli "github.com/jawher/mow.cli"
	fallback "github.com/noffle/fallback-ipfs-shell"
)

func main() {
	cmd := cli.App("ipget", "Retrieve and save IPFS objects.")
	cmd.Spec = "IPFS_PATH [-o]"

	hash := cmd.String(cli.StringArg{
		Name:  "IPFS_PATH",
		Value: "",
		Desc:  "the IPFS object path",
	})

	outFile := cmd.StringOpt("o output", "", "output file path")

	cmd.Action = func() {
		// Use the final segment of the object's path if no path was given.
		if *outFile == "" {
			ipfsPath, err := path.ParsePath(*hash)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ParsePath failure: %s", err)
				os.Exit(1)
			}
			segments := ipfsPath.Segments()
			*outFile = segments[len(segments)-1]
		}

		shell, err := fallback.NewShell()
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err)
			os.Exit(1)
		}

		if err = shell.Get(*hash, *outFile); err != nil {
			os.Remove(*outFile)
			fmt.Fprintf(os.Stderr, "ipget failed: %s\n", err)
			os.Exit(2)
		}
	}
	cmd.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/google/go-github/github"
)

type Contribution struct {
	Date time.Time
	Num  int
}

func (c *Contribution) UnmarshalJSON(data []byte) error {
	var i []interface{}
	err := json.Unmarshal(data, &i)
	if err != nil {
		return err
	}

	if v, ok := i[0].(string); ok {
		c.Date, err = time.Parse("2006-01-02", v)
	}
	if err != nil {
		return err
	}

	if v, ok := i[1].(float64); ok {
		c.Num = int(v)
	}

	return nil
}

func getContributions(user github.User) []Contribution {
	login := github.Stringify(user.Login)
	url := "https://github.com/users/" + login[1:len(login)-1] + "/contributions"
	var contribData []Contribution

	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if data == nil {
		log.Fatalln("No data returned.")
	}

	err = json.Unmarshal(data, &contribData)
	if err != nil {
		log.Fatal(err)
	}

	return contribData
}

func getOrgMembers(orgName string) []github.User {
	client := github.NewClient(nil)

	users, _, err := client.Organizations.ListMembers(orgName, nil)
	if err != nil {
		log.Fatal(err)
	}

	return users
}

func main() {
	users := getOrgMembers("linode")
	userData := make(chan []Contribution, len(users))

	go func() {
		for {
			contribution, more := <-userData
			if more {
				fmt.Println(contribution)
			} else {
				return
			}
		}
	}()

	for _, user := range users {
		userData <- getContributions(user)
	}
	close(userData)
}
<commit_msg>take all the contributions and put them in a map<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/google/go-github/github"
)

type Contribution struct {
	Date time.Time
	Num  int
}

type orgContributions map[time.Time]int

func (c *Contribution) UnmarshalJSON(data []byte) error {
	var i []interface{}
	err := json.Unmarshal(data, &i)
	if err != nil {
		return err
	}

	if v, ok := i[0].(string); ok {
		c.Date, err = time.Parse("2006-01-02", v)
	}
	if err != nil {
		return err
	}

	if v, ok := i[1].(float64); ok {
		c.Num = int(v)
	}

	return nil
}

func getContributions(user github.User) []Contribution {
	login := github.Stringify(user.Login)
	url := "https://github.com/users/" + login[1:len(login)-1] + "/contributions"
	var contribData []Contribution

	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if data == nil {
		log.Fatalln("No data returned.")
	}

	err = json.Unmarshal(data, &contribData)
	if err != nil {
		log.Fatal(err)
	}

	return contribData
}

func getOrgMembers(orgName string) []github.User {
	client := github.NewClient(nil)

	users, _, err := client.Organizations.ListMembers(orgName, nil)
	if err != nil {
		log.Fatal(err)
	}

	return users
}

func main() {
	users := getOrgMembers("linode")
	orgContribMap := make(orgContributions)

	for _, user := range users {
		func() {
			for _, contrib := range getContributions(user) {
				orgContribMap[contrib.Date] += contrib.Num
			}
		}()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os/user"
	"path"
	"runtime"

	"code.google.com/p/getopt"
)

const PROGNAME string = "Fireman"
const PROGVERSION string = "0.1.0"

func main() {
	u, err := user.Current()
	if err != nil {
		f("Error: Couldn't get current user - %s", err.Error())
	}
	home := u.HomeDir
	system := runtime.GOOS
	if system == "darwin" {
		home = path.Join(home, "Library", "Preferences")
	}
	if system == "freebsd" || system == "linux" {
		home = path.Join(home, "."+BASE)
	}
	cfgname := path.Join(home, CONFIGNAME)

	cfgfile = getopt.StringLong("config", 'C', cfgname, "Name of the configuration file to use.")
	version := getopt.BoolLong("version", 'v', "Show version and exit.")
	allusers := getopt.BoolLong("userlist", 'l', "List all users.")
	completeusers := getopt.BoolLong("complete", 'c', "List all users with e-mail set.")
	incompleteusers := getopt.BoolLong("incomplete", 'i', "List all users missing e-mail.")
	user := getopt.StringLong("user", 'u', "", "User to edit.")
	mail := getopt.StringLong("email", 'm', "", "E-mail address of specified user.")
	pw := getopt.StringLong("password", 'p', "", "Password of specified user.")
	initConfig()

	if *version {
		p("%s v%s", PROGNAME, PROGVERSION)
		return
	}

	if *allusers {
		getUsersOF(0)
		return
	}
	if *completeusers {
		getUsersOF(1)
		return
	}
	if *incompleteusers {
		getUsersOF(2)
		return
	}
	if *user != "" {
		if *mail == "" && *pw == "" {
			p("Do what with %s?", *user)
			return
		}
		if *mail != "" && *pw != "" {
			setDetailsOF(*user, *mail, *pw)
			return
		}
		if *mail != "" {
			setDetailsOF(*user, *mail, "")
			return
		}
		if *pw != "" {
			setDetailsOF(*user, "", *pw)
		}
		return
	}
	getopt.Usage()
}
<commit_msg>Show configuration file path along with version information.<commit_after>package main

import (
	"os/user"
	"path"
	"runtime"

	"code.google.com/p/getopt"
)

const PROGNAME string = "Fireman"
const PROGVERSION string = "0.1.0"

func main() {
	u, err := user.Current()
	if err != nil {
		f("Error: Couldn't get current user - %s", err.Error())
	}
	home := u.HomeDir
	system := runtime.GOOS
	if system == "darwin" {
		home = path.Join(home, "Library", "Preferences")
	}
	if system == "freebsd" || system == "linux" {
		home = path.Join(home, "."+BASE)
	}
	cfgname := path.Join(home, CONFIGNAME)

	cfgfile = getopt.StringLong("config", 'C', cfgname, "Name of the configuration file to use.")
	version := getopt.BoolLong("version", 'v', "Show version and config path, then exit.")
	allusers := getopt.BoolLong("userlist", 'l', "List all users.")
	completeusers := getopt.BoolLong("complete", 'c', "List all users with e-mail set.")
	incompleteusers := getopt.BoolLong("incomplete", 'i', "List all users missing e-mail.")
	user := getopt.StringLong("user", 'u', "", "User to edit.")
	mail := getopt.StringLong("email", 'm', "", "E-mail address of specified user.")
	pw := getopt.StringLong("password", 'p', "", "Password of specified user.")
	initConfig()

	if *version {
		p("%s v%s", PROGNAME, PROGVERSION)
		p("Default configuration file is %s", cfgname)
		return
	}

	if *allusers {
		getUsersOF(0)
		return
	}
	if *completeusers {
		getUsersOF(1)
		return
	}
	if *incompleteusers {
		getUsersOF(2)
		return
	}
	if *user != "" {
		if *mail == "" && *pw == "" {
			p("Do what with %s?", *user)
			return
		}
		if *mail != "" && *pw != "" {
			setDetailsOF(*user, *mail, *pw)
			return
		}
		if *mail != "" {
			setDetailsOF(*user, *mail, "")
			return
		}
		if *pw != "" {
			setDetailsOF(*user, "", *pw)
		}
		return
	}
	getopt.Usage()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
)

const (
	exitOK = iota
	exitOpenFile
	exitReadInput
	exitJSONDecode
	exitFormStatements
	exitFetchURL
)

func init() {
	flag.Usage = func() {
		h := "Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable\n\n"

		h += "Usage:\n"
		h += "  gron [file|url]\n\n"

		h += "Exit Codes:\n"
		h += fmt.Sprintf("  %d\t%s\n", exitOK, "OK")
		h += fmt.Sprintf("  %d\t%s\n", exitOpenFile, "Failed to open file")
		h += fmt.Sprintf("  %d\t%s\n", exitReadInput, "Failed to read input")
		h += fmt.Sprintf("  %d\t%s\n", exitJSONDecode, "Failed to decode JSON")
		h += fmt.Sprintf("  %d\t%s\n", exitFormStatements, "Failed to from statements")
		h += fmt.Sprintf("  %d\t%s\n", exitFetchURL, "Failed to fetch URL")
		h += "\n"

		h += "Examples:\n"
		h += "  gron /tmp/apiresponse.json\n"
		h += "  gron http://headers.jsontest.com/ \n"
		h += "  curl -s http://headers.jsontest.com/ | gron\n"

		fmt.Fprintf(os.Stderr, h)
	}
}

func main() {
	flag.Parse()

	var raw io.Reader

	filename := flag.Arg(0)
	if filename == "" {
		raw = os.Stdin
	} else {
		if !validURL(filename) {
			r, err := os.Open(filename)
			if err != nil {
				fatal(exitOpenFile, "failed to open file", err)
			}
			raw = r
		} else {
			r, err := getURL(filename)
			if err != nil {
				fatal(exitFetchURL, "failed to fetch URL", err)
			}
			raw = r
		}
	}

	b, err := ioutil.ReadAll(raw)
	if err != nil {
		fatal(exitReadInput, "failed to read input", err)
	}

	// The 'JSON' might be an object, array or scalar,
	// so the best we can do for now is an empty interface type
	var top interface{}

	err = json.Unmarshal(b, &top)
	if err != nil {
		fatal(exitJSONDecode, "failed to decode JSON", err)
	}

	ss, err := makeStatements("json", top)
	if err != nil {
		fatal(exitFormStatements, "failed to form statements", err)
	}

	sort.Sort(ss)

	for _, s := range ss {
		fmt.Println(s)
	}

	os.Exit(exitOK)
}

func fatal(code int, msg string, err error) {
	fmt.Fprintf(os.Stderr, "%s (%s)\n", msg, err)
	os.Exit(code)
}
<commit_msg>Adds option to use '-' to signify stdin<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
)

const (
	exitOK = iota
	exitOpenFile
	exitReadInput
	exitJSONDecode
	exitFormStatements
	exitFetchURL
)

func init() {
	flag.Usage = func() {
		h := "Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable\n\n"

		h += "Usage:\n"
		h += "  gron [file|url]\n\n"

		h += "Exit Codes:\n"
		h += fmt.Sprintf("  %d\t%s\n", exitOK, "OK")
		h += fmt.Sprintf("  %d\t%s\n", exitOpenFile, "Failed to open file")
		h += fmt.Sprintf("  %d\t%s\n", exitReadInput, "Failed to read input")
		h += fmt.Sprintf("  %d\t%s\n", exitJSONDecode, "Failed to decode JSON")
		h += fmt.Sprintf("  %d\t%s\n", exitFormStatements, "Failed to from statements")
		h += fmt.Sprintf("  %d\t%s\n", exitFetchURL, "Failed to fetch URL")
		h += "\n"

		h += "Examples:\n"
		h += "  gron /tmp/apiresponse.json\n"
		h += "  gron http://headers.jsontest.com/ \n"
		h += "  curl -s http://headers.jsontest.com/ | gron\n"

		fmt.Fprintf(os.Stderr, h)
	}
}

func main() {
	flag.Parse()

	var raw io.Reader

	filename := flag.Arg(0)
	if filename == "" || filename == "-" {
		raw = os.Stdin
	} else {
		if !validURL(filename) {
			r, err := os.Open(filename)
			if err != nil {
				fatal(exitOpenFile, "failed to open file", err)
			}
			raw = r
		} else {
			r, err := getURL(filename)
			if err != nil {
				fatal(exitFetchURL, "failed to fetch URL", err)
			}
			raw = r
		}
	}

	b, err := ioutil.ReadAll(raw)
	if err != nil {
		fatal(exitReadInput, "failed to read input", err)
	}

	// The 'JSON' might be an object, array or scalar,
	// so the best we can do for now is an empty interface type
	var top interface{}

	err = json.Unmarshal(b, &top)
	if err != nil {
		fatal(exitJSONDecode, "failed to decode JSON", err)
	}

	ss, err := makeStatements("json", top)
	if err != nil {
		fatal(exitFormStatements, "failed to form statements", err)
	}

	sort.Sort(ss)

	for _, s := range ss {
		fmt.Println(s)
	}

	os.Exit(exitOK)
}

func fatal(code int, msg string, err error) {
	fmt.Fprintf(os.Stderr, "%s (%s)\n", msg, err)
	os.Exit(code)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"

	"github.com/kadel/henge/pkg/generate/dockercompose"
)

func main() {

	flag.Parse()

	template, err := dockercompose.Generate(flag.Args()[0:]...)
	if err != nil {
		return
	}

	fmt.Printf("%#v", template)

}
<commit_msg>convert to versioned objects and to list instead of template<commit_after>package main

import (
	"flag"
	"fmt"

	"github.com/kadel/henge/pkg/generate/dockercompose"
	"github.com/openshift/origin/pkg/generate/app"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apimachinery/registered"

	// Install OpenShift APIs
	_ "github.com/openshift/origin/pkg/build/api/install"
	_ "github.com/openshift/origin/pkg/deploy/api/install"
	_ "github.com/openshift/origin/pkg/image/api/install"
	_ "github.com/openshift/origin/pkg/route/api/install"
	_ "github.com/openshift/origin/pkg/template/api/install"
)

func main() {

	flag.Parse()

	template, err := dockercompose.Generate(flag.Args()[0:]...)
	if err != nil {
		return
	}

	if errs := app.AsVersionedObjects(template.Objects, kapi.Scheme, kapi.Scheme, registered.EnabledVersions()...); len(errs) > 0 {
		for _, err := range errs {
			fmt.Printf("error: %v\n", err)
		}
	}

	// make it List instead of Template
	list := &kapi.List{Items: template.Objects}
	for _, obj := range list.Items {
		fmt.Printf("%#v\n", obj)
	}

}
<|endoftext|>