<commit_before>/*
Copyright 2018 The Knative Authors

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 (
	"context"
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"

	// Injection related imports.
	kubeclient "knative.dev/pkg/client/injection/kube/client"
	"knative.dev/pkg/injection"
	revisioninformer "knative.dev/serving/pkg/client/injection/informers/serving/v1alpha1/revision"

	"github.com/kelseyhightower/envconfig"
	"go.opencensus.io/stats/view"
	"go.uber.org/zap"
	"k8s.io/apimachinery/pkg/util/wait"
	"knative.dev/pkg/configmap"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/injection/sharedmain"
	pkglogging "knative.dev/pkg/logging"
	"knative.dev/pkg/logging/logkey"
	"knative.dev/pkg/metrics"
	pkgnet "knative.dev/pkg/network"
	"knative.dev/pkg/profiling"
	"knative.dev/pkg/signals"
	"knative.dev/pkg/system"
	"knative.dev/pkg/tracing"
	tracingconfig "knative.dev/pkg/tracing/config"
	"knative.dev/pkg/version"
	"knative.dev/pkg/websocket"
	"knative.dev/serving/pkg/activator"
	activatorconfig "knative.dev/serving/pkg/activator/config"
	activatorhandler "knative.dev/serving/pkg/activator/handler"
	activatornet "knative.dev/serving/pkg/activator/net"
	"knative.dev/serving/pkg/apis/networking"
	"knative.dev/serving/pkg/autoscaler"
	"knative.dev/serving/pkg/goversion"
	pkghttp "knative.dev/serving/pkg/http"
	"knative.dev/serving/pkg/logging"
	"knative.dev/serving/pkg/network"
	"knative.dev/serving/pkg/queue"
)

// Fail if using unsupported go version.
var _ = goversion.IsSupported()

const (
	component = "activator"

	// Add enough buffer to not block request serving on stats collection
	requestCountingQueueLength = 100

	// The number of requests that are queued on the breaker before the 503s are sent.
	// The value must be adjusted depending on the actual production requirements.
	breakerQueueDepth = 10000

	// The upper bound for concurrent requests sent to the revision.
	// As new endpoints show up, the Breakers concurrency increases up to this value.
	breakerMaxConcurrency = 1000

	// The port on which autoscaler WebSocket server listens.
	autoscalerPort = ":8080"
)

var (
	masterURL = flag.String("master", "", "The address of the Kubernetes API server. "+
		"Overrides any value in kubeconfig. Only required if out-of-cluster.")
	kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
)

func statReporter(statSink *websocket.ManagedConnection, stopCh <-chan struct{},
	statChan <-chan []autoscaler.StatMessage, logger *zap.SugaredLogger) {
	for {
		select {
		case sm := <-statChan:
			go func() {
				for _, msg := range sm {
					if err := statSink.Send(msg); err != nil {
						logger.Errorw("Error while sending stat", zap.Error(err))
					}
				}
			}()
		case <-stopCh:
			// It's a sending connection, so no drainage required.
			statSink.Shutdown()
			return
		}
	}
}

type config struct {
	PodName string `split_words:"true" required:"true"`
	PodIP   string `split_words:"true" required:"true"`
}

func main() {
	flag.Parse()

	// Set up a context that we can cancel to tell informers and other subprocesses to stop.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Report stats on Go memory usage every 30 seconds.
	msp := metrics.NewMemStatsAll()
	msp.Start(ctx, 30*time.Second)
	if err := view.Register(msp.DefaultViews()...); err != nil {
		log.Fatalf("Error exporting go memstats view: %v", err)
	}

	cfg, err := sharedmain.GetConfig(*masterURL, *kubeconfig)
	if err != nil {
		log.Fatal("Error building kubeconfig:", err)
	}

	log.Printf("Registering %d clients", len(injection.Default.GetClients()))
	log.Printf("Registering %d informer factories", len(injection.Default.GetInformerFactories()))
	log.Printf("Registering %d informers", len(injection.Default.GetInformers()))

	ctx, informers := injection.Default.SetupInformers(ctx, cfg)

	// Set up our logger.
	loggingConfig, err := sharedmain.GetLoggingConfig(ctx)
	if err != nil {
		log.Fatal("Error loading/parsing logging configuration:", err)
	}
	logger, atomicLevel := pkglogging.NewLoggerFromConfig(loggingConfig, component)
	logger = logger.With(zap.String(logkey.ControllerType, component))
	ctx = pkglogging.WithLogger(ctx, logger)
	defer flush(logger)

	kubeClient := kubeclient.Get(ctx)

	// Run informers instead of starting them from the factory to prevent the sync hanging because of empty handler.
	if err := controller.StartInformers(ctx.Done(), informers...); err != nil {
		logger.Fatalw("Failed to start informers", zap.Error(err))
	}

	logger.Info("Starting the knative activator")

	var env config
	if err := envconfig.Process("", &env); err != nil {
		logger.Fatalw("Failed to process env", zap.Error(err))
	}

	// We sometimes startup faster than we can reach kube-api. Poll on failure to prevent us terminating
	if perr := wait.PollImmediate(time.Second, 60*time.Second, func() (bool, error) {
		if err = version.CheckMinimumVersion(kubeClient.Discovery()); err != nil {
			logger.Errorw("Failed to get k8s version", zap.Error(err))
		}
		return err == nil, nil
	}); perr != nil {
		logger.Fatalw("Timed out attempting to get k8s version", zap.Error(err))
	}

	reporter, err := activator.NewStatsReporter()
	if err != nil {
		logger.Fatalw("Failed to create stats reporter", zap.Error(err))
	}

	statCh := make(chan []autoscaler.StatMessage)
	defer close(statCh)

	reqCh := make(chan activatorhandler.ReqEvent, requestCountingQueueLength)
	defer close(reqCh)

	params := queue.BreakerParams{QueueDepth: breakerQueueDepth, MaxConcurrency: breakerMaxConcurrency, InitialCapacity: 0}

	// Start throttler.
	throttler := activatornet.NewThrottler(ctx, params,
		// We want to join host port since that will be our search space in the Throttler.
		net.JoinHostPort(env.PodIP, strconv.Itoa(networking.BackendHTTPPort)))
	go throttler.Run(ctx)

	oct := tracing.NewOpenCensusTracer(tracing.WithExporter(networking.ActivatorServiceName, logger))

	tracerUpdater := configmap.TypeFilter(&tracingconfig.Config{})(func(name string, value interface{}) {
		cfg := value.(*tracingconfig.Config)
		if err := oct.ApplyConfig(cfg); err != nil {
			logger.Errorw("Unable to apply open census tracer config", zap.Error(err))
			return
		}
	})

	// Set up our config store
	configMapWatcher := configmap.NewInformedWatcher(kubeClient, system.Namespace())
	configStore := activatorconfig.NewStore(logger, tracerUpdater)
	configStore.WatchConfigs(configMapWatcher)

	// Open a WebSocket connection to the autoscaler.
	autoscalerEndpoint := fmt.Sprintf("ws://%s.%s.svc.%s%s", "autoscaler", system.Namespace(), pkgnet.GetClusterDomainName(), autoscalerPort)
	logger.Info("Connecting to Autoscaler at ", autoscalerEndpoint)
	statSink := websocket.NewDurableSendingConnection(autoscalerEndpoint, logger)
	go statReporter(statSink, ctx.Done(), statCh, logger)

	// Create and run our concurrency reporter
	reportTicker := time.NewTicker(time.Second)
	defer reportTicker.Stop()
	cr := activatorhandler.NewConcurrencyReporter(ctx, env.PodName, reqCh,
		reportTicker.C, statCh, reporter)
	go cr.Run(ctx.Done())

	// Create activation handler chain
	// Note: innermost handlers are specified first, ie. the last handler in the chain will be executed first
	var ah http.Handler = activatorhandler.New(
		ctx,
		throttler,
		reporter)
	ah = activatorhandler.NewRequestEventHandler(reqCh, ah)
	ah = tracing.HTTPSpanMiddleware(ah)
	ah = configStore.HTTPMiddleware(ah)
	reqLogHandler, err := pkghttp.NewRequestLogHandler(ah, logging.NewSyncFileWriter(os.Stdout), "",
		requestLogTemplateInputGetter(revisioninformer.Get(ctx).Lister()), false /*enableProbeRequestLog*/)
	if err != nil {
		logger.Fatalw("Unable to create request log handler", zap.Error(err))
	}
	ah = reqLogHandler
	ah = &activatorhandler.ProbeHandler{NextHandler: ah}

	// Set up our health check based on the health of stat sink and environmental factors.
	// When drainCh is closed, we should start to drain connections.
	hc, drainCh := newHealthCheck(logger, statSink)
	ah = &activatorhandler.HealthHandler{HealthCheck: hc, NextHandler: ah}

	// NOTE: MetricHandler is being used as the outermost handler for the purpose of measuring the request latency.
	ah = activatorhandler.NewMetricHandler(ctx, reporter, ah)
	ah = network.NewProbeHandler(ah)

	profilingHandler := profiling.NewHandler(logger, false)
	// Watch the logging config map and dynamically update logging levels.
	configMapWatcher.Watch(pkglogging.ConfigMapName(), pkglogging.UpdateLevelFromConfigMap(logger, atomicLevel, component))

	// Watch the observability config map
	configMapWatcher.Watch(metrics.ConfigMapName(),
		metrics.UpdateExporterFromConfigMap(component, logger),
		updateRequestLogFromConfigMap(logger, reqLogHandler),
		profilingHandler.UpdateFromConfigMap)

	if err = configMapWatcher.Start(ctx.Done()); err != nil {
		logger.Fatalw("Failed to start configuration manager", zap.Error(err))
	}

	servers := map[string]*http.Server{
		"http1":   network.NewServer(":"+strconv.Itoa(networking.BackendHTTPPort), ah),
		"h2c":     network.NewServer(":"+strconv.Itoa(networking.BackendHTTP2Port), ah),
		"profile": profiling.NewServer(profilingHandler),
	}

	errCh := make(chan error, len(servers))
	for name, server := range servers {
		go func(name string, s *http.Server) {
			// Don't forward ErrServerClosed as that indicates we're already shutting down.
			if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
				errCh <- fmt.Errorf("%s server failed: %w", name, err)
			}
		}(name, server)
	}

	// Wait for the signal to drain.
	select {
	case <-drainCh:
		logger.Info("Received the drain signal.")
	case err := <-errCh:
		logger.Errorw("Failed to run HTTP server", zap.Error(err))
	}

	// The drain has started (we are now failing readiness probes).  Let the effects of this
	// propagate so that new requests are no longer routed our way.
	time.Sleep(30 * time.Second)
	logger.Info("Done waiting, shutting down servers.")

	// Drain outstanding requests, and stop accepting new ones.
	for _, server := range servers {
		server.Shutdown(context.Background())
	}
	logger.Info("Servers shutdown.")
}

func newHealthCheck(logger *zap.SugaredLogger, statSink *websocket.ManagedConnection) (func() error, <-chan struct{}) {
	// When we get SIGTERM (sigCh closes), start failing readiness probes.
	sigCh := signals.SetupSignalHandler()

	// Some duration after our first readiness probe failure (to allow time
	// for the network to reprogram) send the signal to drain connections.
	drainCh := make(chan struct{})
	once := sync.Once{}

	return func() error {
		select {
		case <-sigCh:
			// Signal to start the process of draining.
			once.Do(func() {
				logger.Info("Received SIGTERM")
				close(drainCh)
			})
			return errors.New("received SIGTERM from kubelet")
		default:
			logger.Debug("No signal yet.")
			return statSink.Status()
		}
	}, drainCh
}

func flush(logger *zap.SugaredLogger) {
	logger.Sync()
	os.Stdout.Sync()
	os.Stderr.Sync()
	metrics.FlushExporter()
}
<commit_msg>fix metric handler chaining (#5788)<commit_after>/*
Copyright 2018 The Knative Authors

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 (
	"context"
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"

	// Injection related imports.
	kubeclient "knative.dev/pkg/client/injection/kube/client"
	"knative.dev/pkg/injection"
	revisioninformer "knative.dev/serving/pkg/client/injection/informers/serving/v1alpha1/revision"

	"github.com/kelseyhightower/envconfig"
	"go.opencensus.io/stats/view"
	"go.uber.org/zap"
	"k8s.io/apimachinery/pkg/util/wait"
	"knative.dev/pkg/configmap"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/injection/sharedmain"
	pkglogging "knative.dev/pkg/logging"
	"knative.dev/pkg/logging/logkey"
	"knative.dev/pkg/metrics"
	pkgnet "knative.dev/pkg/network"
	"knative.dev/pkg/profiling"
	"knative.dev/pkg/signals"
	"knative.dev/pkg/system"
	"knative.dev/pkg/tracing"
	tracingconfig "knative.dev/pkg/tracing/config"
	"knative.dev/pkg/version"
	"knative.dev/pkg/websocket"
	"knative.dev/serving/pkg/activator"
	activatorconfig "knative.dev/serving/pkg/activator/config"
	activatorhandler "knative.dev/serving/pkg/activator/handler"
	activatornet "knative.dev/serving/pkg/activator/net"
	"knative.dev/serving/pkg/apis/networking"
	"knative.dev/serving/pkg/autoscaler"
	"knative.dev/serving/pkg/goversion"
	pkghttp "knative.dev/serving/pkg/http"
	"knative.dev/serving/pkg/logging"
	"knative.dev/serving/pkg/network"
	"knative.dev/serving/pkg/queue"
)

// Fail if using unsupported go version.
var _ = goversion.IsSupported()

const (
	component = "activator"

	// Add enough buffer to not block request serving on stats collection
	requestCountingQueueLength = 100

	// The number of requests that are queued on the breaker before the 503s are sent.
	// The value must be adjusted depending on the actual production requirements.
	breakerQueueDepth = 10000

	// The upper bound for concurrent requests sent to the revision.
	// As new endpoints show up, the Breakers concurrency increases up to this value.
	breakerMaxConcurrency = 1000

	// The port on which autoscaler WebSocket server listens.
	autoscalerPort = ":8080"
)

var (
	masterURL = flag.String("master", "", "The address of the Kubernetes API server. "+
		"Overrides any value in kubeconfig. Only required if out-of-cluster.")
	kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
)

func statReporter(statSink *websocket.ManagedConnection, stopCh <-chan struct{},
	statChan <-chan []autoscaler.StatMessage, logger *zap.SugaredLogger) {
	for {
		select {
		case sm := <-statChan:
			go func() {
				for _, msg := range sm {
					if err := statSink.Send(msg); err != nil {
						logger.Errorw("Error while sending stat", zap.Error(err))
					}
				}
			}()
		case <-stopCh:
			// It's a sending connection, so no drainage required.
			statSink.Shutdown()
			return
		}
	}
}

type config struct {
	PodName string `split_words:"true" required:"true"`
	PodIP   string `split_words:"true" required:"true"`
}

func main() {
	flag.Parse()

	// Set up a context that we can cancel to tell informers and other subprocesses to stop.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Report stats on Go memory usage every 30 seconds.
	msp := metrics.NewMemStatsAll()
	msp.Start(ctx, 30*time.Second)
	if err := view.Register(msp.DefaultViews()...); err != nil {
		log.Fatalf("Error exporting go memstats view: %v", err)
	}

	cfg, err := sharedmain.GetConfig(*masterURL, *kubeconfig)
	if err != nil {
		log.Fatal("Error building kubeconfig:", err)
	}

	log.Printf("Registering %d clients", len(injection.Default.GetClients()))
	log.Printf("Registering %d informer factories", len(injection.Default.GetInformerFactories()))
	log.Printf("Registering %d informers", len(injection.Default.GetInformers()))

	ctx, informers := injection.Default.SetupInformers(ctx, cfg)

	// Set up our logger.
	loggingConfig, err := sharedmain.GetLoggingConfig(ctx)
	if err != nil {
		log.Fatal("Error loading/parsing logging configuration:", err)
	}
	logger, atomicLevel := pkglogging.NewLoggerFromConfig(loggingConfig, component)
	logger = logger.With(zap.String(logkey.ControllerType, component))
	ctx = pkglogging.WithLogger(ctx, logger)
	defer flush(logger)

	kubeClient := kubeclient.Get(ctx)

	// Run informers instead of starting them from the factory to prevent the sync hanging because of empty handler.
	if err := controller.StartInformers(ctx.Done(), informers...); err != nil {
		logger.Fatalw("Failed to start informers", zap.Error(err))
	}

	logger.Info("Starting the knative activator")

	var env config
	if err := envconfig.Process("", &env); err != nil {
		logger.Fatalw("Failed to process env", zap.Error(err))
	}

	// We sometimes startup faster than we can reach kube-api. Poll on failure to prevent us terminating
	if perr := wait.PollImmediate(time.Second, 60*time.Second, func() (bool, error) {
		if err = version.CheckMinimumVersion(kubeClient.Discovery()); err != nil {
			logger.Errorw("Failed to get k8s version", zap.Error(err))
		}
		return err == nil, nil
	}); perr != nil {
		logger.Fatalw("Timed out attempting to get k8s version", zap.Error(err))
	}

	reporter, err := activator.NewStatsReporter()
	if err != nil {
		logger.Fatalw("Failed to create stats reporter", zap.Error(err))
	}

	statCh := make(chan []autoscaler.StatMessage)
	defer close(statCh)

	reqCh := make(chan activatorhandler.ReqEvent, requestCountingQueueLength)
	defer close(reqCh)

	params := queue.BreakerParams{QueueDepth: breakerQueueDepth, MaxConcurrency: breakerMaxConcurrency, InitialCapacity: 0}

	// Start throttler.
	throttler := activatornet.NewThrottler(ctx, params,
		// We want to join host port since that will be our search space in the Throttler.
		net.JoinHostPort(env.PodIP, strconv.Itoa(networking.BackendHTTPPort)))
	go throttler.Run(ctx)

	oct := tracing.NewOpenCensusTracer(tracing.WithExporter(networking.ActivatorServiceName, logger))

	tracerUpdater := configmap.TypeFilter(&tracingconfig.Config{})(func(name string, value interface{}) {
		cfg := value.(*tracingconfig.Config)
		if err := oct.ApplyConfig(cfg); err != nil {
			logger.Errorw("Unable to apply open census tracer config", zap.Error(err))
			return
		}
	})

	// Set up our config store
	configMapWatcher := configmap.NewInformedWatcher(kubeClient, system.Namespace())
	configStore := activatorconfig.NewStore(logger, tracerUpdater)
	configStore.WatchConfigs(configMapWatcher)

	// Open a WebSocket connection to the autoscaler.
	autoscalerEndpoint := fmt.Sprintf("ws://%s.%s.svc.%s%s", "autoscaler", system.Namespace(), pkgnet.GetClusterDomainName(), autoscalerPort)
	logger.Info("Connecting to Autoscaler at ", autoscalerEndpoint)
	statSink := websocket.NewDurableSendingConnection(autoscalerEndpoint, logger)
	go statReporter(statSink, ctx.Done(), statCh, logger)

	// Create and run our concurrency reporter
	reportTicker := time.NewTicker(time.Second)
	defer reportTicker.Stop()
	cr := activatorhandler.NewConcurrencyReporter(ctx, env.PodName, reqCh,
		reportTicker.C, statCh, reporter)
	go cr.Run(ctx.Done())

	// Create activation handler chain
	// Note: innermost handlers are specified first, ie. the last handler in the chain will be executed first
	var ah http.Handler = activatorhandler.New(
		ctx,
		throttler,
		reporter)
	ah = activatorhandler.NewRequestEventHandler(reqCh, ah)
	ah = tracing.HTTPSpanMiddleware(ah)
	ah = configStore.HTTPMiddleware(ah)
	reqLogHandler, err := pkghttp.NewRequestLogHandler(ah, logging.NewSyncFileWriter(os.Stdout), "",
		requestLogTemplateInputGetter(revisioninformer.Get(ctx).Lister()), false /*enableProbeRequestLog*/)
	if err != nil {
		logger.Fatalw("Unable to create request log handler", zap.Error(err))
	}
	ah = reqLogHandler
	ah = &activatorhandler.ProbeHandler{NextHandler: ah}

	// Set up our health check based on the health of stat sink and environmental factors.
	// When drainCh is closed, we should start to drain connections.
	hc, drainCh := newHealthCheck(logger, statSink)
	ah = &activatorhandler.HealthHandler{HealthCheck: hc, NextHandler: ah}

	ah = network.NewProbeHandler(ah)

	// NOTE: MetricHandler is being used as the outermost handler for the purpose of measuring the request latency.
	ah = activatorhandler.NewMetricHandler(ctx, reporter, ah)

	profilingHandler := profiling.NewHandler(logger, false)
	// Watch the logging config map and dynamically update logging levels.
	configMapWatcher.Watch(pkglogging.ConfigMapName(), pkglogging.UpdateLevelFromConfigMap(logger, atomicLevel, component))

	// Watch the observability config map
	configMapWatcher.Watch(metrics.ConfigMapName(),
		metrics.UpdateExporterFromConfigMap(component, logger),
		updateRequestLogFromConfigMap(logger, reqLogHandler),
		profilingHandler.UpdateFromConfigMap)

	if err = configMapWatcher.Start(ctx.Done()); err != nil {
		logger.Fatalw("Failed to start configuration manager", zap.Error(err))
	}

	servers := map[string]*http.Server{
		"http1":   network.NewServer(":"+strconv.Itoa(networking.BackendHTTPPort), ah),
		"h2c":     network.NewServer(":"+strconv.Itoa(networking.BackendHTTP2Port), ah),
		"profile": profiling.NewServer(profilingHandler),
	}

	errCh := make(chan error, len(servers))
	for name, server := range servers {
		go func(name string, s *http.Server) {
			// Don't forward ErrServerClosed as that indicates we're already shutting down.
			if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
				errCh <- fmt.Errorf("%s server failed: %w", name, err)
			}
		}(name, server)
	}

	// Wait for the signal to drain.
	select {
	case <-drainCh:
		logger.Info("Received the drain signal.")
	case err := <-errCh:
		logger.Errorw("Failed to run HTTP server", zap.Error(err))
	}

	// The drain has started (we are now failing readiness probes).  Let the effects of this
	// propagate so that new requests are no longer routed our way.
	time.Sleep(30 * time.Second)
	logger.Info("Done waiting, shutting down servers.")

	// Drain outstanding requests, and stop accepting new ones.
	for _, server := range servers {
		server.Shutdown(context.Background())
	}
	logger.Info("Servers shutdown.")
}

func newHealthCheck(logger *zap.SugaredLogger, statSink *websocket.ManagedConnection) (func() error, <-chan struct{}) {
	// When we get SIGTERM (sigCh closes), start failing readiness probes.
	sigCh := signals.SetupSignalHandler()

	// Some duration after our first readiness probe failure (to allow time
	// for the network to reprogram) send the signal to drain connections.
	drainCh := make(chan struct{})
	once := sync.Once{}

	return func() error {
		select {
		case <-sigCh:
			// Signal to start the process of draining.
			once.Do(func() {
				logger.Info("Received SIGTERM")
				close(drainCh)
			})
			return errors.New("received SIGTERM from kubelet")
		default:
			logger.Debug("No signal yet.")
			return statSink.Status()
		}
	}, drainCh
}

func flush(logger *zap.SugaredLogger) {
	logger.Sync()
	os.Stdout.Sync()
	os.Stderr.Sync()
	metrics.FlushExporter()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	aonui "github.com/rjw57/aonui"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"time"
)

const maximumSimultaneousDownloads = 5
const maximumTries = 4

// Global semaphore used to limit the number of simultaneous downloads
var fetchSem = make(chan int, maximumSimultaneousDownloads)

func main() {
	// Command-line flags
	var (
		baseDir string
	)

	// Parse command line
	flag.StringVar(&baseDir, "basedir", ".", "directory to download data to")
	flag.Parse()

	// Fetch all of the runs
	runs, err := aonui.GFSHalfDegreeDataset.FetchRuns()
	if err != nil {
		log.Fatal(err)
	}

	// Sort by *descending* date
	sort.Sort(sort.Reverse(ByDate(runs)))

	// Check that we have found enough runs
	if len(runs) < 2 {
		log.Print("Not enough runs found.")
		return
	}

	// Choose the penultimate run
	run := runs[1]
	log.Print("Fetching data for run at ", run.When)

	// Get datasets for this run
	datasets, err := run.FetchDatasets()
	if err != nil {
		log.Fatal(err)
	}

	// Open the output file
	filename := filepath.Join(baseDir, run.Identifier+".grib2")
	log.Print("Fetching run to ", filename)
	output, err := os.Create(filename)
	if err != nil {
		log.Print("Error creating output: ", err)
		return
	}

	// Ensure the file is closed on function exit
	defer output.Close()

	// Concatenate temporary files as they are finished
	fetchStart := time.Now()
	for fn := range fetchDatasetsData(baseDir, datasets) {
		if f, err := os.Open(fn); err != nil {
			log.Print("Error copying temporary file: ", err)
		} else {
			io.Copy(output, f)
		}
		os.Remove(fn)
	}

	fetchDuration := time.Since(fetchStart)
	fi, err := output.Stat()
	if err != nil {
		log.Print("Error: ", err)
		return
	}
	log.Print(fmt.Sprintf("Overall download speed: %v/sec",
		ByteCount(float64(fi.Size())/fetchDuration.Seconds())))
}

func fetchDatasetsData(baseDir string, datasets []*aonui.Dataset) chan string {
	// Which records are we interested in?
	paramsOfInterest := []string{"HGT", "UGRD", "VGRD"}

	var wg sync.WaitGroup
	tmpFilesChan := make(chan string)

	trySleepDuration, err := time.ParseDuration("10s")
	if err != nil {
		log.Fatal(err)
	}

	for _, ds := range datasets {
		wg.Add(1)

		go func(dataset *aonui.Dataset) {
			defer wg.Done()

			fetchSem <- 1
			defer func() { <-fetchSem }()

			// Create a temporary file for output
			tmpFile, err := ioutil.TempFile(baseDir, "dataset-")
			if err != nil {
				log.Print("Error creating temporary file: ", err)
			}
			defer tmpFile.Close()

			// Perform download. Attempt download repeatedly
			for tries := 0; tries < maximumTries; tries++ {
				log.Print("Fetching ", dataset.Identifier,
					" (try ", tries+1, " of ", maximumTries, ")")
				err := fetchDataset(tmpFile, dataset, paramsOfInterest)
				if err == nil {
					break
				} else {
					log.Print("Error fetching dataset: ", err)
				}

				// Sleep until the next try
				time.Sleep(trySleepDuration)
			}

			tmpFilesChan <- tmpFile.Name()
		}(ds)
	}

	// Launch a goroutine to wait for all datasets to be downloaded and
	// then close the channel.
	go func() {
		wg.Wait()
		close(tmpFilesChan)
	}()

	return tmpFilesChan
}

func fetchDataset(output io.Writer, dataset *aonui.Dataset, paramsOfInterest []string) error {
	// Fetch inventory for this dataset
	inventory, err := dataset.FetchInventory()
	if err != nil {
		return err
	}

	// Calculate which items to save
	var (
		totalToFetch int64 = 0
		fetchItems   []*aonui.InventoryItem
	)
	for _, item := range inventory {
		saveItem := false
		for _, poi := range paramsOfInterest {
			for _, p := range item.Parameters {
				saveItem = saveItem || poi == p
			}
		}
		if saveItem {
			fetchItems = append(fetchItems, item)
			totalToFetch += item.Extent
		}
	}

	log.Print(fmt.Sprintf("Fetching %d records from %v (%v)",
		len(fetchItems), dataset.Identifier, ByteCount(totalToFetch)))
	if _, err := dataset.FetchAndWriteRecords(output, fetchItems); err != nil {
		return err
	}

	return nil
}
<commit_msg>aonuisync: only fetch isobaric wind layers<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/rjw57/aonui"
)

const maximumSimultaneousDownloads = 5
const maximumTries = 4

// Global semaphore used to limit the number of simultaneous downloads
var fetchSem = make(chan int, maximumSimultaneousDownloads)

type TemporaryFileSource struct {
	BaseDir string
	Prefix  string

	files []*os.File
}

func (tfs *TemporaryFileSource) Create() (*os.File, error) {
	f, err := ioutil.TempFile(tfs.BaseDir, tfs.Prefix)
	if err != nil {
		return nil, err
	}

	tfs.files = append(tfs.files, f)
	return f, nil
}

func (tfs *TemporaryFileSource) Remove(f *os.File) error {
	// Find index of f in files
	for fIdx := 0; fIdx < len(tfs.files); fIdx++ {
		if tfs.files[fIdx] != f {
			continue
		}

		// We found f, remove it from our list
		tfs.files = append(tfs.files[:fIdx], tfs.files[fIdx+1:]...)

		// Remove it from disk
		if err := os.Remove(f.Name()); err != nil {
			return err
		}
	}

	// If we get here, f was not in files
	return errors.New("Temporary file was not managed by me")
}

func (tfs *TemporaryFileSource) RemoveAll() error {
	var lastErr error

	for _, f := range tfs.files {
		if err := os.Remove(f.Name()); err != nil {
			lastErr = err
		}
	}

	return lastErr
}

func main() {
	// Command-line flags
	var (
		baseDir string
	)

	// Parse command line
	flag.StringVar(&baseDir, "basedir", ".", "directory to download data to")
	flag.Parse()

	// Fetch all of the runs
	runs, err := aonui.GFSQuarterDegreeDataset.FetchRuns()
	if err != nil {
		log.Fatal(err)
	}

	// Sort by *descending* date
	sort.Sort(sort.Reverse(ByDate(runs)))

	// Check that we have found enough runs
	if len(runs) < 2 {
		log.Print("Not enough runs found.")
		return
	}

	// Choose the penultimate run
	run := runs[1]
	log.Print("Fetching data for run at ", run.When)

	// Get datasets for this run
	datasets, err := run.FetchDatasets()
	if err != nil {
		log.Fatal(err)
	}

	// File source for temporary files
	tfs := TemporaryFileSource{BaseDir: baseDir, Prefix: "dataset-"}
	defer tfs.RemoveAll()

	// Make sure to remove temporary files on keyboard interrupt
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for s := range c {
			log.Printf("captured %v, deleting temporary files", s)
			tfs.RemoveAll()
			os.Exit(1)
		}
	}()

	// Open the output file
	filename := filepath.Join(baseDir, run.Identifier+".grib2")
	log.Print("Fetching run to ", filename)
	output, err := os.Create(filename)
	if err != nil {
		log.Print("Error creating output: ", err)
		return
	}

	// Ensure the file is closed on function exit
	defer output.Close()

	// Concatenate temporary files as they are finished
	fetchStart := time.Now()
	for f := range fetchDatasetsData(&tfs, datasets) {
		if input, err := os.Open(f.Name()); err != nil {
			log.Print("Error copying temporary file: ", err)
		} else {
			io.Copy(output, input)
			input.Close()
		}
		tfs.Remove(f)
	}

	fetchDuration := time.Since(fetchStart)
	fi, err := output.Stat()
	if err != nil {
		log.Print("Error: ", err)
		return
	}
	log.Print(fmt.Sprintf("Overall download speed: %v/sec",
		ByteCount(float64(fi.Size())/fetchDuration.Seconds())))
}

func fetchDatasetsData(tfs *TemporaryFileSource, datasets []*aonui.Dataset) chan *os.File {
	// Which records are we interested in?
	paramsOfInterest := []string{"HGT", "UGRD", "VGRD"}

	var wg sync.WaitGroup
	tmpFilesChan := make(chan *os.File)

	trySleepDuration, err := time.ParseDuration("10s")
	if err != nil {
		log.Fatal(err)
	}

	for _, ds := range datasets {
		wg.Add(1)

		go func(dataset *aonui.Dataset) {
			defer wg.Done()

			fetchSem <- 1
			defer func() { <-fetchSem }()

			// Create a temporary file for output
			tmpFile, err := tfs.Create()
			if err != nil {
				log.Print("Error creating temporary file: ", err)
			}
			defer tmpFile.Close()

			// Perform download. Attempt download repeatedly
			for tries := 0; tries < maximumTries; tries++ {
				log.Print("Fetching ", dataset.Identifier,
					" (try ", tries+1, " of ", maximumTries, ")")
				err := fetchDataset(tmpFile, dataset, paramsOfInterest)
				if err == nil {
					break
				} else {
					log.Print("Error fetching dataset: ", err)
				}

				// Sleep until the next try
				time.Sleep(trySleepDuration)
			}

			tmpFilesChan <- tmpFile
		}(ds)
	}

	// Launch a goroutine to wait for all datasets to be downloaded and
	// then close the channel.
	go func() {
		wg.Wait()
		close(tmpFilesChan)
	}()

	return tmpFilesChan
}

func fetchDataset(output io.Writer, dataset *aonui.Dataset, paramsOfInterest []string) error {
	// Fetch inventory for this dataset
	inventory, err := dataset.FetchInventory()
	if err != nil {
		return err
	}

	// Calculate which items to save
	var (
		totalToFetch int64 = 0
		fetchItems   []*aonui.InventoryItem
	)
	for _, item := range inventory {
		saveItem := false
		for _, poi := range paramsOfInterest {
			for _, p := range item.Parameters {
				saveItem = saveItem || poi == p
			}
		}

		// HACK: we also are only interested in wind velocities at a
		// particular pressure. (i.e. ones whose "LayerName" field is of
		// the form "XXX mb".)
		saveItem = saveItem && strings.HasSuffix(item.LayerName, " mb")

		if saveItem {
			fetchItems = append(fetchItems, item)
			totalToFetch += item.Extent
		}
	}

	if len(fetchItems) == 0 {
		log.Print("No items to fetch")
		return nil
	}

	log.Print(fmt.Sprintf("Fetching %d records from %v (%v)",
		len(fetchItems), dataset.Identifier, ByteCount(totalToFetch)))
	if _, err := dataset.FetchAndWriteRecords(output, fetchItems); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/apex/log"
)

type LogsCmdLocalValues struct {
	Filter string
	Follow bool

	name string
}

const logsCmdExample = `  Print logs for a function
  $ apex logs <name>`

var logsCmd = &cobra.Command{
	Use:     "logs <name>",
	Short:   "Output logs with optional filter pattern",
	Example: logsCmdExample,
	PreRun:  logsCmdPreRun,
	Run:     logsCmdRun,
}

var logsCmdLocalValues = LogsCmdLocalValues{}

func init() {
	lv := &logsCmdLocalValues
	f := logsCmd.Flags()

	f.StringVarP(&lv.Filter, "filter", "F", "", "Filter logs with pattern")
	f.BoolVarP(&lv.Follow, "follow", "f", false, "Tail logs")
}

func logsCmdPreRun(c *cobra.Command, args []string) {
	lv := &logsCmdLocalValues

	if len(args) < 1 {
		log.Fatal("Missing name argument")
	}
	lv.name = args[0]
}

func logsCmdRun(c *cobra.Command, args []string) {
	lv := &logsCmdLocalValues

	l, err := pv.project.Logs(pv.session, lv.name, lv.Filter)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	if lv.Follow {
		for event := range l.Tail() {
			fmt.Printf("%s", *event.Message)
		}
		if err := l.Err(); err != nil {
			log.Fatalf("error: %s", err)
		}
	} else {
		events, err := l.Fetch()
		if err != nil {
			log.Fatalf("error: %s", err)
		}
		for _, event := range events {
			fmt.Printf("%s", *event.Message)
		}
	}
}
<commit_msg>refactor logsCmdRun slightly<commit_after>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/apex/log"
)

type LogsCmdLocalValues struct {
	Filter string
	Follow bool

	name string
}

const logsCmdExample = `  Print logs for a function
  $ apex logs <name>`

var logsCmd = &cobra.Command{
	Use:     "logs <name>",
	Short:   "Output logs with optional filter pattern",
	Example: logsCmdExample,
	PreRun:  logsCmdPreRun,
	Run:     logsCmdRun,
}

var logsCmdLocalValues = LogsCmdLocalValues{}

func init() {
	lv := &logsCmdLocalValues
	f := logsCmd.Flags()

	f.StringVarP(&lv.Filter, "filter", "F", "", "Filter logs with pattern")
	f.BoolVarP(&lv.Follow, "follow", "f", false, "Tail logs")
}

func logsCmdPreRun(c *cobra.Command, args []string) {
	lv := &logsCmdLocalValues

	if len(args) < 1 {
		log.Fatal("Missing name argument")
	}
	lv.name = args[0]
}

func logsCmdRun(c *cobra.Command, args []string) {
	lv := &logsCmdLocalValues

	l, err := pv.project.Logs(pv.session, lv.name, lv.Filter)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	if lv.Follow {
		for event := range l.Tail() {
			fmt.Printf("%s", *event.Message)
		}

		if err := l.Err(); err != nil {
			log.Fatalf("error: %s", err)
		}
	}

	events, err := l.Fetch()
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	for _, event := range events {
		fmt.Printf("%s", *event.Message)
	}

}
<|endoftext|>


<commit_before>// Package list outputs a list of Lambda function information.
package list

import (
	"fmt"

	"github.com/apex/log"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/tj/cobra"

	"github.com/apex/apex/cmd/apex/root"
	"github.com/apex/apex/colors"
	"github.com/apex/apex/stats"
)

// tfvars output format.
var tfvars bool

// example output.
const example = `
    List all functions
    $ apex list

    List functions based on glob
    $ apex list api_*

    Output list as Terraform variables (.tfvars)
    $ apex list --tfvars`

// Command config.
var Command = &cobra.Command{
	Use:     "list [<name>...]",
	Short:   "Output functions list",
	Example: example,
	RunE:    run,
}

// Initialize.
func init() {
	root.Register(Command)

	f := Command.Flags()
	f.BoolVar(&tfvars, "tfvars", false, "Output as Terraform variables")
}

// Run command.
func run(c *cobra.Command, args []string) error {
	stats.Track("List", map[string]interface{}{
		"tfvars": tfvars,
	})

	if err := root.Project.LoadFunctions(args...); err != nil {
		return err
	}

	if tfvars {
		outputTFvars()
	} else {
		outputList()
	}

	return nil
}

// outputTFvars format.
func outputTFvars() {
	for _, fn := range root.Project.Functions {
		config, err := fn.GetConfig()
		if err != nil {
			log.Debugf("can't fetch function config: %s", err.Error())
			continue
		}

		fmt.Printf("apex_function_%s=%q\n", fn.Name, *config.Configuration.FunctionArn)
	}
}

// outputList format.
func outputList() {
	fmt.Println()
	for _, fn := range root.Project.Functions {
		_, err := fn.GetConfigCurrent()

		if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "ResourceNotFoundException" {
			fmt.Printf("  \033[%dm%s\033[0m (not deployed) \n", colors.Blue, fn.Name)
		} else {
			fmt.Printf("  \033[%dm%s\033[0m\n", colors.Blue, fn.Name)
		}

		if fn.Description != "" {
			fmt.Printf("    description: %v\n", fn.Description)
		}
		fmt.Printf("    runtime: %v\n", fn.Runtime)
		fmt.Printf("    memory: %vmb\n", fn.Memory)
		fmt.Printf("    timeout: %vs\n", fn.Timeout)
		fmt.Printf("    role: %v\n", fn.Role)
		fmt.Printf("    handler: %v\n", fn.Handler)

		if err != nil {
			fmt.Println()
			continue // ignore
		}

		aliaslist, err := fn.GetAliases()
		if err != nil {
			continue
		}

		var aliases string
		for index, alias := range aliaslist.Aliases {
			if index > 0 {
				aliases += ", "
			}
			aliases += fmt.Sprintf("%s@v%s", *alias.Name, *alias.FunctionVersion)
		}
		if aliases == "" {
			aliases = "<none>"
		}
		fmt.Printf("    aliases: %s\n", aliases)
		fmt.Println()
	}
}
<commit_msg>add function arn to list output (#627)<commit_after>// Package list outputs a list of Lambda function information.
package list

import (
	"fmt"

	"github.com/apex/log"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/tj/cobra"

	"github.com/apex/apex/cmd/apex/root"
	"github.com/apex/apex/colors"
	"github.com/apex/apex/stats"
)

// tfvars output format.
var tfvars bool

// example output.
const example = `
    List all functions
    $ apex list

    List functions based on glob
    $ apex list api_*

    Output list as Terraform variables (.tfvars)
    $ apex list --tfvars`

// Command config.
var Command = &cobra.Command{
	Use:     "list [<name>...]",
	Short:   "Output functions list",
	Example: example,
	RunE:    run,
}

// Initialize.
func init() {
	root.Register(Command)

	f := Command.Flags()
	f.BoolVar(&tfvars, "tfvars", false, "Output as Terraform variables")
}

// Run command.
func run(c *cobra.Command, args []string) error {
	stats.Track("List", map[string]interface{}{
		"tfvars": tfvars,
	})

	if err := root.Project.LoadFunctions(args...); err != nil {
		return err
	}

	if tfvars {
		outputTFvars()
	} else {
		outputList()
	}

	return nil
}

// outputTFvars format.
func outputTFvars() {
	for _, fn := range root.Project.Functions {
		config, err := fn.GetConfig()
		if err != nil {
			log.Debugf("can't fetch function config: %s", err.Error())
			continue
		}

		fmt.Printf("apex_function_%s=%q\n", fn.Name, *config.Configuration.FunctionArn)
	}
}

// outputList format.
func outputList() {
	fmt.Println()
	for _, fn := range root.Project.Functions {
		awsFn, err := fn.GetConfigCurrent()

		if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "ResourceNotFoundException" {
			fmt.Printf("  \033[%dm%s\033[0m (not deployed) \n", colors.Blue, fn.Name)
		} else {
			fmt.Printf("  \033[%dm%s\033[0m\n", colors.Blue, fn.Name)
		}

		if fn.Description != "" {
			fmt.Printf("    description: %v\n", fn.Description)
		}
		fmt.Printf("    runtime: %v\n", fn.Runtime)
		fmt.Printf("    memory: %vmb\n", fn.Memory)
		fmt.Printf("    timeout: %vs\n", fn.Timeout)
		fmt.Printf("    role: %v\n", fn.Role)
		fmt.Printf("    handler: %v\n", fn.Handler)
		if awsFn != nil && awsFn.Configuration != nil && awsFn.Configuration.FunctionArn != nil {
			fmt.Printf("    arn: %v\n", *awsFn.Configuration.FunctionArn)
		}

		if err != nil {
			fmt.Println()
			continue // ignore
		}

		aliaslist, err := fn.GetAliases()
		if err != nil {
			continue
		}

		var aliases string
		for index, alias := range aliaslist.Aliases {
			if index > 0 {
				aliases += ", "
			}
			aliases += fmt.Sprintf("%s@v%s", *alias.Name, *alias.FunctionVersion)
		}
		if aliases == "" {
			aliases = "<none>"
		}
		fmt.Printf("    aliases: %s\n", aliases)
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// TODO(telyn): does the URL really have to start with /?

// Debug makes an HTTP <method> request to the URL specified in the arguments.
// command syntax: debug <method> <url>
// URL probably needs to start with a /
func (dispatch *Dispatcher) Debug(args []string) {
	dispatch.BigV.DebugLevel = 1

	// make sure the command is well-formed

	body, err := dispatch.BigV.Request(args[0], args[1], "")
	if err != nil {
		panic(err)
	}

	buf := new(bytes.Buffer)
	json.Indent(buf, body, "", "    ")
	fmt.Printf("%s", buf)
}
<commit_msg>Fix bug from ddadb05<commit_after>package cmd

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// TODO(telyn): does the URL really have to start with /?

// Debug makes an HTTP <method> request to the URL specified in the arguments.
// command syntax: debug <method> <url>
// URL probably needs to start with a /
func (dispatch *Dispatcher) Debug(args []string) {
	dispatch.BigV.DebugLevel = 1

	// make sure the command is well-formed

	body, err := dispatch.BigV.RequestAndRead(args[0], args[1], "")
	if err != nil {
		panic(err)
	}

	buf := new(bytes.Buffer)
	json.Indent(buf, body, "", "    ")
	fmt.Printf("%s", buf)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	for {
		c := db.Connect(os.Getenv("REDISTOGO_URL"))

		targets0 := []string{"新竹市"}
		msgs0, token0 := rain.GetRainingInfo(targets0, false)

		status0, getErr := redis.Int(c.Do("SISMEMBER", "token0", token0))
		if getErr != nil {
			if err != nil {
				log.Println(err)
			}
		}

		if status0 == 0 {
			users0, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

			if smembersErr != nil {
				log.Println("SMEMBERS redis error", smembersErr)
			} else {
				local := time.Now()
				location, timeZoneErr := time.LoadLocation(timeZone)
				if timeZoneErr == nil {
					local = local.In(location)
				}
				for _, contentTo := range users0 {
					for _, msg := range msgs0 {
						_, err = bot.SendText([]string{contentTo}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}
			}
		}

		n0, addErr := c.Do("SADD", "token0", token0)
		if addErr != nil {
			log.Println("SADD to redis error", addErr, n0)
		}

		targets1 := []string{"新竹市", "新竹縣"}
		msgs1, token1 := rain.GetWarningInfo(targets1)

		status1, getErr := redis.Int(c.Do("SISMEMBER", "token1", token1))
		if getErr != nil {
			if err != nil {
				log.Println(err)
			}
		}

		if status1 == 0 {
			users1, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

			if smembersErr != nil {
				log.Println("SMEMBERS redis error", smembersErr)
			} else {
				local := time.Now()
				location, err := time.LoadLocation(timeZone)
				if err == nil {
					local = local.In(location)
				}
				for _, contentTo := range users1 {
					for _, msg := range msgs1 {
						_, err = bot.SendText([]string{contentTo}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}
			}
		}

		n, addErr := c.Do("SADD", "token1", token1)
		if addErr != nil {
			log.Println("SADD to redis error", addErr, n)
		}

		defer c.Close()

		time.Sleep(30 * time.Second)
	}
}
<commit_msg>updated logs<commit_after>package main

import (
	"log"
	"os"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/lancetw/hcfd-forecast/db"
	"github.com/lancetw/hcfd-forecast/rain"
	"github.com/line/line-bot-sdk-go/linebot"
)

const timeZone = "Asia/Taipei"

var bot *linebot.Client

func main() {
	log.Println("=== 查詢。開始 ===")

	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	if err != nil {
		log.Println("Bot:", bot, " err:", err)
	}

	for {
		c := db.Connect(os.Getenv("REDISTOGO_URL"))

		targets0 := []string{"新竹市"}
		msgs0, token0 := rain.GetRainingInfo(targets0, false)

		status0, getErr := redis.Int(c.Do("SISMEMBER", "token0", token0))
		if getErr != nil {
			if err != nil {
				log.Println(err)
			}
		}

		if status0 == 0 {
			users0, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

			if smembersErr != nil {
				log.Println("SMEMBERS redis error", smembersErr)
			} else {
				local := time.Now()
				location, timeZoneErr := time.LoadLocation(timeZone)
				if timeZoneErr == nil {
					local = local.In(location)
				}
				for _, contentTo := range users0 {
					for _, msg := range msgs0 {
						_, err = bot.SendText([]string{contentTo}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}
			}
		}

		n0, addErr := c.Do("SADD", "token0", token0)
		if addErr != nil {
			log.Println("SADD to redis error", addErr, n0)
		}

		targets1 := []string{"新竹市", "新竹縣"}
		msgs1, token1 := rain.GetWarningInfo(targets1)

		status1, getErr := redis.Int(c.Do("SISMEMBER", "token1", token1))
		if getErr != nil {
			if err != nil {
				log.Println(err)
			}
		}

		if status1 == 0 {
			users1, smembersErr := redis.Strings(c.Do("SMEMBERS", "user"))

			if smembersErr != nil {
				log.Println("SMEMBERS redis error", smembersErr)
			} else {
				local := time.Now()
				location, err := time.LoadLocation(timeZone)
				if err == nil {
					local = local.In(location)
				}
				for _, contentTo := range users1 {
					for _, msg := range msgs1 {
						_, err = bot.SendText([]string{contentTo}, msg)
						if err != nil {
							log.Println(err)
						}
					}
				}
			}
		}

		n, addErr := c.Do("SADD", "token1", token1)
		if addErr != nil {
			log.Println("SADD to redis error", addErr, n)
		}

		defer c.Close()

		log.Println("=== 查詢。結束 ===")

		time.Sleep(30 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"image"
	"image/draw"
	"image/gif"
	_ "image/png"
	"io"
	"net/http"
	"os"
	"strings"

	_ "golang.org/x/image/bmp"

	"github.com/codegangsta/cli"
	"github.com/disintegration/imaging"
	"github.com/kevin-cantwell/dotmatrix"
	"github.com/nfnt/resize"
	"golang.org/x/crypto/ssh/terminal"
)

func main() {
	app := cli.NewApp()
	app.Version = "0.1.0"
	app.Name = "dotmatrix"
	app.Usage = "A command-line tool for encoding images as unicode braille symbols."
	app.UsageText = "1) dotmatrix [options] [file|url]\n" +
		/*      */ "   2) dotmatrix [options] < [file]"
	app.Author = "Kevin Cantwell"
	app.Email = "kevin.cantwell@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "invert,i",
			Usage: "Inverts image color. Useful for black background terminals",
		},
		cli.Float64Flag{
			Name:  "gamma,g",
			Usage: "GAMMA less than 0 darkens the image and GAMMA greater than 0 lightens it.",
		},
		cli.Float64Flag{
			Name:  "brightness,b",
			Usage: "BRIGHTNESS = -100 gives solid black image. BRIGHTNESS = 100 gives solid white image.",
			Value: 0.0,
		},
		cli.Float64Flag{
			Name:  "contrast,c",
			Usage: "CONTRAST = -100 gives solid grey image. CONTRAST = 100 gives maximum contrast.",
			Value: 0.0,
		},
		cli.Float64Flag{
			Name:  "sharpen,s",
			Usage: "SHARPEN greater than 0 sharpens the image.",
			Value: 0.0,
		},
		cli.BoolFlag{
			Name:  "mirror,m",
			Usage: "Mirrors the image.",
		},
		cli.BoolFlag{
			Name:  "mono",
			Usage: "Images are drawn without Floyd Steinberg diffusion.",
		},
		cli.BoolFlag{
			Name:  "motion,mjpeg",
			Usage: "Interpret input as an mjpeg stream, such as from a webcam.",
		},
		cli.IntFlag{
			Name:  "framerate,fps",
			Usage: "Force a framerate for mjpeg streams. Default is -1 (ie: no delay between frames).",
			Value: -1,
		},
	}
	app.Action = func(c *cli.Context) error {
		reader, mimeType, err := decodeReader(c)
		if err != nil {
			return err
		}

		if c.Bool("motion") {
			return mjpegAction(c, reader, c.Int("framerate"))
		}

		switch mimeType {
		case "video/x-motion-jpeg":
			return mjpegAction(c, reader, c.Int("framerate"))
		case "image/gif":
			return gifAction(c, reader)
		default:
			return imageAction(c, reader)
		}
	}

	if err := app.Run(os.Args); err != nil {
		exit(err.Error(), 1)
	}
}

func config(c *cli.Context) *dotmatrix.Config {
	return &dotmatrix.Config{
		Filter: &Filter{
			Gamma:      c.Float64("gamma"),
			Brightness: c.Float64("brightness"),
			Contrast:   c.Float64("contrast"),
			Sharpen:    c.Float64("sharpen"),
			Invert:     c.Bool("invert"),
			Mirror:     c.Bool("mirror"),
		},
		Drawer: func() draw.Drawer {
			if c.Bool("mono") {
				return draw.Src
			}
			return draw.FloydSteinberg
		}(),
	}
}

func imageAction(c *cli.Context, r io.Reader) error {
	img, _, err := image.Decode(r)
	if err != nil {
		return err
	}
	return dotmatrix.NewPrinter(os.Stdout, config(c)).Print(img)
}

func gifAction(c *cli.Context, r io.Reader) error {
	giff, err := gif.DecodeAll(r)
	if err != nil {
		return err
	}
	return dotmatrix.NewGIFPrinter(os.Stdout, config(c)).Print(giff)
}

func mjpegAction(c *cli.Context, r io.Reader, fps int) error {
	return dotmatrix.NewMJPEGPrinter(os.Stdout, config(c)).Print(r, fps)
}

func decodeReader(c *cli.Context) (io.Reader, string, error) {
	var reader io.Reader = os.Stdin

	// Assign to reader
	if input := c.Args().First(); input != "" {
		// Is it a file?
		if !strings.HasPrefix(input, "http://") && !strings.HasPrefix(input, "https://") {
			file, err := os.Open(input)
			if err != nil {
				return nil, "", err
			}
			reader = file
		} else {
			// Is it a url?
			if resp, err := http.Get(input); err != nil {
				return nil, "", err
			} else {
				reader = resp.Body
			}
		}
	}

	bufioReader := bufio.NewReader(reader)

	peeked, err := bufioReader.Peek(512)
	if err != nil {
		return nil, "", err
	}

	mimeType := http.DetectContentType(peeked)

	return bufioReader, mimeType, nil
}

type Filter struct {
	// Gamma less than 0 darkens the image and GAMMA greater than 0 lightens it.
	Gamma float64
	// Brightness = -100 gives solid black image. Brightness = 100 gives solid white image.
	Brightness float64
	// Contrast = -100 gives solid grey image. Contrast = 100 gives maximum contrast.
	Contrast float64
	// Sharpen greater than 0 sharpens the image.
	Sharpen float64
	// Inverts pixel color. Transparent pixels remain transparent.
	Invert bool
	// Mirror flips the image on it's vertical axis
	Mirror bool

	scale float64
}

func (f *Filter) Filter(img image.Image) image.Image {
	if f.Gamma != 0 {
		img = imaging.AdjustGamma(img, f.Gamma+1.0)
	}
	if f.Brightness != 0 {
		img = imaging.AdjustBrightness(img, f.Brightness)
	}
	if f.Sharpen != 0 {
		img = imaging.Sharpen(img, f.Sharpen)
	}
	if f.Contrast != 0 {
		img = imaging.AdjustContrast(img, f.Contrast)
	}
	if f.Mirror {
		img = imaging.FlipH(img)
	}
	if f.Invert {
		img = imaging.Invert(img)
	}

	// Only calculate the scalar values once because gifs
	if f.scale == 0 {
		cols, rows := terminalDimensions()
		dx, dy := img.Bounds().Dx(), img.Bounds().Dy()
		scale := scalar(dx, dy, cols, rows)
		if scale >= 1.0 {
			scale = 1.0
		}
		f.scale = scale
	}

	width := uint(f.scale * float64(img.Bounds().Dx()))
	height := uint(f.scale * float64(img.Bounds().Dy()))
	return resize.Resize(width, height, img, resize.NearestNeighbor)
}

func terminalDimensions() (int, int) {
	var cols, rows int

	if terminal.IsTerminal(int(os.Stdout.Fd())) {
		tw, th, err := terminal.GetSize(int(os.Stdout.Fd()))
		if err == nil {
			th -= 1 // Accounts for the terminal prompt
			if cols == 0 {
				cols = tw
			}
			if rows == 0 {
				rows = th
			}
		}
	}

	// Small, but fairly standard defaults
	if cols == 0 {
		cols = 80
	}
	if rows == 0 {
		rows = 25
	}

	return cols, rows
}

func scalar(dx, dy int, cols, rows int) float64 {
	scale := float64(1.0)
	scaleX := float64(cols*2) / float64(dx)
	scaleY := float64(rows*4) / float64(dy)

	if scaleX < scale {
		scale = scaleX
	}
	if scaleY < scale {
		scale = scaleY
	}

	return scale
}

func exit(msg string, code int) {
	fmt.Println(msg)
	os.Exit(code)
}
<commit_msg>adds mime flag for forcing mime type<commit_after>package main

import (
	"bufio"
	"fmt"
	"image"
	"image/draw"
	"image/gif"
	_ "image/png"
	"io"
	"net/http"
	"os"
	"strings"

	_ "golang.org/x/image/bmp"

	"github.com/codegangsta/cli"
	"github.com/disintegration/imaging"
	"github.com/kevin-cantwell/dotmatrix"
	"github.com/nfnt/resize"
	"golang.org/x/crypto/ssh/terminal"
)

func main() {
	app := cli.NewApp()
	app.Version = "0.1.0"
	app.Name = "dotmatrix"
	app.Usage = "A command-line tool for encoding images as unicode braille symbols."
	app.UsageText = "1) dotmatrix [options] [file|url]\n" +
		/*      */ "   2) dotmatrix [options] < [file]"
	app.Author = "Kevin Cantwell"
	app.Email = "kevin.cantwell@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "invert,i",
			Usage: "Inverts image color. Useful for black background terminals",
		},
		cli.Float64Flag{
			Name:  "gamma,g",
			Usage: "GAMMA less than 0 darkens the image and GAMMA greater than 0 lightens it.",
		},
		cli.Float64Flag{
			Name:  "brightness,b",
			Usage: "BRIGHTNESS = -100 gives solid black image. BRIGHTNESS = 100 gives solid white image.",
			Value: 0.0,
		},
		cli.Float64Flag{
			Name:  "contrast,c",
			Usage: "CONTRAST = -100 gives solid grey image. CONTRAST = 100 gives maximum contrast.",
			Value: 0.0,
		},
		cli.Float64Flag{
			Name:  "sharpen,s",
			Usage: "SHARPEN greater than 0 sharpens the image.",
			Value: 0.0,
		},
		cli.BoolFlag{
			Name:  "mirror,m",
			Usage: "Mirrors the image.",
		},
		cli.BoolFlag{
			Name:  "mono",
			Usage: "Images are drawn without Floyd Steinberg diffusion.",
		},
		cli.BoolFlag{
			Name:  "motion,mjpeg",
			Usage: "Interpret input as an mjpeg stream, such as from a webcam.",
		},
		cli.IntFlag{
			Name:  "framerate,fps",
			Usage: "Force a framerate for mjpeg streams. Default is -1 (ie: no delay between frames).",
			Value: -1,
		},
		cli.StringFlag{
			Name:  "mimeType,mime",
			Usage: "Force interpretation of a specific mime type (eg: \"image/gif\". Default is to examine the first 512 bytes and make an educated guess.",
		},
	}
	app.Action = func(c *cli.Context) error {
		reader, mimeType, err := decodeReader(c)
		if err != nil {
			return err
		}

		if mime := c.String("mimeType"); mime != "" {
			mimeType = mime
		}

		if c.Bool("motion") {
			return mjpegAction(c, reader, c.Int("framerate"))
		}

		switch mimeType {
		case "video/x-motion-jpeg":
			return mjpegAction(c, reader, c.Int("framerate"))
		case "image/gif":
			return gifAction(c, reader)
		default:
			return imageAction(c, reader)
		}
	}

	if err := app.Run(os.Args); err != nil {
		exit(err.Error(), 1)
	}
}

func config(c *cli.Context) *dotmatrix.Config {
	return &dotmatrix.Config{
		Filter: &Filter{
			Gamma:      c.Float64("gamma"),
			Brightness: c.Float64("brightness"),
			Contrast:   c.Float64("contrast"),
			Sharpen:    c.Float64("sharpen"),
			Invert:     c.Bool("invert"),
			Mirror:     c.Bool("mirror"),
		},
		Drawer: func() draw.Drawer {
			if c.Bool("mono") {
				return draw.Src
			}
			return draw.FloydSteinberg
		}(),
	}
}

func imageAction(c *cli.Context, r io.Reader) error {
	img, _, err := image.Decode(r)
	if err != nil {
		return err
	}
	return dotmatrix.NewPrinter(os.Stdout, config(c)).Print(img)
}

func gifAction(c *cli.Context, r io.Reader) error {
	giff, err := gif.DecodeAll(r)
	if err != nil {
		return err
	}
	return dotmatrix.NewGIFPrinter(os.Stdout, config(c)).Print(giff)
}

func mjpegAction(c *cli.Context, r io.Reader, fps int) error {
	return dotmatrix.NewMJPEGPrinter(os.Stdout, config(c)).Print(r, fps)
}

func decodeReader(c *cli.Context) (io.Reader, string, error) {
	var reader io.Reader = os.Stdin

	// Assign to reader
	if input := c.Args().First(); input != "" {
		// Is it a file?
		if !strings.HasPrefix(input, "http://") && !strings.HasPrefix(input, "https://") {
			file, err := os.Open(input)
			if err != nil {
				return nil, "", err
			}
			reader = file
		} else {
			// Is it a url?
			if resp, err := http.Get(input); err != nil {
				return nil, "", err
			} else {
				reader = resp.Body
			}
		}
	}

	bufioReader := bufio.NewReader(reader)

	peeked, err := bufioReader.Peek(512)
	if err != nil {
		return nil, "", err
	}

	mimeType := http.DetectContentType(peeked)

	return bufioReader, mimeType, nil
}

type Filter struct {
	// Gamma less than 0 darkens the image and GAMMA greater than 0 lightens it.
	Gamma float64
	// Brightness = -100 gives solid black image. Brightness = 100 gives solid white image.
	Brightness float64
	// Contrast = -100 gives solid grey image. Contrast = 100 gives maximum contrast.
	Contrast float64
	// Sharpen greater than 0 sharpens the image.
	Sharpen float64
	// Inverts pixel color. Transparent pixels remain transparent.
	Invert bool
	// Mirror flips the image on it's vertical axis
	Mirror bool

	scale float64
}

func (f *Filter) Filter(img image.Image) image.Image {
	if f.Gamma != 0 {
		img = imaging.AdjustGamma(img, f.Gamma+1.0)
	}
	if f.Brightness != 0 {
		img = imaging.AdjustBrightness(img, f.Brightness)
	}
	if f.Sharpen != 0 {
		img = imaging.Sharpen(img, f.Sharpen)
	}
	if f.Contrast != 0 {
		img = imaging.AdjustContrast(img, f.Contrast)
	}
	if f.Mirror {
		img = imaging.FlipH(img)
	}
	if f.Invert {
		img = imaging.Invert(img)
	}

	// Only calculate the scalar values once because gifs
	if f.scale == 0 {
		cols, rows := terminalDimensions()
		dx, dy := img.Bounds().Dx(), img.Bounds().Dy()
		scale := scalar(dx, dy, cols, rows)
		if scale >= 1.0 {
			scale = 1.0
		}
		f.scale = scale
	}

	width := uint(f.scale * float64(img.Bounds().Dx()))
	height := uint(f.scale * float64(img.Bounds().Dy()))
	return resize.Resize(width, height, img, resize.NearestNeighbor)
}

func terminalDimensions() (int, int) {
	var cols, rows int

	if terminal.IsTerminal(int(os.Stdout.Fd())) {
		tw, th, err := terminal.GetSize(int(os.Stdout.Fd()))
		if err == nil {
			th -= 1 // Accounts for the terminal prompt
			if cols == 0 {
				cols = tw
			}
			if rows == 0 {
				rows = th
			}
		}
	}

	// Small, but fairly standard defaults
	if cols == 0 {
		cols = 80
	}
	if rows == 0 {
		rows = 25
	}

	return cols, rows
}

func scalar(dx, dy int, cols, rows int) float64 {
	scale := float64(1.0)
	scaleX := float64(cols*2) / float64(dx)
	scaleY := float64(rows*4) / float64(dy)

	if scaleX < scale {
		scale = scaleX
	}
	if scaleY < scale {
		scale = scaleY
	}

	return scale
}

func exit(msg string, code int) {
	fmt.Println(msg)
	os.Exit(code)
}
<|endoftext|>


<commit_before>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// See csv_test.go for more information about each test.
package csvutil

import (
    "testing"
)

// TEST1 - Simple 3x3 matrix w/ comma separators and w/o excess whitespace.
func TestWriteRow(T *testing.T) {
    var csvw, buff = BufferWriter(nil)
    var csvMatrix = TestMatrix1
    var n int = len(csvMatrix)
    var length = 0
    for i := 0; i < n; i++ {
        nbytes, err := csvw.WriteRow(csvMatrix[i]...)
        if err != nil {
            T.Errorf("Write error: %s\n", err.Error())
        }
        errFlush := csvw.Flush()
        if errFlush != nil {
            T.Logf("Wrote %d bytes on row %d\n", nbytes, i)
        }
        length += nbytes
    }
    flushErr := csvw.Flush()
    if flushErr != nil {
        T.Errorf("Error flushing output; %v\n", flushErr)
    }
    var output string = buff.String()
    if len(output) == 0 {
        T.Error("Read 0 bytes\n")
    } else {
        T.Logf("Read %d bytes from the buffer.", len(output))
    }
    var csvStr string = csvTestString1()
    if output != csvStr {
        T.Errorf("Unexpected output.\n\nExpected:\n'%s'\nReceived:\n'%s'\n\n",
            csvStr, output)
    }
}
// END TEST1

func TestWriterComments(T *testing.T) {
    var config = NewConfig()
    config.Sep = '\t'
    var (
        matrix       = TestMatrix2
        comments     = TestMatrix2Comments
        verification = csvTestString2()
        writer, buff = BufferWriter(config)
    )
    writer.WriteComments(comments...)
    writer.WriteRows(matrix)
    writer.Flush()
    var output = buff.String()
    if output != verification {
        T.Errorf("Error writing comments\n\n'%s'\n'%s'", verification, output)
    }
}
<commit_msg>gofmt<commit_after>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// See csv_test.go for more information about each test.
package csvutil

import (
	"testing"
)

// TEST1 - Simple 3x3 matrix w/ comma separators and w/o excess whitespace.
func TestWriteRow(T *testing.T) {
	var csvw, buff = BufferWriter(nil)
	var csvMatrix = TestMatrix1
	var n int = len(csvMatrix)
	var length = 0
	for i := 0; i < n; i++ {
		nbytes, err := csvw.WriteRow(csvMatrix[i]...)
		if err != nil {
			T.Errorf("Write error: %s\n", err.Error())
		}
		errFlush := csvw.Flush()
		if errFlush != nil {
			T.Logf("Wrote %d bytes on row %d\n", nbytes, i)
		}
		length += nbytes
	}
	flushErr := csvw.Flush()
	if flushErr != nil {
		T.Errorf("Error flushing output; %v\n", flushErr)
	}
	var output string = buff.String()
	if len(output) == 0 {
		T.Error("Read 0 bytes\n")
	} else {
		T.Logf("Read %d bytes from the buffer.", len(output))
	}
	var csvStr string = csvTestString1()
	if output != csvStr {
		T.Errorf("Unexpected output.\n\nExpected:\n'%s'\nReceived:\n'%s'\n\n",
			csvStr, output)
	}
}

// END TEST1

func TestWriterComments(T *testing.T) {
	var config = NewConfig()
	config.Sep = '\t'
	var (
		matrix       = TestMatrix2
		comments     = TestMatrix2Comments
		verification = csvTestString2()
		writer, buff = BufferWriter(config)
	)
	writer.WriteComments(comments...)
	writer.WriteRows(matrix)
	writer.Flush()
	var output = buff.String()
	if output != verification {
		T.Errorf("Error writing comments\n\n'%s'\n'%s'", verification, output)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"net"
	"net/http"
	"os/signal"
	"syscall"

	"fmt"
	"os"

	"github.com/datawire/teleproxy/pkg/supervisor"
	"github.com/pkg/errors"
)

func retrieveRequest(w http.ResponseWriter, r *http.Request) *PPRequest {
	if r.Method == http.MethodPost {
		d := json.NewDecoder(r.Body)
		req := PPRequest{}
		err := d.Decode(&req)
		if err != nil {
			http.Error(w, err.Error(), 400)
		}
		return &req
	}
	http.Error(w, "Bad request", 400)
	return nil
}

func makeRequestHandler(p *supervisor.Process, handle func(*supervisor.Process, *PPRequest) string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		req := retrieveRequest(w, r)
		w.Write([]byte(handle(p, req)))
	}
}
func daemon(p *supervisor.Process) error {
	var err error

	mux := &SerializingMux{}
	mux.HandleSerially("/status", "pp", makeRequestHandler(p, daemonStatus))
	mux.HandleSerially("/connect", "pp", makeRequestHandler(p, daemonConnect))
	mux.HandleSerially("/disconnect", "pp", makeRequestHandler(p, daemonDisconnect))
	mux.HandleSerially("/version", "pp", makeRequestHandler(p, daemonVersion))
	mux.HandleSerially("/quit", "pp", makeRequestHandler(p, daemonQuit))

	unixListener, err := net.Listen("unix", socketName)
	if err != nil {
		return errors.Wrap(err, "listen")
	}

	server := &http.Server{
		Handler: mux,
	}

	serverErr := make(chan error)
	go func() {
		serverErr <- server.Serve(unixListener)
	}()

	p.Ready()

	select {
	case err = <-serverErr: // Server failed
		err = errors.Wrap(err, "server failed")
		p.Supervisor().Shutdown()
	case <-p.Shutdown(): // Supervisor told us to quit
		err = errors.Wrap(server.Shutdown(p.Context()), "shutting down server")
	}
	return err
}

func waitForSignal(p *supervisor.Process) error {
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
	p.Ready()

	select {
	case killSignal := <-interrupt:
		switch killSignal {
		case os.Interrupt:
			p.Log("Got SIGINT...")
		case syscall.SIGTERM:
			p.Log("Got SIGTERM...")
		}
		p.Supervisor().Shutdown()
	case <-p.Shutdown():
	}
	return nil
}

func runAsDaemon() {
	if os.Geteuid() != 0 {
		fmt.Println("Playpen Daemon must run as root.")
		//os.Exit(1)
	}

	sup := supervisor.WithContext(context.Background())
	//sup.Logger = ...
	sup.Supervise(&supervisor.Worker{
		Name: "daemon",
		Work: daemon,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "signal",
		Requires: []string{"daemon"},
		Work:     waitForSignal,
	})

	errors := sup.Run()
	sup.Logger.Printf("Daemon has exited")
	for _, err := range errors {
		sup.Logger.Printf("- %v", err)
	}
	sup.Logger.Printf("Daemon is done.")
	os.Exit(1)
}

func daemonStatus(p *supervisor.Process, req *PPRequest) string {
	return "Not connected"
}

func daemonConnect(p *supervisor.Process, req *PPRequest) string {
	return "Not implemented..."
}

func daemonDisconnect(p *supervisor.Process, req *PPRequest) string {
	return "Not connected"
}

func daemonVersion(p *supervisor.Process, req *PPRequest) string {
	return fmt.Sprintf("playpen daemon v%s (api v%d)\n", Version, apiVersion)
}

func daemonQuit(p *supervisor.Process, req *PPRequest) string {
	me, err := os.FindProcess(os.Getpid())
	if err != nil {
		message := fmt.Sprintf("Error trying to quit: %v", err)
		p.Log(message)
		return message
	}
	me.Signal(syscall.SIGTERM)
	return "Playpen Daemon quitting..."
}
<commit_msg>Have Supervisor manage the http server goroutine<commit_after>package main

import (
	"context"
	"encoding/json"
	"net"
	"net/http"
	"os/signal"
	"syscall"

	"fmt"
	"os"

	"github.com/datawire/teleproxy/pkg/supervisor"
	"github.com/pkg/errors"
)

func retrieveRequest(w http.ResponseWriter, r *http.Request) *PPRequest {
	if r.Method == http.MethodPost {
		d := json.NewDecoder(r.Body)
		req := PPRequest{}
		err := d.Decode(&req)
		if err != nil {
			http.Error(w, err.Error(), 400)
		}
		return &req
	}
	http.Error(w, "Bad request", 400)
	return nil
}

func makeRequestHandler(p *supervisor.Process, handle func(*supervisor.Process, *PPRequest) string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		req := retrieveRequest(w, r)
		w.Write([]byte(handle(p, req)))
	}
}
func daemon(p *supervisor.Process) error {
	var err error

	mux := &SerializingMux{}
	mux.HandleSerially("/status", "pp", makeRequestHandler(p, daemonStatus))
	mux.HandleSerially("/connect", "pp", makeRequestHandler(p, daemonConnect))
	mux.HandleSerially("/disconnect", "pp", makeRequestHandler(p, daemonDisconnect))
	mux.HandleSerially("/version", "pp", makeRequestHandler(p, daemonVersion))
	mux.HandleSerially("/quit", "pp", makeRequestHandler(p, daemonQuit))

	unixListener, err := net.Listen("unix", socketName)
	if err != nil {
		return errors.Wrap(err, "listen")
	}
	server := &http.Server{
		Handler: mux,
	}
	p.Go(func(p *supervisor.Process) error {
		return server.Serve(unixListener)
	})
	p.Ready()

	// Wait for Supervisor to tell us to quit
	<-p.Shutdown()
	return server.Shutdown(p.Context())
}

func waitForSignal(p *supervisor.Process) error {
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
	p.Ready()

	select {
	case killSignal := <-interrupt:
		switch killSignal {
		case os.Interrupt:
			p.Log("Got SIGINT...")
		case syscall.SIGTERM:
			p.Log("Got SIGTERM...")
		}
		p.Supervisor().Shutdown()
	case <-p.Shutdown():
	}
	return nil
}

func runAsDaemon() {
	if os.Geteuid() != 0 {
		fmt.Println("Playpen Daemon must run as root.")
		//os.Exit(1)
	}

	sup := supervisor.WithContext(context.Background())
	//sup.Logger = ...
	sup.Supervise(&supervisor.Worker{
		Name: "daemon",
		Work: daemon,
	})
	sup.Supervise(&supervisor.Worker{
		Name:     "signal",
		Requires: []string{"daemon"},
		Work:     waitForSignal,
	})

	errors := sup.Run()
	sup.Logger.Printf("Daemon has exited")
	for _, err := range errors {
		sup.Logger.Printf("- %v", err)
	}
	sup.Logger.Printf("Daemon is done.")
	os.Exit(1)
}

func daemonStatus(p *supervisor.Process, req *PPRequest) string {
	return "Not connected"
}

func daemonConnect(p *supervisor.Process, req *PPRequest) string {
	return "Not implemented..."
}

func daemonDisconnect(p *supervisor.Process, req *PPRequest) string {
	return "Not connected"
}

func daemonVersion(p *supervisor.Process, req *PPRequest) string {
	return fmt.Sprintf("playpen daemon v%s (api v%d)\n", Version, apiVersion)
}

func daemonQuit(p *supervisor.Process, req *PPRequest) string {
	me, err := os.FindProcess(os.Getpid())
	if err != nil {
		message := fmt.Sprintf("Error trying to quit: %v", err)
		p.Log(message)
		return message
	}
	me.Signal(syscall.SIGTERM)
	return "Playpen Daemon quitting..."
}
<|endoftext|>


<commit_before>package collectors

import (
	"github.com/slarti5191/splendid/configuration"
	"github.com/slarti5191/splendid/utils"
	"regexp"
)

type devPfsense struct {
	configuration.DeviceConfig
}

// Collect gathers config.xml from pfSense
func (d devPfsense) Collect() string {
	var cmd []string
	// Regex matching our config block
	var pf = regexp.MustCompile(`<pfsense>[\s\S]*?<\/pfsense>`)
	// Commands we need to run
	// commands are different for "admin" user
	switch d.User {
	case "admin":
		cmd = append(cmd, "8", "cat /conf/config.xml", "exit", "0")
	default:
		cmd = append(cmd, "cat /conf/config.xml", "exit")
	}
	// Set up SSH
	s := new(utils.SSHRunner)
	// Connect
	s.Connect(d.User, d.Pass, d.Host)
	// Return our config
	return s.Gather(cmd, pf)
}

func makePfsense(d configuration.DeviceConfig) Collector {
	return &devPfsense{d}
}
<commit_msg>Revert "Add handling of non-admin user for pfSense"<commit_after>package collectors

import (
	"github.com/slarti5191/splendid/configuration"
	"github.com/slarti5191/splendid/utils"
	"regexp"
)

type devPfsense struct {
	configuration.DeviceConfig
}

// Collect gathers config.xml from pfSense
func (d devPfsense) Collect() string {
	// Regex matching our config block
	var pf = regexp.MustCompile(`<pfsense>[\s\S]*?<\/pfsense>`)
	// Commands we need to run
	cmd := []string{"8", "cat /conf/config.xml", "exit", "0"}
	// Set up SSH
	s := new(utils.SSHRunner)
	// Connect
	s.Connect(d.User, d.Pass, d.Host)
	// Return our config
	return s.Gather(cmd, pf)
}

func makePfsense(d configuration.DeviceConfig) Collector {
	return &devPfsense{d}
}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package commands

import (
	"fmt"
	"log"
	"strconv"
	"unicode"

	"github.com/nelsam/gxui"
	"github.com/nelsam/vidar/editor"
)

type GotoLine struct {
	statusKeeper

	editor       *editor.CodeEditor
	lineNumInput gxui.TextBox
	input        gxui.Focusable
}

func NewGotoLine(theme gxui.Theme) *GotoLine {
	input := theme.CreateTextBox()
	input.OnTextChanged(func([]gxui.TextBoxEdit) {
		runes := []rune(input.Text())
		for index := 0; index < len(runes); index++ {
			if !unicode.IsDigit(runes[index]) {
				runes = append(runes[:index], runes[index+1:]...)
				index--
			}
		}
		text := string(runes)
		if text != input.Text() {
			input.SetText(text)
		}
	})
	return &GotoLine{
		statusKeeper: statusKeeper{theme: theme},
		lineNumInput: input,
	}
}

func (g *GotoLine) Start(on gxui.Control) gxui.Control {
	g.editor = findEditor(on)
	if g.editor == nil {
		return nil
	}
	g.lineNumInput.SetText("")
	g.input = g.lineNumInput
	return nil
}

func (g *GotoLine) Name() string {
	return "goto-line"
}

func (g *GotoLine) Menu() string {
	return "Edit"
}

func (g *GotoLine) Next() gxui.Focusable {
	input := g.input
	g.input = nil
	return input
}

func (g *GotoLine) Exec(on interface{}) (executed, consume bool) {
	lineStr := g.lineNumInput.Text()
	if lineStr == "" {
		g.warn = "No line number provided"
		return true, true
	}
	line, err := strconv.Atoi(lineStr)
	if err != nil {
		// This shouldn't ever happen, but in the interests of avoiding data loss,
		// we just log that it did.
		log.Printf("ERR: goto-line: failed to parse %s as a line number", g.lineNumInput.Text())
		return true, true
	}
	line = oneToZeroBased(line)
	if line >= g.editor.Controller().LineCount() {
		g.err = fmt.Sprintf("Line %d is past the end of the file", line)
		return true, true
	}
	g.editor.Controller().SetCaret(g.editor.LineStart(line))
	g.editor.ScrollToLine(line)
	return true, true
}
<commit_msg>add checked on zero line<commit_after>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package commands

import (
	"fmt"
	"log"
	"strconv"
	"unicode"

	"github.com/nelsam/gxui"
	"github.com/nelsam/vidar/editor"
)

type GotoLine struct {
	statusKeeper

	editor       *editor.CodeEditor
	lineNumInput gxui.TextBox
	input        gxui.Focusable
}

func NewGotoLine(theme gxui.Theme) *GotoLine {
	input := theme.CreateTextBox()
	input.OnTextChanged(func([]gxui.TextBoxEdit) {
		runes := []rune(input.Text())
		for index := 0; index < len(runes); index++ {
			if !unicode.IsDigit(runes[index]) {
				runes = append(runes[:index], runes[index+1:]...)
				index--
			}
		}
		text := string(runes)
		if text != input.Text() {
			input.SetText(text)
		}
	})
	return &GotoLine{
		statusKeeper: statusKeeper{theme: theme},
		lineNumInput: input,
	}
}

func (g *GotoLine) Start(on gxui.Control) gxui.Control {
	g.editor = findEditor(on)
	if g.editor == nil {
		return nil
	}
	g.lineNumInput.SetText("")
	g.input = g.lineNumInput
	return nil
}

func (g *GotoLine) Name() string {
	return "goto-line"
}

func (g *GotoLine) Menu() string {
	return "Edit"
}

func (g *GotoLine) Next() gxui.Focusable {
	input := g.input
	g.input = nil
	return input
}

func (g *GotoLine) Exec(on interface{}) (executed, consume bool) {
	lineStr := g.lineNumInput.Text()
	if lineStr == "" {
		g.warn = "No line number provided"
		return true, true
	}
	line, err := strconv.Atoi(lineStr)
	if err != nil {
		// This shouldn't ever happen, but in the interests of avoiding data loss,
		// we just log that it did.
		log.Printf("ERR: goto-line: failed to parse %s as a line number", g.lineNumInput.Text())
		return true, true
	}
	line = oneToZeroBased(line)
	if line >= g.editor.Controller().LineCount() {
		g.err = fmt.Sprintf("Line %d is past the end of the file", line)
		return true, true
	}
	if line == -1 {
		g.err = "0 line is not exist"
		return true, true
	}
	g.editor.Controller().SetCaret(g.editor.LineStart(line))
	g.editor.ScrollToLine(line)
	return true, true
}
<|endoftext|>


<commit_before>package help

import (
	"github.com/igungor/ilberbot"
)

func init() {
	ilberbot.RegisterCommand("/help", help)
}

func help(args ...string) string {
	return `
sunlar var:

iftar - iftar vakti
sahur - sahur vakti
okundumu - is it read?
bugunkandilmi - is it candle?
vizyon - sinema felan
hava - nem fena nem
yo - yigit ozgur seysi
tatil - ne zaman
benkimim - ilber!
echo - cok cahilsin
`
}
<commit_msg>rearrange help output<commit_after>package help

import (
	"github.com/igungor/ilberbot"
)

func init() {
	ilberbot.RegisterCommand("/help", help)
}

func help(args ...string) string {
	return `
sunlar var:

bugunkandilmi - is it candle?
vizyon - sinema felan
hava - nem fena nem
yo - yigit ozgur seysi
caps - incicaps gibi degil gibi
imdb - ayemdiibii
tatil - ne zaman
benkimim - ilber!
echo - cok cahilsin
`
}
<|endoftext|>


<commit_before>package lastfm

import (
	"fmt"
	"github.com/0x263b/Porygon2"
	"github.com/0x263b/Porygon2/web"
	"strings"
)

func whosPlaying(command *bot.Cmd, matches []string) (msg string, err error) {
	users := bot.GetNames(strings.ToLower(command.Channel))

	var playing []string

	for index, user := range users {
		if bot.GetUserKey(user, "lastfm") != "" {
			playing = append(playing, user)
		}
	}

	for _, user := range playing {
		username := checkLastfm(user)

		data := &NowPlaying{}
		err = web.GetJSON(fmt.Sprintf(NowPlayingURL, username, bot.API.Lastfm), data)
		if err != nil || data.Error > 0 {
			continue
		}
		if data.Recenttracks.Attr.Total == "0" {
			continue
		}

		if data.Recenttracks.Track[0].Attr.Nowplaying != "true" {
			continue
		}

		var fmttags string
		if len(data.Recenttracks.Track[0].Artist.Mbid) > 10 {
			tags := &ArtistTags{}
			err = web.GetJSON(fmt.Sprintf(ArtistTagsURL, data.Recenttracks.Track[0].Artist.Mbid, bot.API.Lastfm), tags)
			if err != nil {
				continue
			}

			for i := range tags.Toptags.Tag[:4] {
				fmttags += fmt.Sprintf("%s, ", tags.Toptags.Tag[i].Name)
			}

			fmttags = strings.TrimSuffix(fmttags, ", ")
		}

		bot.Conn.Privmsg(command.Channel, fmt.Sprintf("%s (%s): “%s” by %s | %s",
			user,
			username,
			data.Recenttracks.Track[0].Name,
			data.Recenttracks.Track[0].Artist.Text,
			fmttags))
	}

	return "", nil
}

func init() {
	bot.RegisterCommand(
		"^wp$",
		whosPlaying)
}
<commit_msg>index declared and not used<commit_after>package lastfm

import (
	"fmt"
	"github.com/0x263b/Porygon2"
	"github.com/0x263b/Porygon2/web"
	"strings"
)

func whosPlaying(command *bot.Cmd, matches []string) (msg string, err error) {
	users := bot.GetNames(strings.ToLower(command.Channel))

	var playing []string

	for _, user := range users {
		if bot.GetUserKey(user, "lastfm") != "" {
			playing = append(playing, user)
		}
	}

	for _, user := range playing {
		username := checkLastfm(user)

		data := &NowPlaying{}
		err = web.GetJSON(fmt.Sprintf(NowPlayingURL, username, bot.API.Lastfm), data)
		if err != nil || data.Error > 0 {
			continue
		}
		if data.Recenttracks.Attr.Total == "0" {
			continue
		}

		if data.Recenttracks.Track[0].Attr.Nowplaying != "true" {
			continue
		}

		var fmttags string
		if len(data.Recenttracks.Track[0].Artist.Mbid) > 10 {
			tags := &ArtistTags{}
			err = web.GetJSON(fmt.Sprintf(ArtistTagsURL, data.Recenttracks.Track[0].Artist.Mbid, bot.API.Lastfm), tags)
			if err != nil {
				continue
			}

			for i := range tags.Toptags.Tag[:4] {
				fmttags += fmt.Sprintf("%s, ", tags.Toptags.Tag[i].Name)
			}

			fmttags = strings.TrimSuffix(fmttags, ", ")
		}

		bot.Conn.Privmsg(command.Channel, fmt.Sprintf("%s (%s): “%s” by %s | %s",
			user,
			username,
			data.Recenttracks.Track[0].Name,
			data.Recenttracks.Track[0].Artist.Text,
			fmttags))
	}

	return "", nil
}

func init() {
	bot.RegisterCommand(
		"^wp$",
		whosPlaying)
}
<|endoftext|>


<commit_before>package commands

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/cloudfoundry/cli/plugin"
	. "github.com/cloudfoundry/v3-cli-plugin/models"
	. "github.com/cloudfoundry/v3-cli-plugin/util"
)

func Processes(cliConnection plugin.CliConnection, args []string) {
	mySpace, err := cliConnection.GetCurrentSpace()
	FreakOut(err)

	rawOutput, err := cliConnection.CliCommandWithoutTerminalOutput("curl", "v3/processes?per_page=5000", "-X", "GET")
	FreakOut(err)
	output := strings.Join(rawOutput, "")
	processes := V3ProcessesModel{}
	err = json.Unmarshal([]byte(output), &processes)
	FreakOut(err)

	if len(processes.Processes) > 0 {
		processesTable := NewTable([]string{("app"), ("type"), ("instances"), ("memory in MB"), ("disk in MB")})
		for _, v := range processes.Processes {
			if strings.Contains(v.Links.Space.Href, mySpace.Guid) {
				appName := "N/A"
				if v.Links.App.Href != "/v3/apps/" {
					appName = strings.Split(v.Links.App.Href, "/v3/apps/")[1]
				}
				processesTable.Add(
					appName,
					v.Type,
					strconv.Itoa(v.Instances),
					strconv.Itoa(v.Memory)+"MB",
					strconv.Itoa(v.Disk)+"MB",
				)
			}
		}
		fmt.Println("print table?")
		processesTable.Print()
	} else {
		fmt.Println("No v3 processes found.")
	}
}
<commit_msg>Print app name instead of guid when listing v3 processes<commit_after>package commands

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/cloudfoundry/cli/plugin"
	. "github.com/cloudfoundry/v3-cli-plugin/models"
	. "github.com/cloudfoundry/v3-cli-plugin/util"
)

func Processes(cliConnection plugin.CliConnection, args []string) {
	mySpace, err := cliConnection.GetCurrentSpace()
	FreakOut(err)

	rawOutput, err := cliConnection.CliCommandWithoutTerminalOutput("curl", "v3/processes?per_page=5000", "-X", "GET")
	FreakOut(err)
	output := strings.Join(rawOutput, "")
	processes := V3ProcessesModel{}
	err = json.Unmarshal([]byte(output), &processes)
	FreakOut(err)

	rawOutput, err = cliConnection.CliCommandWithoutTerminalOutput("curl", "v3/apps?per_page=5000", "-X", "GET")
	FreakOut(err)
	output = strings.Join(rawOutput, "")
	apps := V3AppsModel{}
	err = json.Unmarshal([]byte(output), &apps)
	FreakOut(err)
	appsMap := make(map[string]V3AppModel)
	for _, app := range apps.Apps {
		appsMap[app.Guid] = app
	}

	if len(processes.Processes) > 0 {
		processesTable := NewTable([]string{("app"), ("type"), ("instances"), ("memory in MB"), ("disk in MB")})
		for _, v := range processes.Processes {
			if strings.Contains(v.Links.Space.Href, mySpace.Guid) {
				appName := "N/A"
				if v.Links.App.Href != "/v3/apps/" {
					appGuid := strings.Split(v.Links.App.Href, "/v3/apps/")[1]
					appName = appsMap[appGuid].Name
				}
				processesTable.Add(
					appName,
					v.Type,
					strconv.Itoa(v.Instances),
					strconv.Itoa(v.Memory)+"MB",
					strconv.Itoa(v.Disk)+"MB",
				)
			}
		}
		processesTable.Print()
	} else {
		fmt.Println("No v3 processes found.")
	}
}
<|endoftext|>