<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/oliver006/redis_exporter/exporter"
)

var (
	/*
		BuildVersion, BuildDate, BuildCommitSha are filled in by the build script
	*/
	BuildVersion   = "<<< filled in by build >>>"
	BuildDate      = "<<< filled in by build >>>"
	BuildCommitSha = "<<< filled in by build >>>"
)

func getEnv(key string, defaultVal string) string {
	if envVal, ok := os.LookupEnv(key); ok {
		return envVal
	}
	return defaultVal
}

func getEnvBool(key string, defaultVal bool) bool {
	if envVal, ok := os.LookupEnv(key); ok {
		envBool, err := strconv.ParseBool(envVal)
		if err == nil {
			return envBool
		}
	}
	return defaultVal
}

func getEnvInt64(key string, defaultVal int64) int64 {
	if envVal, ok := os.LookupEnv(key); ok {
		envInt64, err := strconv.ParseInt(envVal, 10, 64)
		if err == nil {
			return envInt64
		}
	}
	return defaultVal
}

func main() {
	var (
		redisAddr            = flag.String("redis.addr", getEnv("REDIS_ADDR", "redis://localhost:6379"), "Address of the Redis instance to scrape")
		redisUser            = flag.String("redis.user", getEnv("REDIS_USER", ""), "User name to use for authentication (Redis ACL for Redis 6.0 and newer)")
		redisPwd             = flag.String("redis.password", getEnv("REDIS_PASSWORD", ""), "Password of the Redis instance to scrape")
		redisPwdFile         = flag.String("redis.password-file", getEnv("REDIS_PASSWORD_FILE", ""), "Password file of the Redis instance to scrape")
		namespace            = flag.String("namespace", getEnv("REDIS_EXPORTER_NAMESPACE", "redis"), "Namespace for metrics")
		checkKeys            = flag.String("check-keys", getEnv("REDIS_EXPORTER_CHECK_KEYS", ""), "Comma separated list of key-patterns to export value and length/size, searched for with SCAN")
		checkSingleKeys      = flag.String("check-single-keys", getEnv("REDIS_EXPORTER_CHECK_SINGLE_KEYS", ""), "Comma separated list of single keys to export value and length/size")
		checkKeyGroups       = flag.String("check-key-groups", getEnv("REDIS_EXPORTER_CHECK_KEY_GROUPS", ""), "Comma separated list of lua regex for grouping keys")
		checkStreams         = flag.String("check-streams", getEnv("REDIS_EXPORTER_CHECK_STREAMS", ""), "Comma separated list of stream-patterns to export info about streams, groups and consumers, searched for with SCAN")
		checkSingleStreams   = flag.String("check-single-streams", getEnv("REDIS_EXPORTER_CHECK_SINGLE_STREAMS", ""), "Comma separated list of single streams to export info about streams, groups and consumers")
		countKeys            = flag.String("count-keys", getEnv("REDIS_EXPORTER_COUNT_KEYS", ""), "Comma separated list of patterns to count (eg: 'db0=production_*,db3=sessions:*'), searched for with SCAN")
		checkKeysBatchSize   = flag.Int64("check-keys-batch-size", getEnvInt64("REDIS_EXPORTER_CHECK_KEYS_BATCH_SIZE", 1000), "Approximate number of keys to process in each execution, larger value speeds up scanning.\nWARNING: Still Redis is a single-threaded app, huge COUNT can affect production environment.")
		scriptPath           = flag.String("script", getEnv("REDIS_EXPORTER_SCRIPT", ""), "Path to Lua Redis script for collecting extra metrics")
		listenAddress        = flag.String("web.listen-address", getEnv("REDIS_EXPORTER_WEB_LISTEN_ADDRESS", ":9121"), "Address to listen on for web interface and telemetry.")
		metricPath           = flag.String("web.telemetry-path", getEnv("REDIS_EXPORTER_WEB_TELEMETRY_PATH", "/metrics"), "Path under which to expose metrics.")
		logFormat            = flag.String("log-format", getEnv("REDIS_EXPORTER_LOG_FORMAT", "txt"), "Log format, valid options are txt and json")
		configCommand        = flag.String("config-command", getEnv("REDIS_EXPORTER_CONFIG_COMMAND", "CONFIG"), "What to use for the CONFIG command")
		connectionTimeout    = flag.String("connection-timeout", getEnv("REDIS_EXPORTER_CONNECTION_TIMEOUT", "15s"), "Timeout for connection to Redis instance")
		tlsClientKeyFile     = flag.String("tls-client-key-file", getEnv("REDIS_EXPORTER_TLS_CLIENT_KEY_FILE", ""), "Name of the client key file (including full path) if the server requires TLS client authentication")
		tlsClientCertFile    = flag.String("tls-client-cert-file", getEnv("REDIS_EXPORTER_TLS_CLIENT_CERT_FILE", ""), "Name of the client certificate file (including full path) if the server requires TLS client authentication")
		tlsCaCertFile        = flag.String("tls-ca-cert-file", getEnv("REDIS_EXPORTER_TLS_CA_CERT_FILE", ""), "Name of the CA certificate file (including full path) if the server requires TLS client authentication")
		tlsServerKeyFile     = flag.String("tls-server-key-file", getEnv("REDIS_EXPORTER_TLS_SERVER_KEY_FILE", ""), "Name of the server key file (including full path) if the web interface and telemetry should use TLS")
		tlsServerCertFile    = flag.String("tls-server-cert-file", getEnv("REDIS_EXPORTER_TLS_SERVER_CERT_FILE", ""), "Name of the server certificate file (including full path) if the web interface and telemetry should use TLS")
		tlsServerCaCertFile  = flag.String("tls-server-ca-cert-file", getEnv("REDIS_EXPORTER_TLS_SERVER_CA_CERT_FILE", ""), "Name of the CA certificate file (including full path) if the web interface and telemetry should require TLS client authentication")
		maxDistinctKeyGroups = flag.Int64("max-distinct-key-groups", getEnvInt64("REDIS_EXPORTER_MAX_DISTINCT_KEY_GROUPS", 100), "The maximum number of distinct key groups with the most memory utilization to present as distinct metrics per database, the leftover key groups will be aggregated in the 'overflow' bucket")
		isDebug              = flag.Bool("debug", getEnvBool("REDIS_EXPORTER_DEBUG", false), "Output verbose debug information")
		setClientName        = flag.Bool("set-client-name", getEnvBool("REDIS_EXPORTER_SET_CLIENT_NAME", true), "Whether to set client name to redis_exporter")
		isTile38             = flag.Bool("is-tile38", getEnvBool("REDIS_EXPORTER_IS_TILE38", false), "Whether to scrape Tile38 specific metrics")
		isCluster            = flag.Bool("is-cluster", getEnvBool("REDIS_EXPORTER_IS_CLUSTER", false), "Whether this is a redis cluster (Enable this if you need to fetch key level data on a Redis Cluster).")
		exportClientList     = flag.Bool("export-client-list", getEnvBool("REDIS_EXPORTER_EXPORT_CLIENT_LIST", false), "Whether to scrape Client List specific metrics")
		exportClientPort     = flag.Bool("export-client-port", getEnvBool("REDIS_EXPORTER_EXPORT_CLIENT_PORT", false), "Whether to include the client's port when exporting the client list. Warning: including the port increases the number of metrics generated and will make your Prometheus server take up more memory")
		showVersion          = flag.Bool("version", false, "Show version information and exit")
		redisMetricsOnly     = flag.Bool("redis-only-metrics", getEnvBool("REDIS_EXPORTER_REDIS_ONLY_METRICS", false), "Whether to also export go runtime metrics")
		pingOnConnect        = flag.Bool("ping-on-connect", getEnvBool("REDIS_EXPORTER_PING_ON_CONNECT", false), "Whether to ping the redis instance after connecting")
		inclConfigMetrics    = flag.Bool("include-config-metrics", getEnvBool("REDIS_EXPORTER_INCL_CONFIG_METRICS", false), "Whether to include all config settings as metrics")
		redactConfigMetrics  = flag.Bool("redact-config-metrics", getEnvBool("REDIS_EXPORTER_REDACT_CONFIG_METRICS", true), "Whether to redact config settings that include potentially sensitive information like passwords")
		inclSystemMetrics    = flag.Bool("include-system-metrics", getEnvBool("REDIS_EXPORTER_INCL_SYSTEM_METRICS", false), "Whether to include system metrics like e.g. redis_total_system_memory_bytes")
		skipTLSVerification  = flag.Bool("skip-tls-verification", getEnvBool("REDIS_EXPORTER_SKIP_TLS_VERIFICATION", false), "Whether to to skip TLS verification")
	)
	flag.Parse()

	switch *logFormat {
	case "json":
		log.SetFormatter(&log.JSONFormatter{})
	default:
		log.SetFormatter(&log.TextFormatter{})
	}
	log.Printf("Redis Metrics Exporter %s    build date: %s    sha1: %s    Go: %s    GOOS: %s    GOARCH: %s",
		BuildVersion, BuildDate, BuildCommitSha,
		runtime.Version(),
		runtime.GOOS,
		runtime.GOARCH,
	)
	if *isDebug {
		log.SetLevel(log.DebugLevel)
		log.Debugln("Enabling debug output")
	} else {
		log.SetLevel(log.InfoLevel)
	}

	if *showVersion {
		return
	}

	to, err := time.ParseDuration(*connectionTimeout)
	if err != nil {
		log.Fatalf("Couldn't parse connection timeout duration, err: %s", err)
	}

	passwordMap := make(map[string]string)
	if *redisPwd == "" && *redisPwdFile != "" {
		passwordMap, err = exporter.LoadPwdFile(*redisPwdFile)
		if err != nil {
			log.Fatalf("Error loading redis passwords from file %s, err: %s", *redisPwdFile, err)
		}
	}

	var ls []byte
	if *scriptPath != "" {
		if ls, err = ioutil.ReadFile(*scriptPath); err != nil {
			log.Fatalf("Error loading script file %s    err: %s", *scriptPath, err)
		}
	}

	registry := prometheus.NewRegistry()
	if !*redisMetricsOnly {
		registry = prometheus.DefaultRegisterer.(*prometheus.Registry)
	}

	exp, err := exporter.NewRedisExporter(
		*redisAddr,
		exporter.Options{
			User:                  *redisUser,
			Password:              *redisPwd,
			PasswordMap:           passwordMap,
			Namespace:             *namespace,
			ConfigCommandName:     *configCommand,
			CheckKeys:             *checkKeys,
			CheckSingleKeys:       *checkSingleKeys,
			CheckKeysBatchSize:    *checkKeysBatchSize,
			CheckKeyGroups:        *checkKeyGroups,
			MaxDistinctKeyGroups:  *maxDistinctKeyGroups,
			CheckStreams:          *checkStreams,
			CheckSingleStreams:    *checkSingleStreams,
			CountKeys:             *countKeys,
			LuaScript:             ls,
			InclSystemMetrics:     *inclSystemMetrics,
			InclConfigMetrics:     *inclConfigMetrics,
			RedactConfigMetrics:   *redactConfigMetrics,
			SetClientName:         *setClientName,
			IsTile38:              *isTile38,
			IsCluster:             *isCluster,
			ExportClientList:      *exportClientList,
			ExportClientsInclPort: *exportClientPort,
			SkipTLSVerification:   *skipTLSVerification,
			ClientCertFile:        *tlsClientCertFile,
			ClientKeyFile:         *tlsClientKeyFile,
			CaCertFile:            *tlsCaCertFile,
			ConnectionTimeouts:    to,
			MetricsPath:           *metricPath,
			RedisMetricsOnly:      *redisMetricsOnly,
			PingOnConnect:         *pingOnConnect,
			Registry:              registry,
			BuildInfo: exporter.BuildInfo{
				Version:   BuildVersion,
				CommitSha: BuildCommitSha,
				Date:      BuildDate,
			},
		},
	)
	if err != nil {
		log.Fatal(err)
	}

	// Verify that initial client keypair and CA are accepted
	if (*tlsClientCertFile != "") != (*tlsClientKeyFile != "") {
		log.Fatal("TLS client key file and cert file should both be present")
	}
	_, err = exp.CreateClientTLSConfig()
	if err != nil {
		log.Fatal(err)
	}

	log.Infof("Providing metrics at %s%s", *listenAddress, *metricPath)
	log.Debugf("Configured redis addr: %#v", *redisAddr)
	if *tlsServerCertFile != "" && *tlsServerKeyFile != "" {
		log.Debugf("Bind as TLS using cert %s and key %s", *tlsServerCertFile, *tlsServerKeyFile)

		tlsConfig, err := exp.CreateServerTLSConfig(*tlsServerCertFile, *tlsServerKeyFile, *tlsServerCaCertFile)
		if err != nil {
			log.Fatal(err)
		}

		server := &http.Server{
			Addr:      *listenAddress,
			TLSConfig: tlsConfig,
			Handler:   exp}
		log.Fatal(server.ListenAndServeTLS("", ""))
	} else {
		log.Fatal(http.ListenAndServe(*listenAddress, exp))
	}
}
<commit_msg>print version to stdout when -version flag is used (#662)<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/oliver006/redis_exporter/exporter"
)

var (
	/*
		BuildVersion, BuildDate, BuildCommitSha are filled in by the build script
	*/
	BuildVersion   = "<<< filled in by build >>>"
	BuildDate      = "<<< filled in by build >>>"
	BuildCommitSha = "<<< filled in by build >>>"
)

func getEnv(key string, defaultVal string) string {
	if envVal, ok := os.LookupEnv(key); ok {
		return envVal
	}
	return defaultVal
}

func getEnvBool(key string, defaultVal bool) bool {
	if envVal, ok := os.LookupEnv(key); ok {
		envBool, err := strconv.ParseBool(envVal)
		if err == nil {
			return envBool
		}
	}
	return defaultVal
}

func getEnvInt64(key string, defaultVal int64) int64 {
	if envVal, ok := os.LookupEnv(key); ok {
		envInt64, err := strconv.ParseInt(envVal, 10, 64)
		if err == nil {
			return envInt64
		}
	}
	return defaultVal
}

func main() {
	var (
		redisAddr            = flag.String("redis.addr", getEnv("REDIS_ADDR", "redis://localhost:6379"), "Address of the Redis instance to scrape")
		redisUser            = flag.String("redis.user", getEnv("REDIS_USER", ""), "User name to use for authentication (Redis ACL for Redis 6.0 and newer)")
		redisPwd             = flag.String("redis.password", getEnv("REDIS_PASSWORD", ""), "Password of the Redis instance to scrape")
		redisPwdFile         = flag.String("redis.password-file", getEnv("REDIS_PASSWORD_FILE", ""), "Password file of the Redis instance to scrape")
		namespace            = flag.String("namespace", getEnv("REDIS_EXPORTER_NAMESPACE", "redis"), "Namespace for metrics")
		checkKeys            = flag.String("check-keys", getEnv("REDIS_EXPORTER_CHECK_KEYS", ""), "Comma separated list of key-patterns to export value and length/size, searched for with SCAN")
		checkSingleKeys      = flag.String("check-single-keys", getEnv("REDIS_EXPORTER_CHECK_SINGLE_KEYS", ""), "Comma separated list of single keys to export value and length/size")
		checkKeyGroups       = flag.String("check-key-groups", getEnv("REDIS_EXPORTER_CHECK_KEY_GROUPS", ""), "Comma separated list of lua regex for grouping keys")
		checkStreams         = flag.String("check-streams", getEnv("REDIS_EXPORTER_CHECK_STREAMS", ""), "Comma separated list of stream-patterns to export info about streams, groups and consumers, searched for with SCAN")
		checkSingleStreams   = flag.String("check-single-streams", getEnv("REDIS_EXPORTER_CHECK_SINGLE_STREAMS", ""), "Comma separated list of single streams to export info about streams, groups and consumers")
		countKeys            = flag.String("count-keys", getEnv("REDIS_EXPORTER_COUNT_KEYS", ""), "Comma separated list of patterns to count (eg: 'db0=production_*,db3=sessions:*'), searched for with SCAN")
		checkKeysBatchSize   = flag.Int64("check-keys-batch-size", getEnvInt64("REDIS_EXPORTER_CHECK_KEYS_BATCH_SIZE", 1000), "Approximate number of keys to process in each execution, larger value speeds up scanning.\nWARNING: Still Redis is a single-threaded app, huge COUNT can affect production environment.")
		scriptPath           = flag.String("script", getEnv("REDIS_EXPORTER_SCRIPT", ""), "Path to Lua Redis script for collecting extra metrics")
		listenAddress        = flag.String("web.listen-address", getEnv("REDIS_EXPORTER_WEB_LISTEN_ADDRESS", ":9121"), "Address to listen on for web interface and telemetry.")
		metricPath           = flag.String("web.telemetry-path", getEnv("REDIS_EXPORTER_WEB_TELEMETRY_PATH", "/metrics"), "Path under which to expose metrics.")
		logFormat            = flag.String("log-format", getEnv("REDIS_EXPORTER_LOG_FORMAT", "txt"), "Log format, valid options are txt and json")
		configCommand        = flag.String("config-command", getEnv("REDIS_EXPORTER_CONFIG_COMMAND", "CONFIG"), "What to use for the CONFIG command")
		connectionTimeout    = flag.String("connection-timeout", getEnv("REDIS_EXPORTER_CONNECTION_TIMEOUT", "15s"), "Timeout for connection to Redis instance")
		tlsClientKeyFile     = flag.String("tls-client-key-file", getEnv("REDIS_EXPORTER_TLS_CLIENT_KEY_FILE", ""), "Name of the client key file (including full path) if the server requires TLS client authentication")
		tlsClientCertFile    = flag.String("tls-client-cert-file", getEnv("REDIS_EXPORTER_TLS_CLIENT_CERT_FILE", ""), "Name of the client certificate file (including full path) if the server requires TLS client authentication")
		tlsCaCertFile        = flag.String("tls-ca-cert-file", getEnv("REDIS_EXPORTER_TLS_CA_CERT_FILE", ""), "Name of the CA certificate file (including full path) if the server requires TLS client authentication")
		tlsServerKeyFile     = flag.String("tls-server-key-file", getEnv("REDIS_EXPORTER_TLS_SERVER_KEY_FILE", ""), "Name of the server key file (including full path) if the web interface and telemetry should use TLS")
		tlsServerCertFile    = flag.String("tls-server-cert-file", getEnv("REDIS_EXPORTER_TLS_SERVER_CERT_FILE", ""), "Name of the server certificate file (including full path) if the web interface and telemetry should use TLS")
		tlsServerCaCertFile  = flag.String("tls-server-ca-cert-file", getEnv("REDIS_EXPORTER_TLS_SERVER_CA_CERT_FILE", ""), "Name of the CA certificate file (including full path) if the web interface and telemetry should require TLS client authentication")
		maxDistinctKeyGroups = flag.Int64("max-distinct-key-groups", getEnvInt64("REDIS_EXPORTER_MAX_DISTINCT_KEY_GROUPS", 100), "The maximum number of distinct key groups with the most memory utilization to present as distinct metrics per database, the leftover key groups will be aggregated in the 'overflow' bucket")
		isDebug              = flag.Bool("debug", getEnvBool("REDIS_EXPORTER_DEBUG", false), "Output verbose debug information")
		setClientName        = flag.Bool("set-client-name", getEnvBool("REDIS_EXPORTER_SET_CLIENT_NAME", true), "Whether to set client name to redis_exporter")
		isTile38             = flag.Bool("is-tile38", getEnvBool("REDIS_EXPORTER_IS_TILE38", false), "Whether to scrape Tile38 specific metrics")
		isCluster            = flag.Bool("is-cluster", getEnvBool("REDIS_EXPORTER_IS_CLUSTER", false), "Whether this is a redis cluster (Enable this if you need to fetch key level data on a Redis Cluster).")
		exportClientList     = flag.Bool("export-client-list", getEnvBool("REDIS_EXPORTER_EXPORT_CLIENT_LIST", false), "Whether to scrape Client List specific metrics")
		exportClientPort     = flag.Bool("export-client-port", getEnvBool("REDIS_EXPORTER_EXPORT_CLIENT_PORT", false), "Whether to include the client's port when exporting the client list. Warning: including the port increases the number of metrics generated and will make your Prometheus server take up more memory")
		showVersion          = flag.Bool("version", false, "Show version information and exit")
		redisMetricsOnly     = flag.Bool("redis-only-metrics", getEnvBool("REDIS_EXPORTER_REDIS_ONLY_METRICS", false), "Whether to also export go runtime metrics")
		pingOnConnect        = flag.Bool("ping-on-connect", getEnvBool("REDIS_EXPORTER_PING_ON_CONNECT", false), "Whether to ping the redis instance after connecting")
		inclConfigMetrics    = flag.Bool("include-config-metrics", getEnvBool("REDIS_EXPORTER_INCL_CONFIG_METRICS", false), "Whether to include all config settings as metrics")
		redactConfigMetrics  = flag.Bool("redact-config-metrics", getEnvBool("REDIS_EXPORTER_REDACT_CONFIG_METRICS", true), "Whether to redact config settings that include potentially sensitive information like passwords")
		inclSystemMetrics    = flag.Bool("include-system-metrics", getEnvBool("REDIS_EXPORTER_INCL_SYSTEM_METRICS", false), "Whether to include system metrics like e.g. redis_total_system_memory_bytes")
		skipTLSVerification  = flag.Bool("skip-tls-verification", getEnvBool("REDIS_EXPORTER_SKIP_TLS_VERIFICATION", false), "Whether to to skip TLS verification")
	)
	flag.Parse()

	switch *logFormat {
	case "json":
		log.SetFormatter(&log.JSONFormatter{})
	default:
		log.SetFormatter(&log.TextFormatter{})
	}
	if *showVersion {
		log.SetOutput(os.Stdout)
	}
	log.Printf("Redis Metrics Exporter %s    build date: %s    sha1: %s    Go: %s    GOOS: %s    GOARCH: %s",
		BuildVersion, BuildDate, BuildCommitSha,
		runtime.Version(),
		runtime.GOOS,
		runtime.GOARCH,
	)
	if *showVersion {
		return
	}
	if *isDebug {
		log.SetLevel(log.DebugLevel)
		log.Debugln("Enabling debug output")
	} else {
		log.SetLevel(log.InfoLevel)
	}

	to, err := time.ParseDuration(*connectionTimeout)
	if err != nil {
		log.Fatalf("Couldn't parse connection timeout duration, err: %s", err)
	}

	passwordMap := make(map[string]string)
	if *redisPwd == "" && *redisPwdFile != "" {
		passwordMap, err = exporter.LoadPwdFile(*redisPwdFile)
		if err != nil {
			log.Fatalf("Error loading redis passwords from file %s, err: %s", *redisPwdFile, err)
		}
	}

	var ls []byte
	if *scriptPath != "" {
		if ls, err = ioutil.ReadFile(*scriptPath); err != nil {
			log.Fatalf("Error loading script file %s    err: %s", *scriptPath, err)
		}
	}

	registry := prometheus.NewRegistry()
	if !*redisMetricsOnly {
		registry = prometheus.DefaultRegisterer.(*prometheus.Registry)
	}

	exp, err := exporter.NewRedisExporter(
		*redisAddr,
		exporter.Options{
			User:                  *redisUser,
			Password:              *redisPwd,
			PasswordMap:           passwordMap,
			Namespace:             *namespace,
			ConfigCommandName:     *configCommand,
			CheckKeys:             *checkKeys,
			CheckSingleKeys:       *checkSingleKeys,
			CheckKeysBatchSize:    *checkKeysBatchSize,
			CheckKeyGroups:        *checkKeyGroups,
			MaxDistinctKeyGroups:  *maxDistinctKeyGroups,
			CheckStreams:          *checkStreams,
			CheckSingleStreams:    *checkSingleStreams,
			CountKeys:             *countKeys,
			LuaScript:             ls,
			InclSystemMetrics:     *inclSystemMetrics,
			InclConfigMetrics:     *inclConfigMetrics,
			RedactConfigMetrics:   *redactConfigMetrics,
			SetClientName:         *setClientName,
			IsTile38:              *isTile38,
			IsCluster:             *isCluster,
			ExportClientList:      *exportClientList,
			ExportClientsInclPort: *exportClientPort,
			SkipTLSVerification:   *skipTLSVerification,
			ClientCertFile:        *tlsClientCertFile,
			ClientKeyFile:         *tlsClientKeyFile,
			CaCertFile:            *tlsCaCertFile,
			ConnectionTimeouts:    to,
			MetricsPath:           *metricPath,
			RedisMetricsOnly:      *redisMetricsOnly,
			PingOnConnect:         *pingOnConnect,
			Registry:              registry,
			BuildInfo: exporter.BuildInfo{
				Version:   BuildVersion,
				CommitSha: BuildCommitSha,
				Date:      BuildDate,
			},
		},
	)
	if err != nil {
		log.Fatal(err)
	}

	// Verify that initial client keypair and CA are accepted
	if (*tlsClientCertFile != "") != (*tlsClientKeyFile != "") {
		log.Fatal("TLS client key file and cert file should both be present")
	}
	_, err = exp.CreateClientTLSConfig()
	if err != nil {
		log.Fatal(err)
	}

	log.Infof("Providing metrics at %s%s", *listenAddress, *metricPath)
	log.Debugf("Configured redis addr: %#v", *redisAddr)
	if *tlsServerCertFile != "" && *tlsServerKeyFile != "" {
		log.Debugf("Bind as TLS using cert %s and key %s", *tlsServerCertFile, *tlsServerKeyFile)

		tlsConfig, err := exp.CreateServerTLSConfig(*tlsServerCertFile, *tlsServerKeyFile, *tlsServerCaCertFile)
		if err != nil {
			log.Fatal(err)
		}

		server := &http.Server{
			Addr:      *listenAddress,
			TLSConfig: tlsConfig,
			Handler:   exp}
		log.Fatal(server.ListenAndServeTLS("", ""))
	} else {
		log.Fatal(http.ListenAndServe(*listenAddress, exp))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 conntrack-prometheus authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"net/http"
	"strings"

	_ "net/http/pprof"

	sysctl "github.com/lorenzosaino/go-sysctl"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/tsuru/prometheus-conntrack/collector"
	"github.com/tsuru/prometheus-conntrack/workload"
	"github.com/tsuru/prometheus-conntrack/workload/docker"
	"github.com/tsuru/prometheus-conntrack/workload/kubelet"
)

const conntrackTimestampFlag = "net.netfilter.nf_conntrack_timestamp"

func main() {
	addr := flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
	protocol := flag.String("protocol", "", "Protocol to track connections. Defaults to all.")
	engineName := flag.String("engine", "docker", "Engine to track local workload addresses. Defaults to docker.")
	workloadLabelsString := flag.String("workload-labels", "", "Labels to extract from workload. ie (tsuru.io/app-name,tsuru.io/process-name)")
	trackSynSent := flag.Bool("track-syn-sent", false, "Turn on track of stuck connections with syn-sent, will enable automatically the net.netfilter.nf_conntrack_timestamp flag on kernel.")

	dockerEndpoint := flag.String("docker-endpoint", "unix:///var/run/docker.sock", "Docker endpoint.")
	kubeletEndpoint := flag.String("kubelet-endpoint", "https://127.0.0.1:10250/pods", "Kubelet endpoint.")
	kubeletKey := flag.String("kubelet-key", "", "Path to a key to authenticate on kubelet.")
	kubeletCert := flag.String("kubelet-cert", "", "Path to a certificate to authenticate on kubelet.")
	kubeletCA := flag.String("kubelet-ca", "", "Path to a CA to authenticate on kubelet.")

	flag.Parse()

	if *trackSynSent {
		enableConntrackTimestamps()
	}

	http.Handle("/metrics", promhttp.Handler())

	var engine workload.Engine
	var err error
	if *engineName == "kubelet" {
		log.Printf("Fetching workload from kubelet: %s...\n", *kubeletEndpoint)
		engine, err = kubelet.NewEngine(kubelet.Opts{
			Endpoint: *kubeletEndpoint,
			Key:      *kubeletKey,
			Cert:     *kubeletCert,
			CA:       *kubeletCA,
		})
		if err != nil {
			log.Fatal(err)
		}
	} else {
		log.Printf("Fetching workload from docker: %s...\n", *dockerEndpoint)
		engine = docker.NewEngine(*dockerEndpoint)
	}

	workloadLabels := strings.Split(*workloadLabelsString, ",")
	conntrack := collector.NewConntrack(*protocol)
	collector := collector.New(engine, conntrack, workloadLabels)
	prometheus.MustRegister(collector)
	log.Printf("HTTP server listening at %s...\n", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

func enableConntrackTimestamps() {
	val, err := sysctl.Get(conntrackTimestampFlag)
	if err != nil {
		log.Printf("Could not get status of %s, err\n", conntrackTimestampFlag, err.Error())
		return
	}
	if val == "1" {
		log.Printf("Flag %s is already turned on", conntrackTimestampFlag)
		return
	}
	err = sysctl.Set(conntrackTimestampFlag, "1")
	if err != nil {
		log.Printf("Could not set status of %s, err\n", conntrackTimestampFlag, err.Error())
		return
	}

	log.Printf("Flag %s was turned on", conntrackTimestampFlag)

}
<commit_msg>Fix printf lint<commit_after>// Copyright 2016 conntrack-prometheus authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"net/http"
	"strings"

	_ "net/http/pprof"

	sysctl "github.com/lorenzosaino/go-sysctl"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/tsuru/prometheus-conntrack/collector"
	"github.com/tsuru/prometheus-conntrack/workload"
	"github.com/tsuru/prometheus-conntrack/workload/docker"
	"github.com/tsuru/prometheus-conntrack/workload/kubelet"
)

const conntrackTimestampFlag = "net.netfilter.nf_conntrack_timestamp"

func main() {
	addr := flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
	protocol := flag.String("protocol", "", "Protocol to track connections. Defaults to all.")
	engineName := flag.String("engine", "docker", "Engine to track local workload addresses. Defaults to docker.")
	workloadLabelsString := flag.String("workload-labels", "", "Labels to extract from workload. ie (tsuru.io/app-name,tsuru.io/process-name)")
	trackSynSent := flag.Bool("track-syn-sent", false, "Turn on track of stuck connections with syn-sent, will enable automatically the net.netfilter.nf_conntrack_timestamp flag on kernel.")

	dockerEndpoint := flag.String("docker-endpoint", "unix:///var/run/docker.sock", "Docker endpoint.")
	kubeletEndpoint := flag.String("kubelet-endpoint", "https://127.0.0.1:10250/pods", "Kubelet endpoint.")
	kubeletKey := flag.String("kubelet-key", "", "Path to a key to authenticate on kubelet.")
	kubeletCert := flag.String("kubelet-cert", "", "Path to a certificate to authenticate on kubelet.")
	kubeletCA := flag.String("kubelet-ca", "", "Path to a CA to authenticate on kubelet.")

	flag.Parse()

	if *trackSynSent {
		enableConntrackTimestamps()
	}

	http.Handle("/metrics", promhttp.Handler())

	var engine workload.Engine
	var err error
	if *engineName == "kubelet" {
		log.Printf("Fetching workload from kubelet: %s...\n", *kubeletEndpoint)
		engine, err = kubelet.NewEngine(kubelet.Opts{
			Endpoint: *kubeletEndpoint,
			Key:      *kubeletKey,
			Cert:     *kubeletCert,
			CA:       *kubeletCA,
		})
		if err != nil {
			log.Fatal(err)
		}
	} else {
		log.Printf("Fetching workload from docker: %s...\n", *dockerEndpoint)
		engine = docker.NewEngine(*dockerEndpoint)
	}

	workloadLabels := strings.Split(*workloadLabelsString, ",")
	conntrack := collector.NewConntrack(*protocol)
	collector := collector.New(engine, conntrack, workloadLabels)
	prometheus.MustRegister(collector)
	log.Printf("HTTP server listening at %s...\n", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

func enableConntrackTimestamps() {
	val, err := sysctl.Get(conntrackTimestampFlag)
	if err != nil {
		log.Printf("Could not get status of %s, err: %s", conntrackTimestampFlag, err.Error())
		return
	}
	if val == "1" {
		log.Printf("Flag %s is already turned on", conntrackTimestampFlag)
		return
	}
	err = sysctl.Set(conntrackTimestampFlag, "1")
	if err != nil {
		log.Printf("Could not set status of %s, err: %s", conntrackTimestampFlag, err.Error())
		return
	}

	log.Printf("Flag %s was turned on", conntrackTimestampFlag)

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
)

func main() {

	items := create(
		"items",
		[]string{"item_id", "item_name", "type_id", "price"},
	)
	items.insert(1, "apple", 1, 300)
	items.insert(2, "orange", 1, 130)
	items.insert(3, "cabbage", 2, 200)
	items.insert(4, "saury", 3, 220)
	items.insert(5, "seaweed", nil, 250)
	items.insert(6, "mushroom", 3, 180)

	types := create(
		"types",
		[]string{"type_id", "type_name"},
	)
	types.insert(1, "fruit")
	types.insert(2, "vegetable")
	types.insert(3, "fish")

	fmt.Println(items)
	/*
		fmt.Println(from("items"))
		fmt.Println(from("items").selectQ("item_name", "price"))
		fmt.Println(from("items").lessThan("price", 250))
		fmt.Println(from("items").leftJoin("types", "type_id"))
		fmt.Println(
			from(
				from("items").lessThan("price", 250),
			).leftJoin(
				from("types").lessThan("type_id", 3), "type_id",
			),
		)
	*/
}

type tableName string

func (tn tableName) String() string {
	return string(tn)
}

var tables = map[tableName]*table{}

type column struct {
	parent tableName
	name   string
}

func newColumn(parent tableName, name string) *column {
	return &column{parent: parent, name: name}
}

type tuple struct {
	values []interface{}
}

func newTuple(vals []interface{}) *tuple {
	return &tuple{values: vals}
}

func from(s tableName) *table {
	return tables[s]
}

type relation struct {
	columns []*column
	tuples  []*tuple
}

func newRelation(cols []*column, tups []*tuple) *relation {
	return &relation{columns: cols, tuples: tups}
}

func (r *relation) findColumn(name string) int {
	for i, c := range r.columns {
		if c.name == name {
			return i
		}
	}
	// we can simplify checking the existence of n in r,
	// by r.findColumn(n) <= len(r.columns) before random accesses
	return len(r.columns)
}

func (r *relation) selectQ(colNames ...string) *relation {
	idxs := []int{}
	newCols := []*column{}
	for _, cn := range colNames {
		idx := r.findColumn(cn)
		idxs = append(idxs, idx)
		if idx < len(r.columns) {
			newCols = append(newCols, r.columns[idx])
		}
	}
	newTups := []*tuple{}
	for _, tup := range r.tuples {
		vals := []interface{}{}
		for _, idx := range idxs {
			// TODO: Can I avoid to refer the nil pointer?
			if idx < len(tup.values) {
				vals = append(vals, tup.values[idx])
			} else {
				vals = append(vals, nil)
			}
		}
		newTups = append(newTups, newTuple(vals))
	}
	return newRelation(newCols, newTups)
}

func (r *relation) leftJoin(tblName tableName, colName string) *relation {
	t := tables[tblName]
	newCols := []*column{}
	newCols = append(newCols, r.columns...)
	for _, c := range t.columns {
		newCols = append(newCols, newColumn(tblName, c.name))
	}
	rIdx, tIdx := r.findColumn(colName), t.findColumn(colName)
	if len(r.columns) <= rIdx || len(t.columns) <= tIdx {
		return newRelation(newCols, []*tuple{})
	}
	newTups := []*tuple{}
	for _, rTup := range r.tuples {
		if len(rTup.values) <= rIdx {
			continue
		}
		keyVal := rTup.values[rIdx]
		vals := []interface{}{}
		vals = append(vals, rTup.values...)
		// join at non-nil values only
		if keyVal != nil {
			for _, tTup := range t.tuples {
				if len(tTup.values) <= tIdx {
					continue
				}
				if tTup.values[tIdx] == keyVal {
					vals = append(vals, tTup.values...)
					break // join at most one tuple from the rightside table
				}
			}
		}
		for len(vals) < len(newCols) {
			vals = append(vals, nil)
		}
		newTups = append(newTups, newTuple(vals))
	}
	return newRelation(newCols, newTups)
}

func (r *relation) lessThan(colName string, n int) *relation {
	idx := r.findColumn(colName)
	if idx >= len(r.columns) {
		return newRelation(r.columns, []*tuple{})
	}
	newTups := []*tuple{}
	for _, tup := range r.tuples {
		v, ok := tup.values[idx].(int)
		if ok && v < n {
			newTups = append(newTups, tup)
		}
	}
	return newRelation(r.columns, newTups)
}

func (r *relation) String() string {
	var buf bytes.Buffer
	for _, c := range r.columns {
		buf.WriteByte('|')
		if c.parent != "" {
			buf.WriteString(c.parent.String())
			buf.WriteByte('.')
		}
		buf.WriteString(c.name)
	}
	buf.WriteString("|\n")
	for _, t := range r.tuples {
		for _, v := range t.values {
			buf.WriteByte('|')
			buf.WriteString(fmt.Sprint(v))
		}
		buf.WriteString("|\n")
	}
	return buf.String()
}

type table struct {
	relation
	name tableName
}

func newTable(name tableName, cols []*column) *table {
	t := &table{}
	t.name = name
	t.columns = cols
	t.tuples = []*tuple{}
	return t
}

func create(name tableName, colNames []string) *table {
	cols := []*column{}
	for _, cn := range colNames {
		cols = append(cols, newColumn("", cn))
	}
	t := newTable(name, cols)
	tables[name] = t
	return t
}

func (t *table) insert(vals ...interface{}) *table {
	t.tuples = append(t.tuples, newTuple(vals))
	return t
}
<commit_msg>Define the interface for the 'from' constructor<commit_after>package main

import (
	"bytes"
	"fmt"
)

func main() {

	items := create(
		"items",
		[]string{"item_id", "item_name", "type_id", "price"},
	)
	items.insert(1, "apple", 1, 300)
	items.insert(2, "orange", 1, 130)
	items.insert(3, "cabbage", 2, 200)
	items.insert(4, "saury", 3, 220)
	items.insert(5, "seaweed", nil, 250)
	items.insert(6, "mushroom", 3, 180)

	types := create(
		"types",
		[]string{"type_id", "type_name"},
	)
	types.insert(1, "fruit")
	types.insert(2, "vegetable")
	types.insert(3, "fish")

	fmt.Println(items)
	var tblName tableName = "items"
	fmt.Println(from(tblName))
	/*
		fmt.Println(from("items").selectQ("item_name", "price"))
			fmt.Println(from("items").lessThan("price", 250))
			fmt.Println(from("items").leftJoin("types", "type_id"))
			fmt.Println(
				from(
					from("items").lessThan("price", 250),
				).leftJoin(
					from("types").lessThan("type_id", 3), "type_id",
				),
			)
	*/
}

type tableName string

func (tn tableName) String() string {
	return string(tn)
}

var tables = map[tableName]*table{}

type column struct {
	parent tableName
	name   string
}

func newColumn(parent tableName, name string) *column {
	return &column{parent: parent, name: name}
}

type tuple struct {
	values []interface{}
}

func newTuple(vals []interface{}) *tuple {
	return &tuple{values: vals}
}

type relation struct {
	columns []*column
	tuples  []*tuple
}

type relationer interface {
	relation() *relation
}

func (tblName tableName) relation() *relation {
	t := tables[tblName]
	cols := []*column{}
	for _, c := range t.columns {
		cols = append(cols, newColumn(tblName, c.name))
	}
	return newRelation(cols, t.tuples)
}

func (r *relation) relation() *relation {
	return r
}

func from(rel relationer) *relation {
	return rel.relation()
}

func newRelation(cols []*column, tups []*tuple) *relation {
	return &relation{columns: cols, tuples: tups}
}

func (r *relation) findColumn(name string) int {
	for i, c := range r.columns {
		if c.name == name {
			return i
		}
	}
	// we can simplify checking the existence of n in r,
	// by r.findColumn(n) <= len(r.columns) before random accesses
	return len(r.columns)
}

func (r *relation) selectQ(colNames ...string) *relation {
	idxs := []int{}
	newCols := []*column{}
	for _, cn := range colNames {
		idx := r.findColumn(cn)
		idxs = append(idxs, idx)
		if idx < len(r.columns) {
			newCols = append(newCols, r.columns[idx])
		}
	}
	newTups := []*tuple{}
	for _, tup := range r.tuples {
		vals := []interface{}{}
		for _, idx := range idxs {
			// TODO: Can I avoid to refer the nil pointer?
			if idx < len(tup.values) {
				vals = append(vals, tup.values[idx])
			} else {
				vals = append(vals, nil)
			}
		}
		newTups = append(newTups, newTuple(vals))
	}
	return newRelation(newCols, newTups)
}

func (r *relation) leftJoin(tblName tableName, colName string) *relation {
	t := tables[tblName]
	newCols := []*column{}
	newCols = append(newCols, r.columns...)
	for _, c := range t.columns {
		newCols = append(newCols, newColumn(tblName, c.name))
	}
	rIdx, tIdx := r.findColumn(colName), t.findColumn(colName)
	if len(r.columns) <= rIdx || len(t.columns) <= tIdx {
		return newRelation(newCols, []*tuple{})
	}
	newTups := []*tuple{}
	for _, rTup := range r.tuples {
		if len(rTup.values) <= rIdx {
			continue
		}
		keyVal := rTup.values[rIdx]
		vals := []interface{}{}
		vals = append(vals, rTup.values...)
		// join at non-nil values only
		if keyVal != nil {
			for _, tTup := range t.tuples {
				if len(tTup.values) <= tIdx {
					continue
				}
				if tTup.values[tIdx] == keyVal {
					vals = append(vals, tTup.values...)
					break // join at most one tuple from the rightside table
				}
			}
		}
		for len(vals) < len(newCols) {
			vals = append(vals, nil)
		}
		newTups = append(newTups, newTuple(vals))
	}
	return newRelation(newCols, newTups)
}

func (r *relation) lessThan(colName string, n int) *relation {
	idx := r.findColumn(colName)
	if idx >= len(r.columns) {
		return newRelation(r.columns, []*tuple{})
	}
	newTups := []*tuple{}
	for _, tup := range r.tuples {
		v, ok := tup.values[idx].(int)
		if ok && v < n {
			newTups = append(newTups, tup)
		}
	}
	return newRelation(r.columns, newTups)
}

func (r *relation) String() string {
	var buf bytes.Buffer
	for _, c := range r.columns {
		buf.WriteByte('|')
		if c.parent != "" {
			buf.WriteString(c.parent.String())
			buf.WriteByte('.')
		}
		buf.WriteString(c.name)
	}
	buf.WriteString("|\n")
	for _, t := range r.tuples {
		for _, v := range t.values {
			buf.WriteByte('|')
			buf.WriteString(fmt.Sprint(v))
		}
		buf.WriteString("|\n")
	}
	return buf.String()
}

type table struct {
	relation
	name tableName
}

func newTable(name tableName, cols []*column) *table {
	t := &table{}
	t.name = name
	t.columns = cols
	t.tuples = []*tuple{}
	return t
}

func create(name tableName, colNames []string) *table {
	cols := []*column{}
	for _, cn := range colNames {
		cols = append(cols, newColumn("", cn))
	}
	t := newTable(name, cols)
	tables[name] = t
	return t
}

func (t *table) insert(vals ...interface{}) *table {
	t.tuples = append(t.tuples, newTuple(vals))
	return t
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"io"
	"log"
	"math"
	"os"
	"os/signal"

	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/sphere-go-led-controller/ui"
	"github.com/tarm/goserial"
)

func main() {

	ninja, err := ninja.Connect("sphere-led-controller")

	if err != nil {
		log.Fatalf("Failed to connect to mqtt: %s", err)
	}

	layout, wake := ui.NewPaneLayout()

	mqtt := ninja.GetMqttClient()

	lightPane := ui.NewLightPane("images/light-off.png", "images/light-on.png", func(state bool) {
		log.Printf("Light on-off state: %t", state)
	}, func(state float64) {
		log.Printf("Light color state: %f", state)
	}, mqtt)
	layout.AddPane(lightPane)

	fanPane := ui.NewOnOffPane("images/fan-off.png", "images/fan-on.gif", func(state bool) {
		log.Printf("Fan state: %t", state)
	}, mqtt, "fan")
	layout.AddPane(fanPane)

	heaterPane := ui.NewOnOffPane("images/heater-off.png", "images/heater-on.gif", func(state bool) {
		log.Printf("Heater state: %t", state)
	}, mqtt, "heater")
	layout.AddPane(heaterPane)

	// Toggle fan and heater panes every second
	/*go func() {
		state := false
		for {
			time.Sleep(time.Second * 1)
			state = !state
			fanPane.SetState(state)
			heaterPane.SetState(state)
		}
	}()*/

	//	layout.AddPane(ui.NewColorPane(color.RGBA{0, 0, 255, 255}))

	log.Println("starting")
	c := &serial.Config{Name: "/dev/tty.ledmatrix", Baud: 115200}
	s, err := serial.OpenPort(c)
	if err != nil {
		log.Printf("No led matrix? Ignoring... %s", err)
	}

	// Send a blank image to the led matrix
	write(image.NewRGBA(image.Rect(0, 0, 16, 16)), s)

	<-wake

	go func() {
		for {
			//if s == nil {
			//}
			//time.Sleep(time.Second / 10)
			image, wake, err := layout.Render()
			if err != nil {
				log.Fatal(err)
			}

			if s != nil {
				write(image, s)
			} else {
				//	spew.Dump(image)
			}

			if wake != nil {
				log.Println("Waiting as the UI is asleep")
				<-wake
				log.Println("UI woke up!")
			}
		}
	}()

	/*go func() {
		for {
			time.Sleep(time.Second * 4)
			layout.PanLeft()
		}
	}()*/

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

	// Block until a signal is received.
	x := <-blah
	log.Println("Got signal:", x)

	/*	buf := make([]byte, 128)
		n, err = s.Read(buf)
		if err != nil {
		  log.Fatal(err)
		}
		log.Print("%q", buf[:n])*/
}

var cmdWriteBuffer byte = 1
var cmdSwapBuffers byte = 2

func write(image *image.RGBA, s io.ReadWriteCloser) {

	//spew.Dump("writing image", image)

	var frame [768]byte

	for i := 0; i < len(image.Pix); i = i + 4 {
		//log.Println(i)
		frame[i/4*3] = uint8(math.Min(float64(adjustLedBrightness(image.Pix[i]))*1.5, 255))
		frame[(i/4*3)+1] = adjustLedBrightness(image.Pix[i+1])
		frame[(i/4*3)+2] = adjustLedBrightness(image.Pix[i+2])
	}

	rows := split(frame[:], 16*3)

	var orderedRows [][]byte
	for i := 0; i < 8; i++ {
		orderedRows = append(orderedRows, rows[i+8])
		orderedRows = append(orderedRows, rows[i])
	}

	var finalFrame []byte

	for _, line := range orderedRows {
		for i, j := 0, len(line)-1; i < j; i, j = i+1, j-1 {
			line[i], line[j] = line[j], line[i]
		}

		finalFrame = append(finalFrame, line...)
	}

	_, err := s.Write([]byte{cmdWriteBuffer})
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	_, err = s.Write(finalFrame[:])
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	_, err = s.Write([]byte{cmdSwapBuffers})
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	//log.Println("Wrote frame", n)
	buf := make([]byte, 1)
	_, err = s.Read(buf)
	if err != nil {
		log.Fatalf("Failed to read char after sending frame : %s", err)
	}
	if buf[0] != byte('F') {
		log.Fatalf("Expected an 'F', got '%q'", buf[0])
	}
}

func split(a []byte, size int) [][]byte {
	var out [][]byte
	var i = 0
	for i < len(a) {
		out = append(out, a[i:i+size])
		i += size
	}

	return out
}

// From https://diarmuid.ie/blog/post/pwm-exponential-led-fading-on-arduino-or-other-platforms
var R = (255 * math.Log10(2)) / (math.Log10(255))

func adjustLedBrightness(in uint8) byte {
	return uint8(math.Pow(2, (float64(in)/R)) - 1)
}
<commit_msg>Precompute led gamma adjustment<commit_after>package main

import (
	"image"
	"io"
	"log"
	"math"
	"os"
	"os/signal"

	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/sphere-go-led-controller/ui"
	"github.com/tarm/goserial"
)

func main() {

	ninja, err := ninja.Connect("sphere-led-controller")

	if err != nil {
		log.Fatalf("Failed to connect to mqtt: %s", err)
	}

	layout, wake := ui.NewPaneLayout()

	mqtt := ninja.GetMqttClient()

	lightPane := ui.NewLightPane("images/light-off.png", "images/light-on.png", func(state bool) {
		log.Printf("Light on-off state: %t", state)
	}, func(state float64) {
		log.Printf("Light color state: %f", state)
	}, mqtt)
	layout.AddPane(lightPane)

	fanPane := ui.NewOnOffPane("images/fan-off.png", "images/fan-on.gif", func(state bool) {
		log.Printf("Fan state: %t", state)
	}, mqtt, "fan")
	layout.AddPane(fanPane)

	heaterPane := ui.NewOnOffPane("images/heater-off.png", "images/heater-on.gif", func(state bool) {
		log.Printf("Heater state: %t", state)
	}, mqtt, "heater")
	layout.AddPane(heaterPane)

	// Toggle fan and heater panes every second
	/*go func() {
		state := false
		for {
			time.Sleep(time.Second * 1)
			state = !state
			fanPane.SetState(state)
			heaterPane.SetState(state)
		}
	}()*/

	//	layout.AddPane(ui.NewColorPane(color.RGBA{0, 0, 255, 255}))

	log.Println("starting")
	c := &serial.Config{Name: "/dev/tty.ledmatrix", Baud: 115200}
	s, err := serial.OpenPort(c)
	if err != nil {
		log.Printf("No led matrix? Ignoring... %s", err)
	}

	// Send a blank image to the led matrix
	write(image.NewRGBA(image.Rect(0, 0, 16, 16)), s)

	<-wake

	go func() {
		for {
			//if s == nil {
			//}
			//time.Sleep(time.Second / 10)
			image, wake, err := layout.Render()
			if err != nil {
				log.Fatal(err)
			}

			if s != nil {
				write(image, s)
			} else {
				//	spew.Dump(image)
			}

			if wake != nil {
				log.Println("Waiting as the UI is asleep")
				<-wake
				log.Println("UI woke up!")
			}
		}
	}()

	/*go func() {
		for {
			time.Sleep(time.Second * 4)
			layout.PanLeft()
		}
	}()*/

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

	// Block until a signal is received.
	x := <-blah
	log.Println("Got signal:", x)

	/*	buf := make([]byte, 128)
		n, err = s.Read(buf)
		if err != nil {
		  log.Fatal(err)
		}
		log.Print("%q", buf[:n])*/
}

var cmdWriteBuffer byte = 1
var cmdSwapBuffers byte = 2

// From https://diarmuid.ie/blog/post/pwm-exponential-led-fading-on-arduino-or-other-platforms
var R = (255 * math.Log10(2)) / (math.Log10(255))
var ledAdjust = make(map[uint8]uint8)

func init() {
	for i := 0; i < 256; i++ {
		ledAdjust[uint8(i)] = uint8(math.Pow(2, (float64(i)/R)) - 1)
	}
}

func write(image *image.RGBA, s io.ReadWriteCloser) {

	//spew.Dump("writing image", image)

	var frame [768]byte

	for inPos, outPos := 0, 0; inPos < len(image.Pix); inPos = inPos + 4 {

		outPos = inPos / 4 * 3

		frame[outPos] = ledAdjust[image.Pix[inPos]]
		frame[outPos+1] = ledAdjust[image.Pix[inPos+1]]
		frame[outPos+2] = ledAdjust[image.Pix[inPos+2]]
	}

	rows := split(frame[:], 16*3)

	var orderedRows [][]byte
	for i := 0; i < 8; i++ {
		orderedRows = append(orderedRows, rows[i+8])
		orderedRows = append(orderedRows, rows[i])
	}

	var finalFrame []byte

	for _, line := range orderedRows {
		for i, j := 0, len(line)-1; i < j; i, j = i+1, j-1 {
			line[i], line[j] = line[j], line[i]
		}

		finalFrame = append(finalFrame, line...)
	}

	_, err := s.Write([]byte{cmdWriteBuffer})
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	_, err = s.Write(finalFrame[:])
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	_, err = s.Write([]byte{cmdSwapBuffers})
	if err != nil {
		log.Fatal("Failed writing frame", err)
	}

	//log.Println("Wrote frame", n)
	buf := make([]byte, 1)
	_, err = s.Read(buf)
	if err != nil {
		log.Fatalf("Failed to read char after sending frame : %s", err)
	}
	if buf[0] != byte('F') {
		log.Fatalf("Expected an 'F', got '%q'", buf[0])
	}
}

func split(a []byte, size int) [][]byte {
	var out [][]byte
	var i = 0
	for i < len(a) {
		out = append(out, a[i:i+size])
		i += size
	}

	return out
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"time"
)

const (
	timeFormat = "Mon Jan 2 3:04 PM"
)

func emit(t time.Time) {
	cmd := exec.Command("xsetroot", "-name", t.Format(timeFormat))
	cmd.Run()
}

func main() {
	for {
		t := time.Now()
		emit(t)
		time.Sleep(time.Second)
	}
}
<commit_msg>Implemented a battery monitor<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

const (
	timeFormat = "Mon Jan 2 3:04 PM"
	batteryPath = "/sys/class/power_supply/BAT0/"
)

var (
	deviceNotReady = errors.New("Device is not ready for polling")
)

var (
	battInfo *BatteryInfo
)

type BatteryInfo struct {
	hour, min, sec int // time remaining
	capacity int // percent charged
	charging bool
}

func (b *BatteryInfo) String() string {
	if b.charging {
		return fmt.Sprintf("Battery charging, %d%%", b.capacity)
	} else {
		return fmt.Sprintf("On battery, %d:%02d:%02d remaining (%d%%)",
			b.hour, b.min, b.sec, b.capacity)
	}
}

func emit(str string) {
	cmd := exec.Command("xsetroot", "-name", str)
	cmd.Run()
}

func haveBattery() bool {
	_, err := os.Stat(batteryPath)
	return err == nil
}

func slurpFile(filename string) (string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	return string(data), err
}

func pollBattery() (*BatteryInfo, error) {
	var err error
	text := make(map[string] string)
	for _, f := range []string{"status", "capacity", "power_now", "energy_now" } {
		text[f], err = slurpFile(batteryPath + f)
		if err != nil {
			return nil, err
		}
		text[f] = strings.TrimSpace(text[f])
	}

	nums := make(map[string] int)
	for _, f := range []string{"capacity", "power_now", "energy_now"} {
		nums[f], err = strconv.Atoi(text[f])
		if err != nil {
			fmt.Printf("%#v", text[f])
			return nil, err
		}
	}

	capacity, power, energy := nums["capacity"], nums["power_now"], nums["energy_now"]

	if power == 0 {
		// We should wait for the device to settle.
		return nil, deviceNotReady
	}

	result := &BatteryInfo{}

	// work out how much time we have left
	result.hour = energy/power
	energy %= power
	result.min = (60*energy) / power
	energy = (60*energy) % power
	result.sec = (60*energy) / power

	result.capacity = capacity

	result.charging = (text["status"][0] == 'C')
	return result, nil
}

func main() {
	go func() {
		if !haveBattery() {
			return
		}
		for {
			info, err := pollBattery()
			if err == nil {
				battInfo = info
			}
			time.Sleep(time.Second)
		}
	}()

	for {
		t := time.Now()
		batt := battInfo
		if batt != nil {
			emit(fmt.Sprintf("%v | %s", batt, t.Format(timeFormat)))
		} else {
			emit(t.Format(timeFormat))
		}
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strconv"

	"github.com/gizak/termui"
	"github.com/kolo/xmlrpc"
	"github.com/spf13/viper"
)

func main() {
	// handle configurations for server
	viper.SetConfigName("bapu")           // no need to include file extension
	viper.AddConfigPath("/usr/local/etc") // set the path of your config file
	viper.AddConfigPath("../bapu")        // set the path of your config file

	err := viper.ReadInConfig()
	if err != nil {
		log.Fatal(err)
	}

	var apiKey string
	var api *xmlrpc.Client

	production := viper.GetBool("production.enabled")
	if production {
		apiKey = viper.GetString("production.apiKey")
		api, err = xmlrpc.NewClient("https://rpc.gandi.net/xmlrpc/", nil)
		if err != nil {
			log.Fatal(err)
		}
	}

	development := viper.GetBool("development.enabled")
	if development {
		log.Println("Development Config found")
		api, err = xmlrpc.NewClient("https://rpc.ote.gandi.net/xmlrpc/", nil)
		if err != nil {
			log.Fatal(err)
		}
		apiKey = viper.GetString("development.apiKey")
	}

	if api == nil {
		log.Fatal("neither production nor development environment enabled in config")
	}

	// initialize termui
	err = termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()

	// Title
	title := termui.NewPar("Bapu")
	title.Border = false
	title.Height = 1
	title.TextFgColor = termui.ColorMagenta
	title.Width = 10
	title.X = 1
	title.Y = 1

	// List
	strs := []string{
		"[0] github.com/gizak/termui",
		"[1] [你好，世界](fg-blue)",
		"[2] [こんにちは世界](fg-red)",
		"[3] [color output](fg-white,bg-green)",
		"[4] output.go",
		"[5] random_out.go",
		"[6] dashboard.go",
		"[7] nsf/termbox-go"}

	ls := termui.NewList()
	ls.Items = strs
	ls.ItemFgColor = termui.ColorYellow
	ls.BorderLabel = "Servers"
	ls.Height = 20
	ls.Width = 80
	ls.Y = 4

	termui.Render(title, ls)

	// Count number of instances
	var paasCount *int
	err = api.Call("paas.count", apiKey, &paasCount)
	if err != nil {
		log.Fatal(err)
	}

	count := termui.NewPar("# instances: " + strconv.Itoa(*paasCount))
	count.Border = false
	count.Height = 1
	count.TextFgColor = termui.ColorMagenta
	count.Width = 20
	count.X = 1
	count.Y = 2

	termui.Render(count)

	// List instances
	//	var paasList *int
	//	err = api.Call("paas.count", apiKey, &paasCount)
	//	if err != nil {
	//		log.Fatal(err)
	//	}

	// Quit with q
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/<up>", func(termui.Event) {
		termui.Render(ls)
	})

	termui.Loop()
}
<commit_msg>we are talking about iaas not paas<commit_after>package main

import (
	"log"
	"strconv"

	"github.com/gizak/termui"
	"github.com/kolo/xmlrpc"
	"github.com/spf13/viper"
)

func main() {
	// handle configurations for server
	viper.SetConfigName("bapu")           // no need to include file extension
	viper.AddConfigPath("/usr/local/etc") // set the path of your config file
	viper.AddConfigPath("../bapu")        // set the path of your config file

	err := viper.ReadInConfig()
	if err != nil {
		log.Fatal(err)
	}

	var apiKey string
	var api *xmlrpc.Client

	production := viper.GetBool("production.enabled")
	if production {
		apiKey = viper.GetString("production.apiKey")
		api, err = xmlrpc.NewClient("https://rpc.gandi.net/xmlrpc/", nil)
		if err != nil {
			log.Fatal(err)
		}
	}

	development := viper.GetBool("development.enabled")
	if development {
		log.Println("Development Config found")
		api, err = xmlrpc.NewClient("https://rpc.ote.gandi.net/xmlrpc/", nil)
		if err != nil {
			log.Fatal(err)
		}
		apiKey = viper.GetString("development.apiKey")
	}

	if api == nil {
		log.Fatal("neither production nor development environment enabled in config")
	}

	// initialize termui
	err = termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()

	// Title
	title := termui.NewPar("Bapu")
	title.Border = false
	title.Height = 1
	title.TextFgColor = termui.ColorMagenta
	title.Width = 10
	title.X = 1
	title.Y = 1

	// List
	strs := []string{
		"[0] github.com/gizak/termui",
		"[1] [你好，世界](fg-blue)",
		"[2] [こんにちは世界](fg-red)",
		"[3] [color output](fg-white,bg-green)",
		"[4] output.go",
		"[5] random_out.go",
		"[6] dashboard.go",
		"[7] nsf/termbox-go"}

	ls := termui.NewList()
	ls.Items = strs
	ls.ItemFgColor = termui.ColorYellow
	ls.BorderLabel = "Servers"
	ls.Height = 20
	ls.Width = 80
	ls.Y = 4

	termui.Render(title, ls)

	// Count number of instances
	var iaasCount *int
	err = api.Call("hosting.vm.count", apiKey, &iaasCount)
	if err != nil {
		log.Fatal(err)
	}

	count := termui.NewPar("# instances: " + strconv.Itoa(*iaasCount))
	count.Border = false
	count.Height = 1
	count.TextFgColor = termui.ColorMagenta
	count.Width = 20
	count.X = 1
	count.Y = 2

	termui.Render(count)

	// List instances
	//	var iaasList *int
	//	err = api.Call("iaas.count", apiKey, &iaasCount)
	//	if err != nil {
	//		log.Fatal(err)
	//	}

	// Quit with q
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/<up>", func(termui.Event) {
		termui.Render(ls)
	})

	termui.Loop()
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Foursquare Labs Inc.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	_ "expvar"
	_ "net/http/pprof"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/foursquare/fsgo/adminz"
	"github.com/foursquare/fsgo/report"
	"github.com/foursquare/quiver/hfile"
)

var version string = "HEAD?"
var buildTime string = "unknown?"

type SettingDefs struct {
	port    int
	rpcPort int

	downloadOnly bool

	debug bool

	bloom int

	mlock bool

	configJsonUrl string

	cachePath string

	zk            string
	discoveryPath string
}

var Settings SettingDefs

func readSettings() []string {
	s := SettingDefs{}
	flag.IntVar(&s.port, "port", 9999, "listen port")
	flag.IntVar(&s.rpcPort, "rpc-port", 0, "listen port for raw thrift rpc (framed tbinary)")

	flag.BoolVar(&s.debug, "debug", false, "print more output")

	flag.IntVar(&s.bloom, "bloom", 0, "bloom filter wrong-positive % (or 0 to disable): lower numbers use more RAM but filter more queries.")

	flag.BoolVar(&s.downloadOnly, "download-only", false, "exit after downloading remote files to local cache.")

	flag.BoolVar(&s.mlock, "mlock", false, "mlock mapped files in memory rather than copy to heap.")

	flag.StringVar(&s.configJsonUrl, "config-json", "", "URL of collection configuration json")

	flag.StringVar(&s.cachePath, "cache", os.TempDir(), "local path to write files fetched (*not* cleaned up automatically)")

	flag.StringVar(&s.zk, "zookeeper", "", "zookeeper")
	flag.StringVar(&s.discoveryPath, "discovery", "", "service discovery base path")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			`
Usage: %s [options] col1=path1 col2=path2 ...
`, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
	Settings = s

	if (len(flag.Args()) > 0) == (Settings.configJsonUrl != "") {
		log.Println("Collections must be specified OR URL to configuration json.")
		flag.Usage()
		os.Exit(-1)
	}

	return flag.Args()
}

func main() {
	log.Printf("Quiver version %s (built %s, %s).\n\n", version, buildTime, runtime.Version())
	t := time.Now()

	graphite := report.Flag()
	args := readSettings()

	stats := report.NewRecorder().
		EnableGCInfoCollection().
		MaybeReportTo(graphite).
		RegisterHttp().
		SetAsDefault()

	hostname, err := os.Hostname()
	if err != nil {
		hostname = "localhost"
	}

	registrations := new(Registrations)

	if Settings.discoveryPath != "" && !Settings.downloadOnly {
		registrations.Connect()
		defer registrations.Close()
	}

	configs := getCollectionConfig(args)

	log.Println("Loading collections...")

	cs, err := hfile.LoadCollections(configs, Settings.cachePath, Settings.downloadOnly, stats)

	if err != nil {
		log.Fatal(err)
	}

	if Settings.downloadOnly {
		stats.FlushNow()
		return
	}

	if Settings.bloom > 0 {
		beforeBloom := time.Now()
		for _, c := range cs.Collections {
			log.Println("Calculating bloom filter for", c.Name)
			c.CalculateBloom(float64(Settings.bloom) / 100)
		}
		stats.TimeSince("startup.bloom", beforeBloom)
	}

	log.Printf("Serving on http://%s:%d/ \n", hostname, Settings.port)

	http.Handle("/rpc/HFileService", WrapHttpRpcHandler(cs, stats))

	admin := adminz.New()
	admin.KillfilePaths(adminz.Killfiles(Settings.port))

	admin.Servicez(func() interface{} {
		return struct {
			Collections   map[string]*hfile.Reader `json:"collections"`
			Impl          string                   `json:"implementation"`
			QuiverVersion string                   `json:"quiver_version"`
		}{
			cs.Collections,
			"quiver",
			version,
		}
	})

	admin.OnPause(registrations.Leave)
	admin.OnResume(func() {
		if Settings.discoveryPath != "" {
			registrations.Join(hostname, Settings.discoveryPath, configs, 0)
		}
	})

	http.HandleFunc("/hfilez", admin.ServicezHandler)
	http.HandleFunc("/", admin.ServicezHandler)

	http.HandleFunc("/debug/bloom/enable", func(w http.ResponseWriter, r *http.Request) {
		for _, c := range cs.Collections {
			c.EnableBloom()
		}
	})

	http.HandleFunc("/debug/bloom/disable", func(w http.ResponseWriter, r *http.Request) {
		for _, c := range cs.Collections {
			c.DisableBloom()
		}
	})

	http.HandleFunc("/debug/bloom/calc", func(w http.ResponseWriter, r *http.Request) {
		if falsePos, err := strconv.Atoi(r.URL.Query().Get("err")); err != nil {
			http.Error(w, err.Error(), 400)
		} else if falsePos > 99 || falsePos < 1 {
			http.Error(w, "`err` param must be a false pos rate between 0 and 100", 400)
		} else {
			admin.Pause()
			defer admin.Resume()
			for _, c := range cs.Collections {
				fmt.Fprintln(w, "Recalculating bloom for", c.Name)
				c.CalculateBloom(float64(falsePos) / 100)
			}
		}
	})

	runtime.GC()
	stats.FlushNow()

	admin.Start()
	stats.TimeSince("startup.total", t)

	if Settings.rpcPort > 0 {
		s, err := NewTRpcServer(fmt.Sprintf(":%d", Settings.rpcPort), WrapProcessor(cs, stats), thrift.NewTBinaryProtocolFactory(true, true))
		if err != nil {
			log.Fatalln("Could not open RPC port", Settings.rpcPort, err)
		} else {
			if err := s.Listen(); err != nil {
				log.Fatalln("Failed to listen on RPC port", err)
			}
			go func() {
				log.Fatalln(s.Serve())
			}()
			log.Println("Listening for raw RPC on", Settings.rpcPort)
		}

	}

	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", Settings.port), nil))
}
<commit_msg>add package_version arg and surface in servicez<commit_after>// Copyright (C) 2015 Foursquare Labs Inc.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	_ "expvar"
	_ "net/http/pprof"

	"github.com/apache/thrift/lib/go/thrift"
	"github.com/foursquare/fsgo/adminz"
	"github.com/foursquare/fsgo/report"
	"github.com/foursquare/quiver/hfile"
)

var version string = "HEAD?"
var buildTime string = "unknown?"

type SettingDefs struct {
	port    int
	rpcPort int

	downloadOnly bool

	debug bool

	bloom int

	mlock bool

	configJsonUrl string

	cachePath string

	zk             string
	discoveryPath  string
	packageVersion string
}

var Settings SettingDefs

func readSettings() []string {
	s := SettingDefs{}
	flag.IntVar(&s.port, "port", 9999, "listen port")
	flag.IntVar(&s.rpcPort, "rpc-port", 0, "listen port for raw thrift rpc (framed tbinary)")

	flag.BoolVar(&s.debug, "debug", false, "print more output")

	flag.IntVar(&s.bloom, "bloom", 0, "bloom filter wrong-positive % (or 0 to disable): lower numbers use more RAM but filter more queries.")

	flag.BoolVar(&s.downloadOnly, "download-only", false, "exit after downloading remote files to local cache.")

	flag.BoolVar(&s.mlock, "mlock", false, "mlock mapped files in memory rather than copy to heap.")

	flag.StringVar(&s.configJsonUrl, "config-json", "", "URL of collection configuration json")

	flag.StringVar(&s.cachePath, "cache", os.TempDir(), "local path to write files fetched (*not* cleaned up automatically)")

	flag.StringVar(&s.zk, "zookeeper", "", "zookeeper")
	flag.StringVar(&s.discoveryPath, "discovery", "", "service discovery base path")

	flag.StringVar(&s.packageVersion, "package-version", "", "version of the deployed package")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			`
Usage: %s [options] col1=path1 col2=path2 ...
`, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
	Settings = s

	if (len(flag.Args()) > 0) == (Settings.configJsonUrl != "") {
		log.Println("Collections must be specified OR URL to configuration json.")
		flag.Usage()
		os.Exit(-1)
	}

	return flag.Args()
}

func main() {
	log.Printf("Quiver version %s (built %s, %s).\n\n", version, buildTime, runtime.Version())
	t := time.Now()

	graphite := report.Flag()
	args := readSettings()

	stats := report.NewRecorder().
		EnableGCInfoCollection().
		MaybeReportTo(graphite).
		RegisterHttp().
		SetAsDefault()

	hostname, err := os.Hostname()
	if err != nil {
		hostname = "localhost"
	}

	registrations := new(Registrations)

	if Settings.discoveryPath != "" && !Settings.downloadOnly {
		registrations.Connect()
		defer registrations.Close()
	}

	configs := getCollectionConfig(args)

	log.Println("Loading collections...")

	cs, err := hfile.LoadCollections(configs, Settings.cachePath, Settings.downloadOnly, stats)

	if err != nil {
		log.Fatal(err)
	}

	if Settings.downloadOnly {
		stats.FlushNow()
		return
	}

	if Settings.bloom > 0 {
		beforeBloom := time.Now()
		for _, c := range cs.Collections {
			log.Println("Calculating bloom filter for", c.Name)
			c.CalculateBloom(float64(Settings.bloom) / 100)
		}
		stats.TimeSince("startup.bloom", beforeBloom)
	}

	log.Printf("Serving on http://%s:%d/ \n", hostname, Settings.port)

	http.Handle("/rpc/HFileService", WrapHttpRpcHandler(cs, stats))

	admin := adminz.New()
	admin.KillfilePaths(adminz.Killfiles(Settings.port))

	admin.Servicez(func() interface{} {
		return struct {
			Collections    map[string]*hfile.Reader `json:"collections"`
			Impl           string                   `json:"implementation"`
			QuiverVersion  string                   `json:"quiver_version"`
			PackageVersion string                   `json:"package_version"`
		}{
			cs.Collections,
			"quiver",
			version,
			Settings.packageVersion,
		}
	})

	admin.OnPause(registrations.Leave)
	admin.OnResume(func() {
		if Settings.discoveryPath != "" {
			registrations.Join(hostname, Settings.discoveryPath, configs, 0)
		}
	})

	http.HandleFunc("/hfilez", admin.ServicezHandler)
	http.HandleFunc("/", admin.ServicezHandler)

	http.HandleFunc("/debug/bloom/enable", func(w http.ResponseWriter, r *http.Request) {
		for _, c := range cs.Collections {
			c.EnableBloom()
		}
	})

	http.HandleFunc("/debug/bloom/disable", func(w http.ResponseWriter, r *http.Request) {
		for _, c := range cs.Collections {
			c.DisableBloom()
		}
	})

	http.HandleFunc("/debug/bloom/calc", func(w http.ResponseWriter, r *http.Request) {
		if falsePos, err := strconv.Atoi(r.URL.Query().Get("err")); err != nil {
			http.Error(w, err.Error(), 400)
		} else if falsePos > 99 || falsePos < 1 {
			http.Error(w, "`err` param must be a false pos rate between 0 and 100", 400)
		} else {
			admin.Pause()
			defer admin.Resume()
			for _, c := range cs.Collections {
				fmt.Fprintln(w, "Recalculating bloom for", c.Name)
				c.CalculateBloom(float64(falsePos) / 100)
			}
		}
	})

	runtime.GC()
	stats.FlushNow()

	admin.Start()
	stats.TimeSince("startup.total", t)

	if Settings.rpcPort > 0 {
		s, err := NewTRpcServer(fmt.Sprintf(":%d", Settings.rpcPort), WrapProcessor(cs, stats), thrift.NewTBinaryProtocolFactory(true, true))
		if err != nil {
			log.Fatalln("Could not open RPC port", Settings.rpcPort, err)
		} else {
			if err := s.Listen(); err != nil {
				log.Fatalln("Failed to listen on RPC port", err)
			}
			go func() {
				log.Fatalln(s.Serve())
			}()
			log.Println("Listening for raw RPC on", Settings.rpcPort)
		}

	}

	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", Settings.port), nil))
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/vikashvverma/greeter/config"
	"github.com/vikashvverma/greeter/job"
)

func main() {
	c := config.ReadConfig("./config.json")
	if c == nil {
		log.Fatal("Could not read config file!")
	}
	g := job.NewGreeter(c)
	s := job.NewScheduler(c.Time, g)
	gocron, err := s.Schedule()
	if err != nil {
		log.Fatalf("ListenAndServe: %s", err)
	}
	<-gocron.Start()
}
<commit_msg>Update error message :heart_eyes:<commit_after>package main

import (
	"log"

	"github.com/vikashvverma/greeter/config"
	"github.com/vikashvverma/greeter/job"
)

func main() {
	c := config.ReadConfig("./config.json")
	if c == nil {
		log.Fatal("Could not read config file!")
	}
	g := job.NewGreeter(c)
	s := job.NewScheduler(c.Time, g)
	gocron, err := s.Schedule()
	if err != nil {
		log.Fatalf("main: %s", err)
	}
	<-gocron.Start()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/http"
)

func main() {
	// Add flag for listening on a different port
	port := flag.String("port", "10181", "Port to listen on.")
	flag.Parse()

	sf := NewSunfish()
	defer sf.Close()
	err := http.ListenAndServe(":"+*port, sf.Router)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Switched panic to fmt with exit<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
)

func main() {
	// Add flag for listening on a different port
	port := flag.String("port", "10181", "Port to listen on.")
	flag.Parse()

	sf := NewSunfish()
	defer sf.Close()
	err := http.ListenAndServe(":"+*port, sf.Router)
	if err != nil {
		fmt.Println("Error attempting to listen and serve on port: " + *port)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/jhunt/safe/vault"
)

var Version string

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

func notok(err error) {
	if err == nil {
		fmt.Fprintf(os.Stderr, "expected an error, but nothing failed!\n")
		os.Exit(1)
	}
}

func DELETE(v *vault.Vault, path string) {
	fmt.Printf("DELETE %s\n", path)
	err := v.Delete(path)
	ok(err)
	READ(v, path)
	fmt.Printf("\n")
}

func READ(v *vault.Vault, path string) {
	secret, _ := v.Read(path)
	fmt.Printf("READ %s: %v\n", path, secret)
}

func COPY(v *vault.Vault, oldpath, newpath string) {
	fmt.Printf("COPY %s -> %s\n", oldpath, newpath)
	err := v.Copy(oldpath, newpath)
	ok(err)
	READ(v, oldpath)
	READ(v, newpath)
	fmt.Printf("\n")
}

func MOVE(v *vault.Vault, oldpath, newpath string) {
	fmt.Printf("MOVE %s -> %s\n", oldpath, newpath)
	err := v.Move(oldpath, newpath)
	ok(err)
	READ(v, oldpath)
	READ(v, newpath)
	fmt.Printf("\n")
}

func connect() *vault.Vault {
	v, err := vault.NewVault(os.Getenv("VAULT_ADDR"), "")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	return v
}

func main() {
	r := NewRunner()
	r.Dispatch("version", func(command string, args ...string) error {
		if Version != "" {
			fmt.Printf("safe v%s\n", Version)
		} else {
			fmt.Printf("safe (development build)\n")
		}
		os.Exit(0)
		return nil
	}, "-v", "--version")

	r.Dispatch("set", func(command string, args ...string) error {
		if len(args) < 2 {
			return fmt.Errorf("USAGE: set path key[=value] [key ...]")
		}
		v := connect()
		path, args := args[0], args[1:]
		s, err := v.Read(path)
		if err != nil && err != vault.NotFound {
			return err
		}
		for _, set := range args {
			k, v := keyPrompt(set)
			s.Set(k, v)
		}
		return v.Write(path, s)
	}, "write")

	r.Dispatch("get", func(command string, args ...string) error {
		if len(args) < 1 {
			return fmt.Errorf("USAGE: get path [path ...]")
		}
		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil {
				return err
			}
			fmt.Printf("--- # %s\n", path)
			fmt.Printf("%s\n\n", s.YAML())
		}
		return nil
	}, "read", "cat")

	r.Dispatch("delete", func(command string, args ...string) error {
		if len(args) < 1 {
			return fmt.Errorf("USAGE: delete path [path ...]")
		}
		v := connect()
		for _, path := range args {
			if err := v.Delete(path); err != nil {
				return err
			}
		}
		return nil
	}, "rm")

	r.Dispatch("move", func (command string, args ...string) error {
		if len(args) != 2 {
			return fmt.Errorf("USAGE: move oldpath newpath")
		}
		v := connect()
		return v.Move(args[0], args[1])
	}, "mv", "rename")

	r.Dispatch("copy", func(command string, args ...string) error {
		if len(args) != 2 {
			return fmt.Errorf("USAGE: copy oldpath newpath")
		}
		v := connect()
		return v.Copy(args[0], args[1])
	}, "cp")

	r.Dispatch("gen", func(command string, args ...string) error {
		length := 64
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				length = int(u)
				args = args[1:]
			}
		}

		if len(args) != 2 {
			return fmt.Errorf("USAGE: gen [length] path key")
		}

		v := connect()
		path, key := args[0], args[1]
		s, err := v.Read(path)
		if err != nil && err != vault.NotFound {
			return err
		}
		s.Password(key, length)
		if err = v.Write(path, s); err != nil {
			return err
		}
		return nil
	}, "auto")

	r.Dispatch("ssh", func(command string, args ...string) error {
		bits := 2048
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				bits = int(u)
				args = args[1:]
			}
		}

		if len(args) < 1 {
			return fmt.Errorf("USAGE: ssh [bits] path [path ...]")
		}

		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil && err != vault.NotFound {
				return err
			}
			if err = s.SSHKey(bits); err != nil {
				return err
			}
			if err = v.Write(path, s); err != nil {
				return err
			}
		}
		return nil
	})

	r.Dispatch("rsa", func(command string, args ...string) error {
		bits := 2048
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				bits = int(u)
				args = args[1:]
			}
		}

		if len(args) < 1 {
			return fmt.Errorf("USAGE: rsa [bits] path [path ...]")
		}

		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil && err != vault.NotFound {
				return err
			}
			if err = s.SSHKey(bits); err != nil {
				return err
			}
			if err = v.Write(path, s); err != nil {
				return err
			}
		}
		return nil
	})

	if err := r.Run(os.Args[1:]...); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

func main2() {
	fmt.Printf("starting up\n")
	v, err := vault.NewVault(os.Getenv("VAULT_ADDR"), "")
	ok(err)

	DELETE(v, "secret/other")
	DELETE(v, "secret/copy")
	READ(v, "secret/handshake")

	COPY(v, "secret/handshake", "secret/copy")
	MOVE(v, "secret/copy", "secret/other")

	DELETE(v, "secret/ssh")
	s := vault.NewSecret()
	err = s.SSHKey(2048); ok(err)
	err = v.Write("secret/ssh", s); ok(err)
	READ(v, "secret/ssh")

	DELETE(v, "secret/rsa")
	s = vault.NewSecret()
	err = s.RSAKey(2048); ok(err)
	err = v.Write("secret/rsa", s); ok(err)
	READ(v, "secret/rsa")

	fmt.Printf("shutting down...\n")
}
<commit_msg>Remove cruft from main binary<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/jhunt/safe/vault"
)

var Version string

func connect() *vault.Vault {
	v, err := vault.NewVault(os.Getenv("VAULT_ADDR"), "")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	return v
}

func main() {
	r := NewRunner()
	r.Dispatch("version", func(command string, args ...string) error {
		if Version != "" {
			fmt.Printf("safe v%s\n", Version)
		} else {
			fmt.Printf("safe (development build)\n")
		}
		os.Exit(0)
		return nil
	}, "-v", "--version")

	r.Dispatch("set", func(command string, args ...string) error {
		if len(args) < 2 {
			return fmt.Errorf("USAGE: set path key[=value] [key ...]")
		}
		v := connect()
		path, args := args[0], args[1:]
		s, err := v.Read(path)
		if err != nil && err != vault.NotFound {
			return err
		}
		for _, set := range args {
			k, v := keyPrompt(set)
			s.Set(k, v)
		}
		return v.Write(path, s)
	}, "write")

	r.Dispatch("get", func(command string, args ...string) error {
		if len(args) < 1 {
			return fmt.Errorf("USAGE: get path [path ...]")
		}
		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil {
				return err
			}
			fmt.Printf("--- # %s\n", path)
			fmt.Printf("%s\n\n", s.YAML())
		}
		return nil
	}, "read", "cat")

	r.Dispatch("delete", func(command string, args ...string) error {
		if len(args) < 1 {
			return fmt.Errorf("USAGE: delete path [path ...]")
		}
		v := connect()
		for _, path := range args {
			if err := v.Delete(path); err != nil {
				return err
			}
		}
		return nil
	}, "rm")

	r.Dispatch("move", func (command string, args ...string) error {
		if len(args) != 2 {
			return fmt.Errorf("USAGE: move oldpath newpath")
		}
		v := connect()
		return v.Move(args[0], args[1])
	}, "mv", "rename")

	r.Dispatch("copy", func(command string, args ...string) error {
		if len(args) != 2 {
			return fmt.Errorf("USAGE: copy oldpath newpath")
		}
		v := connect()
		return v.Copy(args[0], args[1])
	}, "cp")

	r.Dispatch("gen", func(command string, args ...string) error {
		length := 64
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				length = int(u)
				args = args[1:]
			}
		}

		if len(args) != 2 {
			return fmt.Errorf("USAGE: gen [length] path key")
		}

		v := connect()
		path, key := args[0], args[1]
		s, err := v.Read(path)
		if err != nil && err != vault.NotFound {
			return err
		}
		s.Password(key, length)
		if err = v.Write(path, s); err != nil {
			return err
		}
		return nil
	}, "auto")

	r.Dispatch("ssh", func(command string, args ...string) error {
		bits := 2048
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				bits = int(u)
				args = args[1:]
			}
		}

		if len(args) < 1 {
			return fmt.Errorf("USAGE: ssh [bits] path [path ...]")
		}

		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil && err != vault.NotFound {
				return err
			}
			if err = s.SSHKey(bits); err != nil {
				return err
			}
			if err = v.Write(path, s); err != nil {
				return err
			}
		}
		return nil
	})

	r.Dispatch("rsa", func(command string, args ...string) error {
		bits := 2048
		if len(args) > 0 {
			if u, err := strconv.ParseUint(args[0], 10, 16); err == nil {
				bits = int(u)
				args = args[1:]
			}
		}

		if len(args) < 1 {
			return fmt.Errorf("USAGE: rsa [bits] path [path ...]")
		}

		v := connect()
		for _, path := range args {
			s, err := v.Read(path)
			if err != nil && err != vault.NotFound {
				return err
			}
			if err = s.SSHKey(bits); err != nil {
				return err
			}
			if err = v.Write(path, s); err != nil {
				return err
			}
		}
		return nil
	})

	if err := r.Run(os.Args[1:]...); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	log "github.com/cihub/seelog"
	"github.com/coreos/etcd/client"
	"github.com/nlopes/slack"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

func main() {
	defer log.Flush()
	flag.Parse()
	err := initLogger()
	if err != nil {
		log.Critical(err)
		return
	}

	serveBot()
	log.Info("Now shutting down.")
}

func serveBot() {
	endpoints := os.Getenv("BOT_ETCD_ENDPOINTS")
	if endpoints == "" {
		endpoints = "http://localhost:2379"
	}
	c, err := client.New(client.Config{
		Endpoints:               strings.Split(endpoints, ","),
		Transport:               client.DefaultTransport,
		Username:                os.Getenv("BOT_ETCD_USER"),
		Password:                os.Getenv("BOT_ETCD_PASSWORD"),
		HeaderTimeoutPerRequest: time.Second,
	})
	if err != nil {
		log.Critical(err)
		os.Exit(1)
	}

	metaDir := os.Getenv("BOT_METADATA_DIR")
	if metaDir == "" {
		metaDir = "/etcdbot_meta/"
	}
	watchBase := os.Getenv("BOT_WATCH_TARGET_BASE")
	if watchBase == "" {
		watchBase = "/public/"
	}

	keysApi := client.NewKeysAPI(c)

	key := os.Getenv("BOT_SLACK_API_KEY")
	if key == "" {
		log.Critical("Missing slack api key!")
		os.Exit(1)
	}

	api := slack.New(key)
	auth, err := api.AuthTest()
	if err != nil {
		log.Critical(err)
		os.Exit(1)
	}
	id := auth.UserID

	rtm := api.NewRTM()
	defer rtm.Disconnect()
	mngCh := make(chan int, 1)
	go func() {
		rtm.ManageConnection()
		close(mngCh)
	}()

	conf := &Config{rtm: rtm, keysApi: keysApi, metaDir: metaDir, watchBase: watchBase}

	log.Info("Starting RTM loop...")

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.ConnectedEvent:
				log.Info("RTM connected...")
			case *slack.MessageEvent:
				if strings.HasPrefix(ev.Text, "<@"+id+">") {
					log.Info("User: ", ev.User, ", Channel: ", ev.Channel, ", Text: ", ev.Text)
					conf.run(ev.Channel, strings.Fields(ev.Text)[1:])
				}
			case *slack.InvalidAuthEvent:
				log.Error("Invalid credentials")
				return
			case *slack.DisconnectedEvent:
				if ev.Intentional {
					log.Info("RTM connection intentionally closed.")
					return
				}
			}
		case <-mngCh:
			log.Error("ManageConnection goroutine unexpectedly finished!!!")
			return
		case sig := <-sigCh:
			log.Infof("Signal(%v) recieved", sig)
			return
		}
	}
}
<commit_msg>add hang up check<commit_after>package main

import (
	"flag"
	log "github.com/cihub/seelog"
	"github.com/coreos/etcd/client"
	"github.com/nlopes/slack"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

func main() {
	defer log.Flush()
	flag.Parse()
	err := initLogger()
	if err != nil {
		log.Critical(err)
		return
	}

	serveBot()
	log.Info("Now shutting down.")
}

func serveBot() {
	endpoints := os.Getenv("BOT_ETCD_ENDPOINTS")
	if endpoints == "" {
		endpoints = "http://localhost:2379"
	}
	c, err := client.New(client.Config{
		Endpoints:               strings.Split(endpoints, ","),
		Transport:               client.DefaultTransport,
		Username:                os.Getenv("BOT_ETCD_USER"),
		Password:                os.Getenv("BOT_ETCD_PASSWORD"),
		HeaderTimeoutPerRequest: time.Second,
	})
	if err != nil {
		log.Critical(err)
		os.Exit(1)
	}

	metaDir := os.Getenv("BOT_METADATA_DIR")
	if metaDir == "" {
		metaDir = "/etcdbot_meta/"
	}
	watchBase := os.Getenv("BOT_WATCH_TARGET_BASE")
	if watchBase == "" {
		watchBase = "/public/"
	}

	keysApi := client.NewKeysAPI(c)

	key := os.Getenv("BOT_SLACK_API_KEY")
	if key == "" {
		log.Critical("Missing slack api key!")
		os.Exit(1)
	}

	api := slack.New(key)
	auth, err := api.AuthTest()
	if err != nil {
		log.Critical(err)
		os.Exit(1)
	}
	id := auth.UserID

	rtm := api.NewRTM()
	defer rtm.Disconnect()
	mngCh := make(chan int, 1)
	go func() {
		rtm.ManageConnection()
		close(mngCh)
	}()

	conf := &Config{rtm: rtm, keysApi: keysApi, metaDir: metaDir, watchBase: watchBase}

	log.Info("Starting RTM loop...")

	hangCheck := time.NewTicker(time.Second)
	defer hangCheck.Stop()
	lastIncomingEvent := time.Now() // sentinel

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			lastIncomingEvent = time.Now()

			switch ev := msg.Data.(type) {
			case *slack.ConnectedEvent:
				log.Info("RTM connected...")
			case *slack.MessageEvent:
				if strings.HasPrefix(ev.Text, "<@"+id+">") {
					log.Info("User: ", ev.User, ", Channel: ", ev.Channel, ", Text: ", ev.Text)
					conf.run(ev.Channel, strings.Fields(ev.Text)[1:])
				}
			case *slack.InvalidAuthEvent:
				log.Error("Invalid credentials")
				return
			case *slack.DisconnectedEvent:
				if ev.Intentional {
					log.Info("RTM connection intentionally closed.")
					return
				} else {
					log.Error("RTM connection unexpectedly closed.")
				}
			}
		case <-hangCheck.C:
			if lastIncomingEvent.Add(61 * time.Second).Before(time.Now()) {
				// PING/PONG event should create a LatencyReport IncomingEvent at 30 second-interval.
				// So it may be hanged up.
				log.Critical("RTM connection may be hanged up.")
				return
			}
		case <-mngCh:
			log.Error("ManageConnection goroutine unexpectedly finished!!!")
			return
		case sig := <-sigCh:
			log.Infof("Signal(%v) recieved", sig)
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/ant0ine/go-json-rest/rest"
  "github.com/PuerkitoBio/goquery"
  //"github.com/k0kubun/pp"
  "log"
  "fmt"
  "net/http"
  "sync"
  "strconv"
  "runtime"
)

type PostData struct {
  Url string
}

type List struct {
  Url []string
  User []User
}

type User struct {
  Name string
  Image string
  CancelCount int
  JoinCount int
}

func main() {
  api := rest.NewApi()
  api.Use(rest.DefaultDevStack...)
  router, err := rest.MakeRouter(
    rest.Post("/", PostCancel),
  )

  if err != nil {
    log.Fatal(err)
  }

  api.SetApp(router)
  log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}

func PostCancel(w rest.ResponseWriter, r *rest.Request) {
  cpus := runtime.NumCPU()
  runtime.GOMAXPROCS(cpus)

  post_data := PostData{}
  err := r.DecodeJsonPayload(&post_data)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  if post_data.Url == "" {
    rest.Error(w, "url required", 400)
  }

  list := List{}
  fmt.Println(post_data.Url)
  GetPageToConnpass(post_data.Url, &list)

  wg := new(sync.WaitGroup)
  for _, url := range list.Url {
    wg.Add(1)
    go GetUserPageToConnpass(&list, url, wg)
  }
  wg.Wait()

  w.WriteJson(list.User)
  // pp.Println(list.User)
}

func GetPageToConnpass(url string, list *List) {
  doc, _ := goquery.NewDocument(url + "participation/#participants")
  doc.Find(".user").Each(func(_ int, s *goquery.Selection) {
    s.Find(".image_link").Each(func(_ int, s *goquery.Selection) {
      url, _ := s.Attr("href")
      list.Url = append(list.Url, url)
    })
  })
}

func GetUserPageToConnpass(list *List, url string, wg *sync.WaitGroup) {
  // 退会ユーザーなどはURLが取れないため無視
  if url != "" {
    user := User{"", "", 0, 0}

    doc, _ := goquery.NewDocument(url)
    image_elm := doc.Find("#side_area > div.mb_20.text_center img")
    user.Name, _ = image_elm.Attr("title")
    user.Image, _ = image_elm.Attr("src")
    doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
      join_status := s.Find("p.label_status_tag").Text()
      if join_status == "キャンセル" {
        user.CancelCount++
      } else {
        user.JoinCount++
      }
    })

    // ページ数が１以上ある場合
    if (doc.Find("#main > div.paging_area > ul > li").Length() - 1) > 1 {
      total_page := doc.Find("#main > div.paging_area > ul > li").Length() - 1

      for i := 2; i <= total_page; i++ {
        doc, _ := goquery.NewDocument(url + "?page=" + strconv.Itoa(i))
        doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
          join_status := s.Find("p.label_status_tag").Text()
          if join_status == "キャンセル" {
            user.CancelCount++
          } else {
            user.JoinCount++
          }
        })
      }
    }

    list.User = append(list.User, user)
  }
  wg.Done()
}
<commit_msg>commit<commit_after>package main

import (
  "vendor/github.com/ant0ine/go-json-rest/rest"
  "vendor/github.com/PuerkitoBio/goquery"
  //"github.com/k0kubun/pp"
  "log"
  "fmt"
  "net/http"
  "sync"
  "strconv"
  "runtime"
)

type PostData struct {
  Url string
}

type List struct {
  Url []string
  User []User
}

type User struct {
  Name string
  Image string
  CancelCount int
  JoinCount int
}

func main() {
  api := rest.NewApi()
  api.Use(rest.DefaultDevStack...)
  router, err := rest.MakeRouter(
    rest.Post("/", PostCancel),
  )

  if err != nil {
    log.Fatal(err)
  }

  api.SetApp(router)
  log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}

func PostCancel(w rest.ResponseWriter, r *rest.Request) {
  cpus := runtime.NumCPU()
  runtime.GOMAXPROCS(cpus)

  post_data := PostData{}
  err := r.DecodeJsonPayload(&post_data)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  if post_data.Url == "" {
    rest.Error(w, "url required", 400)
  }

  list := List{}
  fmt.Println(post_data.Url)
  GetPageToConnpass(post_data.Url, &list)

  wg := new(sync.WaitGroup)
  for _, url := range list.Url {
    wg.Add(1)
    go GetUserPageToConnpass(&list, url, wg)
  }
  wg.Wait()

  w.WriteJson(list.User)
  // pp.Println(list.User)
}

func GetPageToConnpass(url string, list *List) {
  doc, _ := goquery.NewDocument(url + "participation/#participants")
  doc.Find(".user").Each(func(_ int, s *goquery.Selection) {
    s.Find(".image_link").Each(func(_ int, s *goquery.Selection) {
      url, _ := s.Attr("href")
      list.Url = append(list.Url, url)
    })
  })
}

func GetUserPageToConnpass(list *List, url string, wg *sync.WaitGroup) {
  // 退会ユーザーなどはURLが取れないため無視
  if url != "" {
    user := User{"", "", 0, 0}

    doc, _ := goquery.NewDocument(url)
    image_elm := doc.Find("#side_area > div.mb_20.text_center img")
    user.Name, _ = image_elm.Attr("title")
    user.Image, _ = image_elm.Attr("src")
    doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
      join_status := s.Find("p.label_status_tag").Text()
      if join_status == "キャンセル" {
        user.CancelCount++
      } else {
        user.JoinCount++
      }
    })

    // ページ数が１以上ある場合
    if (doc.Find("#main > div.paging_area > ul > li").Length() - 1) > 1 {
      total_page := doc.Find("#main > div.paging_area > ul > li").Length() - 1

      for i := 2; i <= total_page; i++ {
        doc, _ := goquery.NewDocument(url + "?page=" + strconv.Itoa(i))
        doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
          join_status := s.Find("p.label_status_tag").Text()
          if join_status == "キャンセル" {
            user.CancelCount++
          } else {
            user.JoinCount++
          }
        })
      }
    }

    list.User = append(list.User, user)
  }
  wg.Done()
}
<|endoftext|>