<commit_before>package main

import (
	"context"
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"regexp"
	"runtime"
	"time"

	"github.com/lomik/graphite-clickhouse/autocomplete"
	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/find"
	"github.com/lomik/graphite-clickhouse/helper/version"
	"github.com/lomik/graphite-clickhouse/index"
	"github.com/lomik/graphite-clickhouse/prometheus"
	"github.com/lomik/graphite-clickhouse/render"
	"github.com/lomik/graphite-clickhouse/tagger"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of graphite-clickhouse
const Version = "0.7.0"

func init() {
	version.Version = Version
}

type LogResponseWriter struct {
	http.ResponseWriter
	status int
}

func (w *LogResponseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *LogResponseWriter) Status() int {
	if w.status == 0 {
		return http.StatusOK
	}
	return w.status
}

func WrapResponseWriter(w http.ResponseWriter) *LogResponseWriter {
	if wrapped, ok := w.(*LogResponseWriter); ok {
		return wrapped
	}
	return &LogResponseWriter{ResponseWriter: w}
}

var requestIdRegexp *regexp.Regexp = regexp.MustCompile("^[a-zA-Z0-9_.-]+$")

func Handler(logger *zap.Logger, handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := WrapResponseWriter(w)

		requestID := r.Header.Get("X-Request-Id")
		if requestID == "" || !requestIdRegexp.MatchString(requestID) {
			var b [16]byte
			binary.LittleEndian.PutUint64(b[:], rand.Uint64())
			binary.LittleEndian.PutUint64(b[8:], rand.Uint64())
			requestID = fmt.Sprintf("%x", b)
		}

		logger := logger.With(zap.String("request_id", requestID))

		r = r.WithContext(
			context.WithValue(
				context.WithValue(
					r.Context(),
					"logger",
					logger,
				),
				"requestID",
				requestID,
			),
		)

		start := time.Now()
		handler.ServeHTTP(writer, r)
		d := time.Since(start)
		logger.Info("access",
			zap.Duration("time", d),
			zap.String("method", r.Method),
			zap.String("url", r.URL.String()),
			zap.String("peer", r.RemoteAddr),
			zap.Int("status", writer.Status()),
		)
	})
}

func main() {
	rand.Seed(time.Now().UnixNano())

	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/graphite-clickhouse/graphite-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	buildTags := flag.Bool("tags", false, "Build tags table")

	printVersion := flag.Bool("version", false, "Print version")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *printDefaultConfig {
		if err = config.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	cfg, err := config.ReadConfig(*configFile)
	if err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	runtime.GOMAXPROCS(cfg.Common.MaxCPU)

	/* CONFIG end */

	/* CONSOLE COMMANDS start */
	if *buildTags {
		if err := tagger.Make(cfg); err != nil {
			log.Fatal(err)
		}
		return
	}

	/* CONSOLE COMMANDS end */

	http.Handle("/metrics/find/", Handler(zapwriter.Default(), find.NewHandler(cfg)))
	http.Handle("/metrics/index.json", Handler(zapwriter.Default(), index.NewHandler(cfg)))
	http.Handle("/render/", Handler(zapwriter.Default(), render.NewHandler(cfg)))
	http.Handle("/read", Handler(zapwriter.Default(), prometheus.NewHandler(cfg)))
	http.Handle("/tags/autoComplete/tags", Handler(zapwriter.Default(), autocomplete.NewTags(cfg)))
	http.Handle("/tags/autoComplete/values", Handler(zapwriter.Default(), autocomplete.NewValues(cfg)))

	http.Handle("/", Handler(zapwriter.Default(), http.HandlerFunc(http.NotFound)))

	log.Fatal(http.ListenAndServe(cfg.Common.Listen, nil))
}
<commit_msg>version 0.8.0<commit_after>package main

import (
	"context"
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"regexp"
	"runtime"
	"time"

	"github.com/lomik/graphite-clickhouse/autocomplete"
	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/find"
	"github.com/lomik/graphite-clickhouse/helper/version"
	"github.com/lomik/graphite-clickhouse/index"
	"github.com/lomik/graphite-clickhouse/prometheus"
	"github.com/lomik/graphite-clickhouse/render"
	"github.com/lomik/graphite-clickhouse/tagger"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of graphite-clickhouse
const Version = "0.8.0"

func init() {
	version.Version = Version
}

type LogResponseWriter struct {
	http.ResponseWriter
	status int
}

func (w *LogResponseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *LogResponseWriter) Status() int {
	if w.status == 0 {
		return http.StatusOK
	}
	return w.status
}

func WrapResponseWriter(w http.ResponseWriter) *LogResponseWriter {
	if wrapped, ok := w.(*LogResponseWriter); ok {
		return wrapped
	}
	return &LogResponseWriter{ResponseWriter: w}
}

var requestIdRegexp *regexp.Regexp = regexp.MustCompile("^[a-zA-Z0-9_.-]+$")

func Handler(logger *zap.Logger, handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := WrapResponseWriter(w)

		requestID := r.Header.Get("X-Request-Id")
		if requestID == "" || !requestIdRegexp.MatchString(requestID) {
			var b [16]byte
			binary.LittleEndian.PutUint64(b[:], rand.Uint64())
			binary.LittleEndian.PutUint64(b[8:], rand.Uint64())
			requestID = fmt.Sprintf("%x", b)
		}

		logger := logger.With(zap.String("request_id", requestID))

		r = r.WithContext(
			context.WithValue(
				context.WithValue(
					r.Context(),
					"logger",
					logger,
				),
				"requestID",
				requestID,
			),
		)

		start := time.Now()
		handler.ServeHTTP(writer, r)
		d := time.Since(start)
		logger.Info("access",
			zap.Duration("time", d),
			zap.String("method", r.Method),
			zap.String("url", r.URL.String()),
			zap.String("peer", r.RemoteAddr),
			zap.Int("status", writer.Status()),
		)
	})
}

func main() {
	rand.Seed(time.Now().UnixNano())

	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/graphite-clickhouse/graphite-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	buildTags := flag.Bool("tags", false, "Build tags table")

	printVersion := flag.Bool("version", false, "Print version")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *printDefaultConfig {
		if err = config.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	cfg, err := config.ReadConfig(*configFile)
	if err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	runtime.GOMAXPROCS(cfg.Common.MaxCPU)

	/* CONFIG end */

	/* CONSOLE COMMANDS start */
	if *buildTags {
		if err := tagger.Make(cfg); err != nil {
			log.Fatal(err)
		}
		return
	}

	/* CONSOLE COMMANDS end */

	http.Handle("/metrics/find/", Handler(zapwriter.Default(), find.NewHandler(cfg)))
	http.Handle("/metrics/index.json", Handler(zapwriter.Default(), index.NewHandler(cfg)))
	http.Handle("/render/", Handler(zapwriter.Default(), render.NewHandler(cfg)))
	http.Handle("/read", Handler(zapwriter.Default(), prometheus.NewHandler(cfg)))
	http.Handle("/tags/autoComplete/tags", Handler(zapwriter.Default(), autocomplete.NewTags(cfg)))
	http.Handle("/tags/autoComplete/values", Handler(zapwriter.Default(), autocomplete.NewValues(cfg)))

	http.Handle("/", Handler(zapwriter.Default(), http.HandlerFunc(http.NotFound)))

	log.Fatal(http.ListenAndServe(cfg.Common.Listen, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync/atomic"
	"time"

	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/find"
	"github.com/lomik/graphite-clickhouse/render"
	"github.com/lomik/graphite-clickhouse/tagger"
	"github.com/lomik/zapwriter"
	"github.com/uber-go/zap"

	_ "net/http/pprof"
)

// Version of graphite-clickhouse
const Version = "0.2.1"

type LogResponseWriter struct {
	http.ResponseWriter
	status int
}

func (w *LogResponseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *LogResponseWriter) Status() int {
	if w.status == 0 {
		return http.StatusOK
	}
	return w.status
}

func WrapResponseWriter(w http.ResponseWriter) *LogResponseWriter {
	if wrapped, ok := w.(*LogResponseWriter); ok {
		return wrapped
	}
	return &LogResponseWriter{ResponseWriter: w}
}

func Handler(logger zap.Logger, handler http.Handler) http.Handler {
	var requestCounter uint32
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := WrapResponseWriter(w)

		requestID := r.Header.Get("X-Request-Id")
		if requestID == "" {
			requestID = fmt.Sprintf("%d", atomic.AddUint32(&requestCounter, 1))
		}

		logger := logger.With(zap.String("request_id", requestID))

		r = r.WithContext(context.WithValue(r.Context(), "logger", logger))

		start := time.Now()
		handler.ServeHTTP(w, r)
		d := time.Since(start)
		logger.Info("access",
			zap.String("runtime", d.String()),
			zap.Duration("runtime_ns", d),
			zap.String("method", r.Method),
			zap.String("url", r.URL.String()),
			zap.String("peer", r.RemoteAddr),
			zap.Int("status", writer.Status()),
		)
	})
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/graphite-clickhouse/graphite-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	tags := flag.Bool("tags", false, "Build tags table")

	printVersion := flag.Bool("version", false, "Print version")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *printDefaultConfig {
		if err = config.Print(config.New()); err != nil {
			log.Fatal(err)
		}
		return
	}

	cfg := config.New()
	if err := config.Parse(*configFile, cfg); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}
	runtime.GOMAXPROCS(cfg.Common.MaxCPU)

	zapOutput, err := zapwriter.New(cfg.Logging.File)
	if err != nil {
		log.Fatal(err)
	}

	var logLevel zap.Level
	if err = logLevel.UnmarshalText([]byte(cfg.Logging.Level)); err != nil {
		log.Fatal(err)
	}

	dynamicLevel := zap.DynamicLevel()
	dynamicLevel.SetLevel(logLevel)

	logger := zap.New(
		zapwriter.NewMixedEncoder(),
		zap.AddCaller(),
		zap.Output(zapOutput),
		dynamicLevel,
	)

	/* CONFIG end */

	/* CONSOLE COMMANDS start */
	if *tags {
		if err := tagger.Make(cfg, logger.With(zap.String("module", "tagger"))); err != nil {
			log.Fatal(err)
		}
		return
	}

	/* CONSOLE COMMANDS end */

	http.Handle("/metrics/find/", Handler(logger, find.NewHandler(cfg)))
	http.Handle("/render/", Handler(logger, render.NewHandler(cfg)))

	http.Handle("/", Handler(logger, http.HandlerFunc(http.NotFound)))

	log.Fatal(http.ListenAndServe(cfg.Common.Listen, nil))
}
<commit_msg>version 0.3.0<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync/atomic"
	"time"

	"github.com/lomik/graphite-clickhouse/config"
	"github.com/lomik/graphite-clickhouse/find"
	"github.com/lomik/graphite-clickhouse/render"
	"github.com/lomik/graphite-clickhouse/tagger"
	"github.com/lomik/zapwriter"
	"github.com/uber-go/zap"

	_ "net/http/pprof"
)

// Version of graphite-clickhouse
const Version = "0.3.0"

type LogResponseWriter struct {
	http.ResponseWriter
	status int
}

func (w *LogResponseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *LogResponseWriter) Status() int {
	if w.status == 0 {
		return http.StatusOK
	}
	return w.status
}

func WrapResponseWriter(w http.ResponseWriter) *LogResponseWriter {
	if wrapped, ok := w.(*LogResponseWriter); ok {
		return wrapped
	}
	return &LogResponseWriter{ResponseWriter: w}
}

func Handler(logger zap.Logger, handler http.Handler) http.Handler {
	var requestCounter uint32
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := WrapResponseWriter(w)

		requestID := r.Header.Get("X-Request-Id")
		if requestID == "" {
			requestID = fmt.Sprintf("%d", atomic.AddUint32(&requestCounter, 1))
		}

		logger := logger.With(zap.String("request_id", requestID))

		r = r.WithContext(context.WithValue(r.Context(), "logger", logger))

		start := time.Now()
		handler.ServeHTTP(w, r)
		d := time.Since(start)
		logger.Info("access",
			zap.String("runtime", d.String()),
			zap.Duration("runtime_ns", d),
			zap.String("method", r.Method),
			zap.String("url", r.URL.String()),
			zap.String("peer", r.RemoteAddr),
			zap.Int("status", writer.Status()),
		)
	})
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/graphite-clickhouse/graphite-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	tags := flag.Bool("tags", false, "Build tags table")

	printVersion := flag.Bool("version", false, "Print version")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *printDefaultConfig {
		if err = config.Print(config.New()); err != nil {
			log.Fatal(err)
		}
		return
	}

	cfg := config.New()
	if err := config.Parse(*configFile, cfg); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}
	runtime.GOMAXPROCS(cfg.Common.MaxCPU)

	zapOutput, err := zapwriter.New(cfg.Logging.File)
	if err != nil {
		log.Fatal(err)
	}

	var logLevel zap.Level
	if err = logLevel.UnmarshalText([]byte(cfg.Logging.Level)); err != nil {
		log.Fatal(err)
	}

	dynamicLevel := zap.DynamicLevel()
	dynamicLevel.SetLevel(logLevel)

	logger := zap.New(
		zapwriter.NewMixedEncoder(),
		zap.AddCaller(),
		zap.Output(zapOutput),
		dynamicLevel,
	)

	/* CONFIG end */

	/* CONSOLE COMMANDS start */
	if *tags {
		if err := tagger.Make(cfg, logger.With(zap.String("module", "tagger"))); err != nil {
			log.Fatal(err)
		}
		return
	}

	/* CONSOLE COMMANDS end */

	http.Handle("/metrics/find/", Handler(logger, find.NewHandler(cfg)))
	http.Handle("/render/", Handler(logger, render.NewHandler(cfg)))

	http.Handle("/", Handler(logger, http.HandlerFunc(http.NotFound)))

	log.Fatal(http.ListenAndServe(cfg.Common.Listen, nil))
}
<|endoftext|>


<commit_before>/**
 * @file counter.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief cound round results
 *
 * Contain functions for work with round results
 */

package counter

import "database/sql"

import "github.com/jollheef/tin_foil_hat/steward"

func CountStatesResult(db *sql.DB, round, team int,
	service steward.Service) (score float64, err error) {

	halfStatus := steward.Status{round, team, service.Id,
		steward.STATUS_UNKNOWN}

	states, err := steward.GetStates(db, halfStatus)
	if err != nil {
		return
	}

	if len(states) == 0 {
		return
	}

	ok := 0.0
	for _, state := range states {
		if state == steward.STATUS_UP {
			ok++
		}
	}

	score = 1.0 / float64(len(states)) * ok

	return
}

func CountDefenceResult(db *sql.DB, round, team int,
	services []steward.Service) (defence float64, err error) {

	defence = 0

	per_service := 1.0 / float64(len(services))

	for _, svc := range services {

		score, err := CountStatesResult(db, round, team, svc)
		if err != nil {
			return defence, err
		}

		defence += score * per_service
	}

	return
}

func CountRound(db *sql.DB, round int, teams []steward.Team,
	services []steward.Service) (err error) {

	round_res := make(map[steward.Team]steward.RoundResult)

	for _, team := range teams {

		res := steward.RoundResult{TeamId: team.Id, Round: round}

		def, err := CountDefenceResult(db, round, team.Id, services)
		if err != nil {
			return err
		}

		res.DefenceScore = def * 2

		round_res[team] = res
	}

	per_service := 1.0 / float64(len(services))

	for _, team := range teams {

		cflags, err := steward.GetCapturedFlags(db, round, team.Id)
		if err != nil {
			return err
		}

		for _, flag := range cflags {

			attacked_team, err := steward.GetTeam(db, flag.TeamId)
			if err != nil {
				return err
			}

			res := round_res[attacked_team]
			res.DefenceScore -= per_service
			if res.DefenceScore < 0 {
				res.DefenceScore = 0
			}
			round_res[attacked_team] = res

			attack_res := round_res[team]
			attack_res.AttackScore += per_service
			round_res[team] = attack_res
		}
	}

	for _, res := range round_res {
		_, err := steward.AddRoundResult(db, res)
		if err != nil {
			return err
		}

	}

	return
}
<commit_msg>Refactor counter module<commit_after>/**
 * @file counter.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU GPLv3
 * @date September, 2015
 * @brief cound round results
 *
 * Contain functions for work with round results
 */

package counter

import (
	"database/sql"

	"github.com/jollheef/tin_foil_hat/steward"
)

// CountStatesResult count round states (up/down/etc.) result
func CountStatesResult(db *sql.DB, round, team int,
	service steward.Service) (score float64, err error) {

	halfStatus := steward.Status{round, team, service.Id,
		steward.STATUS_UNKNOWN}

	states, err := steward.GetStates(db, halfStatus)
	if err != nil {
		return
	}

	if len(states) == 0 {
		return
	}

	ok := 0.0
	for _, state := range states {
		if state == steward.STATUS_UP {
			ok++
		}
	}

	score = 1.0 / float64(len(states)) * ok

	return
}

// CountDefenceResult count round defence result
func CountDefenceResult(db *sql.DB, round, team int,
	services []steward.Service) (defence float64, err error) {

	defence = 0

	perService := 1.0 / float64(len(services))

	for _, svc := range services {

		score, err := CountStatesResult(db, round, team, svc)
		if err != nil {
			return defence, err
		}

		defence += score * perService
	}

	return
}

// CountRound count round result
func CountRound(db *sql.DB, round int, teams []steward.Team,
	services []steward.Service) (err error) {

	roundRes := make(map[steward.Team]steward.RoundResult)

	for _, team := range teams {

		res := steward.RoundResult{TeamId: team.Id, Round: round}

		def, err := CountDefenceResult(db, round, team.Id, services)
		if err != nil {
			return err
		}

		res.DefenceScore = def * 2

		roundRes[team] = res
	}

	perService := 1.0 / float64(len(services))

	for _, team := range teams {

		cflags, err := steward.GetCapturedFlags(db, round, team.Id)
		if err != nil {
			return err
		}

		for _, flag := range cflags {

			attackedTeam, err := steward.GetTeam(db, flag.TeamId)
			if err != nil {
				return err
			}

			res := roundRes[attackedTeam]
			res.DefenceScore -= perService
			if res.DefenceScore < 0 {
				res.DefenceScore = 0
			}
			roundRes[attackedTeam] = res

			attackRes := roundRes[team]
			attackRes.AttackScore += perService
			roundRes[team] = attackRes
		}
	}

	for _, res := range roundRes {
		_, err := steward.AddRoundResult(db, res)
		if err != nil {
			return err
		}

	}

	return
}
<|endoftext|>


<commit_before>// Package to help map ISO Country Codes
//
// ISO 3166-1
// https://en.wikipedia.org/wiki/ISO_3166-1
//
// Defines standardized 2-digit, 3-digit, and numeric codes this package
// provides a way to easily convert between them.
//
// All country data is contained in tab-delimited countries.txt.
// To update with new country information edit this file with
// the new information
//
// To compile this package you need to run:
//  go generate
//
// This will generate all the necessary go maps that hold the mapping Data
//
package iso

import (
	"fmt"
)

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 1 -m alpha2ToCountry -p iso -h
// Map between Country Name and 2-digit alpha code
func GetCountryNameFromISOAlpha2(alpha2 string) (string, error) {
	country, ok := alpha3ToCountry[alpha2]
	if !ok {
		return "", fmt.Errorf("No country found for alpha3 '%s'", alpha2)
	}
	return country, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 1 -m alpha3ToCountry -p iso -h
// Map between Country Name and 3-digit alpha code
func GetCountryNameFromISOAlpha3(alpha3 string) (string, error) {
	country, ok := alpha3ToCountry[alpha3]
	if !ok {
		return "", fmt.Errorf("No country found for alpha3 '%s'", alpha3)
	}
	return country, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 1 -m alpha3ToAlpha2 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha2FromAlpha3(alpha3 string) (string, error) {
	alpha2, ok := alpha3ToAlpha2[alpha3]
	if !ok {
		return "", fmt.Errorf("No alpha2 code found for alpha2 '%s'", alpha3)
	}
	return alpha2, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 1 -m alpha2ToAlpha3 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha3FromAlpha2(alpha2 string) (string, error) {
	alpha3, ok := alpha2ToAlpha3[alpha2]
	if !ok {
		return "", fmt.Errorf("No alpha3 code found for alpha2 '%s'", alpha2)
	}
	return alpha3, nil
}
<commit_msg>adding numerics<commit_after>// Package to help map ISO Country Codes
//
// ISO 3166-1
// https://en.wikipedia.org/wiki/ISO_3166-1
//
// Defines standardized 2-digit, 3-digit, and numeric codes this package
// provides a way to easily convert between them.
//
// All country data is contained in tab-delimited countries.txt.
// To update with new country information edit this file with
// the new information
//
// To compile this package you need to run:
//  go generate
//
// This will generate all the necessary go maps that hold the mapping Data
//
package iso

import (
	"fmt"
)

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 1 -m alpha2ToCountry -p iso -h
// Map between Country Name and 2-digit alpha code
func GetCountryNameFromISOAlpha2(alpha2 string) (string, error) {
	country, ok := alpha3ToCountry[alpha2]
	if !ok {
		return "", fmt.Errorf("No country found for alpha3 '%s'", alpha2)
	}
	return country, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 3 -v 1 -m alpha3ToCountry -p iso -h
// Map between Country Name and 3-digit alpha code
func GetCountryNameFromISOAlpha3(alpha3 string) (string, error) {
	country, ok := alpha3ToCountry[alpha3]
	if !ok {
		return "", fmt.Errorf("No country found for alpha3 '%s'", alpha3)
	}
	return country, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 3 -v 2 -m alpha3ToAlpha2 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha2FromAlpha3(alpha3 string) (string, error) {
	alpha2, ok := alpha3ToAlpha2[alpha3]
	if !ok {
		return "", fmt.Errorf("No alpha2 code found for alpha2 '%s'", alpha3)
	}
	return alpha2, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 2 -v 3 -m alpha2ToAlpha3 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha3FromAlpha2(alpha2 string) (string, error) {
	alpha3, ok := alpha2ToAlpha3[alpha2]
	if !ok {
		return "", fmt.Errorf("No alpha3 code found for alpha2 '%s'", alpha2)
	}
	return alpha3, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 4 -v 1 -m numericToCountry -p iso -h
// Map between Country Name and 3-digit alpha code
func GetCountryNameFromISONumeric(numeric string) (string, error) {
	country, ok := numericToCountry[numeric]
	if !ok {
		return "", fmt.Errorf("No country found for numeric '%s'", numeric)
	}
	return country, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 4 -v 2 -m numericToAlpha2 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha2FromNumeric(numeric string) (string, error) {
	alpha2, ok := numericToAlpha2[numeric]
	if !ok {
		return "", fmt.Errorf("No alpha2 code found for numeric '%s'", numeric)
	}
	return alpha2, nil
}

//go:generate csv2map -d "\t" -in country.txt -k 4 -v 3 -m numericToAlpha3 -p iso -h
// Map between 3-digit alpha code and 2-digit alpha code
func GetISOAlpha3FromNumeric(numeric string) (string, error) {
	alpha3, ok := numericToAlpha3[numeric]
	if !ok {
		return "", fmt.Errorf("No alpha3 code found for numeric '%s'", numeric)
	}
	return alpha3, nil
}
<|endoftext|>


<commit_before>package autosignr

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
)

type AccountAWS struct {
	Name        string
	Key         string
	Secret      string
	Regions     []string
	AccountType string
	aws_creds   *credentials.Credentials
}

func NewAccountAWS(data map[interface{}]interface{}) *AccountAWS {

	r := make([]string, len(data["regions"].([]interface{})))
	for i := range data["regions"].([]interface{}) {
		r[i] = data["regions"].([]interface{})[i].(string)
	}

	f := AccountAWS{
		Name:        data["name"].(string),
		Key:         data["key_id"].(string),
		Secret:      data["secret_key"].(string),
		Regions:     r,
		AccountType: "aws",
	}

	f.aws_creds = credentials.NewStaticCredentials(
		f.Key,
		f.Secret,
		"")

	return &f
}

func (a AccountAWS) Type() string {
	return a.AccountType
}

func (a AccountAWS) Check(instanceId string) bool {
	for _, region := range a.Regions {

		log.WithFields(log.Fields{
			"instance": instanceId,
			"region":   region,
			"account":  a.Name,
		}).Debug("checking")

		svc := ec2.New(session.New(), &aws.Config{
			Credentials: a.aws_creds,
			Region:      aws.String(region),
		})

		params := &ec2.DescribeInstancesInput{
			Filters: []*ec2.Filter{
				&ec2.Filter{
					Name: aws.String("instance-id"),
					Values: []*string{
						aws.String(instanceId),
					},
				},
			},
		}

		// Call the DescribeInstances Operation
		resp, err := svc.DescribeInstances(params)
		if err != nil {
			panic(err)
		}

		found := len(resp.Reservations) > 0
		log.WithFields(log.Fields{
			"instance": instanceId,
			"region":   region,
			"account":  a.Name,
			"found":    found,
		}).Debug("check-result")

		if found {
			return true
		}
	}

	return false
}

func (a AccountAWS) String() string {
	return fmt.Sprintf("aws account: %s", a.Name)
}
<commit_msg>fixing gofmt issue<commit_after>package autosignr

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
)

type AccountAWS struct {
	Name        string
	Key         string
	Secret      string
	Regions     []string
	AccountType string
	aws_creds   *credentials.Credentials
}

func NewAccountAWS(data map[interface{}]interface{}) *AccountAWS {

	r := make([]string, len(data["regions"].([]interface{})))
	for i := range data["regions"].([]interface{}) {
		r[i] = data["regions"].([]interface{})[i].(string)
	}

	f := AccountAWS{
		Name:        data["name"].(string),
		Key:         data["key_id"].(string),
		Secret:      data["secret_key"].(string),
		Regions:     r,
		AccountType: "aws",
	}

	f.aws_creds = credentials.NewStaticCredentials(
		f.Key,
		f.Secret,
		"")

	return &f
}

func (a AccountAWS) Type() string {
	return a.AccountType
}

func (a AccountAWS) Check(instanceId string) bool {
	for _, region := range a.Regions {

		log.WithFields(log.Fields{
			"instance": instanceId,
			"region":   region,
			"account":  a.Name,
		}).Debug("checking")

		svc := ec2.New(session.New(), &aws.Config{
			Credentials: a.aws_creds,
			Region:      aws.String(region),
		})

		params := &ec2.DescribeInstancesInput{
			Filters: []*ec2.Filter{
				{
					Name: aws.String("instance-id"),
					Values: []*string{
						aws.String(instanceId),
					},
				},
			},
		}

		// Call the DescribeInstances Operation
		resp, err := svc.DescribeInstances(params)
		if err != nil {
			panic(err)
		}

		found := len(resp.Reservations) > 0
		log.WithFields(log.Fields{
			"instance": instanceId,
			"region":   region,
			"account":  a.Name,
			"found":    found,
		}).Debug("check-result")

		if found {
			return true
		}
	}

	return false
}

func (a AccountAWS) String() string {
	return fmt.Sprintf("aws account: %s", a.Name)
}
<|endoftext|>


<commit_before>package static

import (
	"errors"
	"fmt"
	"github.com/jkomoros/boardgame/boardgame-util/lib/config"
	"os"
	"os/exec"
	"path/filepath"
)

var filesToExclude map[string]bool = map[string]bool{
	".gitignore":      true,
	"README.md":       true,
	polymerConfig:     true,
	nodeModulesFolder: true,
	//Don't copy over because we'll generate our own; if we copy over and
	//generate our own we'll overwrite original.
	clientConfigJsFileName: true,
	".DS_Store":            true,
}

//Server runs a static server. directory is the folder that the `static`
//folder is contained within. If no error is returned, runs until the program
//exits. Under the cover uses `polymer serve` because imports use bare module
//specifiers that must be rewritten.
func Server(directory string, port string) error {

	if err := verifyPolymer(directory); err != nil {
		return err
	}

	staticDir := filepath.Join(directory, staticSubFolder)

	cmd := exec.Command("polymer", "serve", "--port="+port)
	cmd.Dir = staticDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return errors.New("Couldn't `polymer serve`: " + err.Error())
	}

	return nil

}

//CleanCache clears the central cache the build system uses (currently just
//node_modules). If that cache doesn't exist, is a no op.
func CleanCache() error {

	cacheDir, err := buildCachePath()
	if err != nil {
		return errors.New("Couldn't get build cache path: " + err.Error())
	}

	//os.RemoveAll is OK if the path doesn't exist
	return os.RemoveAll(cacheDir)

}

//Build creates a folder of static resources for serving within the static
//subfolder of directory. It symlinks necessary resources in. The return value
//is the directory where the assets can be served from, and an error if there
//was an error. You can clean up the created folder structure with
//CleanStatic. If prodBuild is true, then `polymer build` will be run. If
//copyFiles is true, instead of symlinking the files it will copy them
//(directories will still be symlinked). This is good if you intend to modify
//the files.
func Build(directory string, gameImports []string, c *config.Config, prodBuild bool, copyFiles bool) (assetRoot string, err error) {

	staticDir, err := staticBuildDir(directory)
	if err != nil {
		return "", err
	}

	fmt.Println("Copying base static resources")
	if err := CopyStaticResources(directory, copyFiles); err != nil {
		return "", errors.New("Couldn't copy static resources")
	}

	fmt.Println("Updating " + nodeModulesFolder + " and linking in")
	if err := LinkNodeModules(directory); err != nil {
		return "", errors.New("Couldn't link " + nodeModulesFolder + ": " + err.Error())
	}

	fmt.Println("Creating " + clientConfigJsFileName)
	if err := CreateClientConfigJs(directory, c); err != nil {
		return "", errors.New("Couldn't create " + clientConfigJsFileName + ": " + err.Error())
	}

	fmt.Println("Creating " + gameSrcSubFolder)
	if err := LinkGameClientFolders(directory, gameImports); err != nil {
		return "", errors.New("Couldn't create " + gameSrcSubFolder + ": " + err.Error())
	}

	fmt.Println("Creating " + polymerConfig)
	if err := CreatePolymerJson(directory, false); err != nil {
		return "", errors.New("Couldn't create " + polymerConfig + ": " + err.Error())
	}

	if prodBuild {
		fmt.Println("Building bundled resources with `polymer build`")
		if err := BuildPolymer(directory); err != nil {
			return "", errors.New("Couldn't build bundled resources: " + err.Error())
		}
	}

	return staticDir, nil

}

//Clean removes all of the things created in the static subfolder within
//directory.
func Clean(directory string) error {
	return os.RemoveAll(filepath.Join(directory, staticSubFolder))
}
<commit_msg>Revamp documentation for Build to describe the steps it calls. Part of #671.<commit_after>package static

import (
	"errors"
	"fmt"
	"github.com/jkomoros/boardgame/boardgame-util/lib/config"
	"os"
	"os/exec"
	"path/filepath"
)

var filesToExclude map[string]bool = map[string]bool{
	".gitignore":      true,
	"README.md":       true,
	polymerConfig:     true,
	nodeModulesFolder: true,
	//Don't copy over because we'll generate our own; if we copy over and
	//generate our own we'll overwrite original.
	clientConfigJsFileName: true,
	".DS_Store":            true,
}

//Server runs a static server. directory is the folder that the `static`
//folder is contained within. If no error is returned, runs until the program
//exits. Under the cover uses `polymer serve` because imports use bare module
//specifiers that must be rewritten.
func Server(directory string, port string) error {

	if err := verifyPolymer(directory); err != nil {
		return err
	}

	staticDir := filepath.Join(directory, staticSubFolder)

	cmd := exec.Command("polymer", "serve", "--port="+port)
	cmd.Dir = staticDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return errors.New("Couldn't `polymer serve`: " + err.Error())
	}

	return nil

}

//CleanCache clears the central cache the build system uses (currently just
//node_modules). If that cache doesn't exist, is a no op.
func CleanCache() error {

	cacheDir, err := buildCachePath()
	if err != nil {
		return errors.New("Couldn't get build cache path: " + err.Error())
	}

	//os.RemoveAll is OK if the path doesn't exist
	return os.RemoveAll(cacheDir)

}

/*

Build creates a folder of static resources for a server in the given
directory. It is the primary entrypoint for this package. It has no logic of
its own but serves to call all of the build steps in the correct order.

Specificlaly, it calls: CopyStaticResources, passing copyFiles;
LinkNodeModules; CreateClientConfigJs, passing c; LinkGameClientFolders,
passing gameImports; CreatePolymerJson, passing false. If prodBuild is true,
also calls BuildPolymer.

See the package doc for more about the specific build steps and what they do.

*/
func Build(directory string, gameImports []string, c *config.Config, prodBuild bool, copyFiles bool) (assetRoot string, err error) {

	staticDir, err := staticBuildDir(directory)
	if err != nil {
		return "", err
	}

	fmt.Println("Copying base static resources")
	if err := CopyStaticResources(directory, copyFiles); err != nil {
		return "", errors.New("Couldn't copy static resources")
	}

	fmt.Println("Updating " + nodeModulesFolder + " and linking in")
	if err := LinkNodeModules(directory); err != nil {
		return "", errors.New("Couldn't link " + nodeModulesFolder + ": " + err.Error())
	}

	fmt.Println("Creating " + clientConfigJsFileName)
	if err := CreateClientConfigJs(directory, c); err != nil {
		return "", errors.New("Couldn't create " + clientConfigJsFileName + ": " + err.Error())
	}

	fmt.Println("Creating " + gameSrcSubFolder)
	if err := LinkGameClientFolders(directory, gameImports); err != nil {
		return "", errors.New("Couldn't create " + gameSrcSubFolder + ": " + err.Error())
	}

	fmt.Println("Creating " + polymerConfig)
	if err := CreatePolymerJson(directory, false); err != nil {
		return "", errors.New("Couldn't create " + polymerConfig + ": " + err.Error())
	}

	if prodBuild {
		fmt.Println("Building bundled resources with `polymer build`")
		if err := BuildPolymer(directory); err != nil {
			return "", errors.New("Couldn't build bundled resources: " + err.Error())
		}
	}

	return staticDir, nil

}

//Clean removes all of the things created in the static subfolder within
//directory.
func Clean(directory string) error {
	return os.RemoveAll(filepath.Join(directory, staticSubFolder))
}
<|endoftext|>


<commit_before>package codegen

import (
	"strings"
	"text/template"

	"github.com/jkomoros/boardgame"
)

var headerTemplate *template.Template
var structHeaderTemplate *template.Template
var typedPropertyTemplate *template.Template
var readerTemplate *template.Template
var readSetterTemplate *template.Template
var readSetConfigurerTemplate *template.Template
var enumHeaderTemplate *template.Template
var enumDelegateTemplate *template.Template
var enumItemTemplate *template.Template

func init() {
	funcMap := template.FuncMap{
		"withimmutable": withImmutable,
		"verbfortype":   verbForType,
		"firstLetter":   firstLetter,
	}

	headerTemplate = template.Must(template.New("header").Funcs(funcMap).Parse(headerTemplateText))
	structHeaderTemplate = template.Must(template.New("structHeader").Funcs(funcMap).Parse(structHeaderTemplateText))
	typedPropertyTemplate = template.Must(template.New("typedProperty").Funcs(funcMap).Parse(typedPropertyTemplateText))
	readerTemplate = template.Must(template.New("reader").Funcs(funcMap).Parse(readerTemplateText))
	readSetterTemplate = template.Must(template.New("readsetter").Funcs(funcMap).Parse(readSetterTemplateText))
	readSetConfigurerTemplate = template.Must(template.New("readsetconfigurer").Funcs(funcMap).Parse(readSetConfigurerTemplateText))
	enumHeaderTemplate = template.Must(template.New("enumheader").Funcs(funcMap).Parse(enumHeaderTemplateText))
	enumDelegateTemplate = template.Must(template.New("enumdelegate").Funcs(funcMap).Parse(enumDelegateTemplateText))
	enumItemTemplate = template.Must(template.New("enumitem").Parse(enumItemTemplateText))
}

func withImmutable(in string) string {
	prefix := ""
	rest := in
	parts := strings.Split(in, ".")
	if len(parts) > 1 {
		prefix = strings.Join(parts[:len(parts)-1], ".")
		rest = parts[len(parts)-1]
	}

	if _, needsImmutable := configureTypes[rest]; !needsImmutable {
		return in
	}

	rest = "Immutable" + rest

	if prefix == "" {
		return rest
	}

	return prefix + "." + rest

}

var configureTypes = map[string]bool{
	"Stack": true,
	"Timer": true,
	"Board": true,
	"Val":   true,
	"Enum":  true,
}

func verbForType(in boardgame.PropertyType) string {
	if in.IsInterface() {
		return "Configure"
	}
	return "Set"
}

func firstLetter(in string) string {

	if in == "" {
		return ""
	}

	return strings.ToLower(in[:1])
}

const headerTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help certain structs
 * implement boardgame.PropertyReader and friends. It was generated
 * by the codegen package via 'boardgame-util codegen'.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/

package {{.packageName}}
`

const importText = `import (
	"errors"

	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/enum"
)

`

const structHeaderTemplateText = `// Implementation for {{.StructName}}

var {{.ReaderName}}Props = map[string]boardgame.PropertyType{
	{{range $key, $value := .Fields -}}
		"{{$key}}": boardgame.{{$value.Type.String}},
	{{end}}
}

type {{.ReaderName}} struct {
	data *{{.StructName}}
}

func ({{.FirstLetter}} *{{.ReaderName}}) Props() map[string]boardgame.PropertyType {
	return {{.ReaderName}}Props
}

func ({{.FirstLetter}} *{{.ReaderName}}) Prop(name string) (interface{}, error) {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return nil, errors.New("No such property with that name: " + name)
	}

	{{$firstLetter := .FirstLetter}}

	switch propType {
	{{range $type := .PropertyTypes -}}
	case boardgame.Type{{$type.Key}}:
		return {{$firstLetter}}.{{withimmutable $type.Key}}Prop(name)
	{{end}}
	}

	return nil, errors.New("Unexpected property type: " + propType.String())
}

{{if .OutputReadSetter -}}

func ({{.FirstLetter}} *{{.ReaderName}}) PropMutable(name string) bool {
	switch name {
		{{range $key, $val := .Fields -}}
	case "{{$key}}":
		return {{$val.Mutable}}
		{{end -}}
	}

	return false
}

func ({{.FirstLetter}} *{{.ReaderName}}) SetProp(name string, value interface{}) error {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return errors.New("No such property with that name: " + name)
	}

	switch propType {
	{{range $type := .PropertyTypes -}}
	{{if $type.IsInterface -}}
	case boardgame.Type{{$type.Key}}:
		return errors.New("SetProp does not allow setting mutable types; use ConfigureProp instead")
	{{- else -}}
	case boardgame.Type{{$type.Key}}:
		val, ok := value.({{$type.ImmutableGoType}})
		if !ok {
			return errors.New("Provided value was not of type {{$type.ImmutableGoType}}")
		}
		return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
	{{- end}}
	{{end}}
	}

	return errors.New("Unexpected property type: " + propType.String())
}

{{end}}

{{if .OutputReadSetConfigurer -}}
func ({{.FirstLetter}} *{{.ReaderName}}) ConfigureProp(name string, value interface{}) error {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return errors.New("No such property with that name: " + name)
	}

	switch propType {
	{{range $type := .PropertyTypes -}}
	case boardgame.Type{{$type.Key}}:
		{{if $type.IsInterface -}}
		if {{$firstLetter}}.PropMutable(name) {
			//Mutable variant
			val, ok := value.({{$type.MutableGoType}})
			if !ok {
				return errors.New("Provided value was not of type {{$type.MutableGoType}}")
			}
			return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
		}
		//Immutable variant
		val, ok := value.({{withimmutable $type.ImmutableGoType}})
		if !ok {
			return errors.New("Provided value was not of type {{withimmutable $type.ImmutableGoType}}")
		}
		return {{$firstLetter}}.{{verbfortype $type}}{{withimmutable $type.Key}}Prop(name, val)
		{{- else -}}
			val, ok := value.({{$type.ImmutableGoType}})
			if !ok {
				return errors.New("Provided value was not of type {{$type.ImmutableGoType}}")
			}
			return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
		{{- end}}
	{{end}}
	}

	return errors.New("Unexpected property type: " + propType.String())
}

{{end}}
`

const typedPropertyTemplateText = `func ({{.FirstLetter}} *{{.ReaderName}}) {{withimmutable .PropType.Key}}Prop(name string) ({{.PropType.ImmutableGoType}}, error) {
	{{$firstLetter := .FirstLetter}}
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
				return {{$firstLetter}}.data.{{.Name}}, nil
		{{end}}
	}
	{{end}}

	return {{.PropType.ZeroValue}}, errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{if .OutputReadSetConfigurer -}}
{{if .PropType.IsInterface -}}
func ({{.FirstLetter}} *{{.ReaderName}}) Configure{{.PropType.Key}}Prop(name string, value {{.PropType.MutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				{{if .UpConverter -}}
				slotValue := value.{{.UpConverter}}()
				if slotValue == nil {
					return errors.New("{{.Name}} couldn't be upconverted, returned nil")
				}
				{{$firstLetter}}.data.{{.Name}} = slotValue
				{{- else -}}
				{{$firstLetter}}.data.{{.Name}} = value
				{{- end}}
				return nil
			{{- else -}}
				return boardgame.ErrPropertyImmutable
			{{- end}}
		{{end}}
	}
	{{end}}

	return errors.New("No such {{.PropType.Key}} prop: " + name)

}

func ({{.FirstLetter}} *{{.ReaderName}}) Configure{{withimmutable .PropType.Key}}Prop(name string, value {{withimmutable .PropType.MutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				return boardgame.ErrPropertyImmutable
			{{- else -}}
				{{if .UpConverter -}}
				slotValue := value.{{.UpConverter}}()
				if slotValue == nil {
					return errors.New("{{.Name}} couldn't be upconverted, returned nil")
				}
				{{$firstLetter}}.data.{{.Name}} = slotValue
				{{- else -}}
				{{$firstLetter}}.data.{{.Name}} = value
				{{- end}}
				return nil
			{{- end}}
		{{end}}
	}
	{{end}}

	return errors.New("No such {{withimmutable .PropType.Key}} prop: " + name)

}

{{end}}
{{end}}

{{if .OutputReadSetter -}}
{{if .PropType.IsInterface -}}
func ({{.FirstLetter}} *{{.ReaderName}}) {{.PropType.Key}}Prop(name string) ({{.PropType.MutableGoType}}, error) {
	{{$firstLetter := .FirstLetter}}
	{{$zeroValue := .PropType.ZeroValue}}
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				return {{$firstLetter}}.data.{{.Name}}, nil
			{{- else -}}
				return {{$zeroValue}}, boardgame.ErrPropertyImmutable
			{{- end}}
		{{end}}
	}
	{{end}}

	return {{.PropType.ZeroValue}}, errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{else}}
func ({{.FirstLetter}} *{{.ReaderName}}) Set{{.PropType.Key}}Prop(name string, value {{.PropType.MutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
				{{$firstLetter}}.data.{{.Name}} = value
				return nil
		{{end}}
	}
	{{end}}

	return errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{end}}
{{end}}
`

const readerTemplateText = `//Reader returns an autp-generated boardgame.PropertyReader for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) Reader() boardgame.PropertyReader {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`

const readSetterTemplateText = `//ReadSetter returns an autp-generated boardgame.PropertyReadSetter for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) ReadSetter() boardgame.PropertyReadSetter {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`

const readSetConfigurerTemplateText = `//ReadSetConfigurer returns an autp-generated boardgame.PropertyReadSetConfigurer for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) ReadSetConfigurer() boardgame.PropertyReadSetConfigurer {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`
const enumHeaderTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help configure enums.
 * It was generated by the codegen package via 'boardgame-util codegen'.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/

package {{.packageName}}

import (
	"github.com/jkomoros/boardgame/enum"
)

var enums = enum.NewSet()

`

const enumDelegateTemplateText = `//ConfigureEnums simply returns enums, the auto-generated Enums variable. This
//is output because {{.delegateName}} appears to be a struct that implements
//boardgame.GameDelegate, and does not already have a ConfigureEnums
//explicitly defined.
func ({{firstLetter .delegateName}} *{{.delegateName}}) ConfigureEnums() *enum.Set {
	return enums
}

`

const enumItemTemplateText = `{{if .firstNewKey}}
//Implicitly created constants for {{.prefix}}
const (
	{{.firstNewKey}} = iota - 9223372036854775808
{{range .restNewKeys -}}
	{{.}}
{{- end -}}
)

{{ end -}}
//{{.prefix}}Enum is the enum.Enum for {{.prefix}}
var {{.prefix}}Enum = enums.MustAdd{{if .parents}}Tree{{end}}("{{.prefix}}", map[int]string{
	{{ $prefix := .prefix -}}
	{{range $name, $value := .values -}}
	{{$name}}: "{{$value}}",
	{{end}}
{{if .parents -}} }, map[int]int{
	{{ $prefix := .prefix -}}
	{{range $name, $value := .parents -}}
	{{$name}}: {{$value}},
	{{end}}
{{end -}}
})

`
<commit_msg>Remove a few unimportant uses of withImmutable. Part of #746.<commit_after>package codegen

import (
	"strings"
	"text/template"

	"github.com/jkomoros/boardgame"
)

var headerTemplate *template.Template
var structHeaderTemplate *template.Template
var typedPropertyTemplate *template.Template
var readerTemplate *template.Template
var readSetterTemplate *template.Template
var readSetConfigurerTemplate *template.Template
var enumHeaderTemplate *template.Template
var enumDelegateTemplate *template.Template
var enumItemTemplate *template.Template

func init() {
	funcMap := template.FuncMap{
		"withimmutable": withImmutable,
		"verbfortype":   verbForType,
		"firstLetter":   firstLetter,
	}

	headerTemplate = template.Must(template.New("header").Funcs(funcMap).Parse(headerTemplateText))
	structHeaderTemplate = template.Must(template.New("structHeader").Funcs(funcMap).Parse(structHeaderTemplateText))
	typedPropertyTemplate = template.Must(template.New("typedProperty").Funcs(funcMap).Parse(typedPropertyTemplateText))
	readerTemplate = template.Must(template.New("reader").Funcs(funcMap).Parse(readerTemplateText))
	readSetterTemplate = template.Must(template.New("readsetter").Funcs(funcMap).Parse(readSetterTemplateText))
	readSetConfigurerTemplate = template.Must(template.New("readsetconfigurer").Funcs(funcMap).Parse(readSetConfigurerTemplateText))
	enumHeaderTemplate = template.Must(template.New("enumheader").Funcs(funcMap).Parse(enumHeaderTemplateText))
	enumDelegateTemplate = template.Must(template.New("enumdelegate").Funcs(funcMap).Parse(enumDelegateTemplateText))
	enumItemTemplate = template.Must(template.New("enumitem").Parse(enumItemTemplateText))
}

func withImmutable(in string) string {
	prefix := ""
	rest := in
	parts := strings.Split(in, ".")
	if len(parts) > 1 {
		prefix = strings.Join(parts[:len(parts)-1], ".")
		rest = parts[len(parts)-1]
	}

	if _, needsImmutable := configureTypes[rest]; !needsImmutable {
		return in
	}

	rest = "Immutable" + rest

	if prefix == "" {
		return rest
	}

	return prefix + "." + rest

}

var configureTypes = map[string]bool{
	"Stack": true,
	"Timer": true,
	"Board": true,
	"Val":   true,
	"Enum":  true,
}

func verbForType(in boardgame.PropertyType) string {
	if in.IsInterface() {
		return "Configure"
	}
	return "Set"
}

func firstLetter(in string) string {

	if in == "" {
		return ""
	}

	return strings.ToLower(in[:1])
}

const headerTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help certain structs
 * implement boardgame.PropertyReader and friends. It was generated
 * by the codegen package via 'boardgame-util codegen'.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/

package {{.packageName}}
`

const importText = `import (
	"errors"

	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/enum"
)

`

const structHeaderTemplateText = `// Implementation for {{.StructName}}

var {{.ReaderName}}Props = map[string]boardgame.PropertyType{
	{{range $key, $value := .Fields -}}
		"{{$key}}": boardgame.{{$value.Type.String}},
	{{end}}
}

type {{.ReaderName}} struct {
	data *{{.StructName}}
}

func ({{.FirstLetter}} *{{.ReaderName}}) Props() map[string]boardgame.PropertyType {
	return {{.ReaderName}}Props
}

func ({{.FirstLetter}} *{{.ReaderName}}) Prop(name string) (interface{}, error) {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return nil, errors.New("No such property with that name: " + name)
	}

	{{$firstLetter := .FirstLetter}}

	switch propType {
	{{range $type := .PropertyTypes -}}
	case boardgame.Type{{$type.Key}}:
		return {{$firstLetter}}.{{withimmutable $type.Key}}Prop(name)
	{{end}}
	}

	return nil, errors.New("Unexpected property type: " + propType.String())
}

{{if .OutputReadSetter -}}

func ({{.FirstLetter}} *{{.ReaderName}}) PropMutable(name string) bool {
	switch name {
		{{range $key, $val := .Fields -}}
	case "{{$key}}":
		return {{$val.Mutable}}
		{{end -}}
	}

	return false
}

func ({{.FirstLetter}} *{{.ReaderName}}) SetProp(name string, value interface{}) error {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return errors.New("No such property with that name: " + name)
	}

	switch propType {
	{{range $type := .PropertyTypes -}}
	{{if $type.IsInterface -}}
	case boardgame.Type{{$type.Key}}:
		return errors.New("SetProp does not allow setting mutable types; use ConfigureProp instead")
	{{- else -}}
	case boardgame.Type{{$type.Key}}:
		val, ok := value.({{$type.ImmutableGoType}})
		if !ok {
			return errors.New("Provided value was not of type {{$type.ImmutableGoType}}")
		}
		return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
	{{- end}}
	{{end}}
	}

	return errors.New("Unexpected property type: " + propType.String())
}

{{end}}

{{if .OutputReadSetConfigurer -}}
func ({{.FirstLetter}} *{{.ReaderName}}) ConfigureProp(name string, value interface{}) error {
	props := {{.FirstLetter}}.Props()
	propType, ok := props[name]

	if !ok {
		return errors.New("No such property with that name: " + name)
	}

	switch propType {
	{{range $type := .PropertyTypes -}}
	case boardgame.Type{{$type.Key}}:
		{{if $type.IsInterface -}}
		if {{$firstLetter}}.PropMutable(name) {
			//Mutable variant
			val, ok := value.({{$type.MutableGoType}})
			if !ok {
				return errors.New("Provided value was not of type {{$type.MutableGoType}}")
			}
			return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
		}
		//Immutable variant
		val, ok := value.({{$type.ImmutableGoType}})
		if !ok {
			return errors.New("Provided value was not of type {{$type.ImmutableGoType}}")
		}
		return {{$firstLetter}}.{{verbfortype $type}}{{withimmutable $type.Key}}Prop(name, val)
		{{- else -}}
			val, ok := value.({{$type.ImmutableGoType}})
			if !ok {
				return errors.New("Provided value was not of type {{$type.ImmutableGoType}}")
			}
			return {{$firstLetter}}.{{verbfortype $type}}{{$type.Key}}Prop(name, val)
		{{- end}}
	{{end}}
	}

	return errors.New("Unexpected property type: " + propType.String())
}

{{end}}
`

const typedPropertyTemplateText = `func ({{.FirstLetter}} *{{.ReaderName}}) {{withimmutable .PropType.Key}}Prop(name string) ({{.PropType.ImmutableGoType}}, error) {
	{{$firstLetter := .FirstLetter}}
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
				return {{$firstLetter}}.data.{{.Name}}, nil
		{{end}}
	}
	{{end}}

	return {{.PropType.ZeroValue}}, errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{if .OutputReadSetConfigurer -}}
{{if .PropType.IsInterface -}}
func ({{.FirstLetter}} *{{.ReaderName}}) Configure{{.PropType.Key}}Prop(name string, value {{.PropType.MutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				{{if .UpConverter -}}
				slotValue := value.{{.UpConverter}}()
				if slotValue == nil {
					return errors.New("{{.Name}} couldn't be upconverted, returned nil")
				}
				{{$firstLetter}}.data.{{.Name}} = slotValue
				{{- else -}}
				{{$firstLetter}}.data.{{.Name}} = value
				{{- end}}
				return nil
			{{- else -}}
				return boardgame.ErrPropertyImmutable
			{{- end}}
		{{end}}
	}
	{{end}}

	return errors.New("No such {{.PropType.Key}} prop: " + name)

}

func ({{.FirstLetter}} *{{.ReaderName}}) Configure{{withimmutable .PropType.Key}}Prop(name string, value {{.PropType.ImmutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				return boardgame.ErrPropertyImmutable
			{{- else -}}
				{{if .UpConverter -}}
				slotValue := value.{{.UpConverter}}()
				if slotValue == nil {
					return errors.New("{{.Name}} couldn't be upconverted, returned nil")
				}
				{{$firstLetter}}.data.{{.Name}} = slotValue
				{{- else -}}
				{{$firstLetter}}.data.{{.Name}} = value
				{{- end}}
				return nil
			{{- end}}
		{{end}}
	}
	{{end}}

	return errors.New("No such {{withimmutable .PropType.Key}} prop: " + name)

}

{{end}}
{{end}}

{{if .OutputReadSetter -}}
{{if .PropType.IsInterface -}}
func ({{.FirstLetter}} *{{.ReaderName}}) {{.PropType.Key}}Prop(name string) ({{.PropType.MutableGoType}}, error) {
	{{$firstLetter := .FirstLetter}}
	{{$zeroValue := .PropType.ZeroValue}}
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
			{{if .Mutable -}}
				return {{$firstLetter}}.data.{{.Name}}, nil
			{{- else -}}
				return {{$zeroValue}}, boardgame.ErrPropertyImmutable
			{{- end}}
		{{end}}
	}
	{{end}}

	return {{.PropType.ZeroValue}}, errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{else}}
func ({{.FirstLetter}} *{{.ReaderName}}) Set{{.PropType.Key}}Prop(name string, value {{.PropType.MutableGoType}}) error {
	{{if .NamesForType}}
	switch name {
		{{range .NamesForType -}}
			case "{{.Name}}":
				{{$firstLetter}}.data.{{.Name}} = value
				return nil
		{{end}}
	}
	{{end}}

	return errors.New("No such {{.PropType.Key}} prop: " + name)

}

{{end}}
{{end}}
`

const readerTemplateText = `//Reader returns an autp-generated boardgame.PropertyReader for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) Reader() boardgame.PropertyReader {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`

const readSetterTemplateText = `//ReadSetter returns an autp-generated boardgame.PropertyReadSetter for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) ReadSetter() boardgame.PropertyReadSetter {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`

const readSetConfigurerTemplateText = `//ReadSetConfigurer returns an autp-generated boardgame.PropertyReadSetConfigurer for {{.StructName}}
func ({{.FirstLetter}} *{{.StructName}}) ReadSetConfigurer() boardgame.PropertyReadSetConfigurer {
	return &{{.ReaderName}}{ {{.FirstLetter}} }
}

`
const enumHeaderTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help configure enums.
 * It was generated by the codegen package via 'boardgame-util codegen'.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/

package {{.packageName}}

import (
	"github.com/jkomoros/boardgame/enum"
)

var enums = enum.NewSet()

`

const enumDelegateTemplateText = `//ConfigureEnums simply returns enums, the auto-generated Enums variable. This
//is output because {{.delegateName}} appears to be a struct that implements
//boardgame.GameDelegate, and does not already have a ConfigureEnums
//explicitly defined.
func ({{firstLetter .delegateName}} *{{.delegateName}}) ConfigureEnums() *enum.Set {
	return enums
}

`

const enumItemTemplateText = `{{if .firstNewKey}}
//Implicitly created constants for {{.prefix}}
const (
	{{.firstNewKey}} = iota - 9223372036854775808
{{range .restNewKeys -}}
	{{.}}
{{- end -}}
)

{{ end -}}
//{{.prefix}}Enum is the enum.Enum for {{.prefix}}
var {{.prefix}}Enum = enums.MustAdd{{if .parents}}Tree{{end}}("{{.prefix}}", map[int]string{
	{{ $prefix := .prefix -}}
	{{range $name, $value := .values -}}
	{{$name}}: "{{$value}}",
	{{end}}
{{if .parents -}} }, map[int]int{
	{{ $prefix := .prefix -}}
	{{range $name, $value := .parents -}}
	{{$name}}: {{$value}},
	{{end}}
{{end -}}
})

`
<|endoftext|>


<commit_before>package worker

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	"github.com/stitchfix/flotilla-os/config"
	"github.com/stitchfix/flotilla-os/execution/engine"
	flotillaLog "github.com/stitchfix/flotilla-os/log"
	"github.com/stitchfix/flotilla-os/state"
	"gopkg.in/tomb.v2"
)

type statusWorker struct {
	sm           state.Manager
	ee           engine.Engine
	conf         config.Config
	log          flotillaLog.Logger
	pollInterval time.Duration
	t            tomb.Tomb
	engine       *string
}

func (sw *statusWorker) Initialize(conf config.Config, sm state.Manager, ee engine.Engine, log flotillaLog.Logger, pollInterval time.Duration, engine *string) error {
	sw.pollInterval = pollInterval
	sw.conf = conf
	sw.sm = sm
	sw.ee = ee
	sw.log = log
	sw.engine = engine
	sw.log.Log("message", "initialized a status worker", "engine", *engine)
	return nil
}

func (sw *statusWorker) GetTomb() *tomb.Tomb {
	return &sw.t
}

//
// Run updates status of tasks
//
func (sw *statusWorker) Run() error {
	for {
		select {
		case <-sw.t.Dying():
			sw.log.Log("message", "A status worker was terminated")
			return nil
		default:
			if *sw.engine == state.ECSEngine {
				sw.runOnceECS()
				time.Sleep(sw.pollInterval)
			}

			if *sw.engine == state.EKSEngine {
				sw.runOnceEKS()
				time.Sleep(time.Second * 15)
			}
		}
	}
}

func (sw *statusWorker) runOnceEKS() {
	rl, err := sw.sm.ListRuns(1000, 0, "status", "asc", map[string][]string{
		"queued_at_since": {
			time.Now().AddDate(0, 0, -1).Format(time.RFC3339),
		},
		"status": {state.StatusNeedsRetry, state.StatusRunning, state.StatusQueued, state.StatusPending},
	}, nil, []string{state.EKSEngine})

	if err != nil {
		sw.log.Log("message", "unable to receive runs", "error", fmt.Sprintf("%+v", err))
		return
	}

	for _, run := range rl.Runs {
		updatedRun, err := sw.ee.FetchUpdateStatus(run)
		if err != nil {
			sw.log.Log("message", "unable to receive runs", "error", fmt.Sprintf("%+v", err))
		} else {
			sw.log.Log("message", "updating run", "run", run.RunID)
			_, err = sw.sm.UpdateRun(updatedRun.RunID, updatedRun)
			if err != nil {
				sw.log.Log("message", "unable to save runs", "error", fmt.Sprintf("%+v", err))
			}
		}
	}
}

func (sw *statusWorker) runOnceECS() {
	runReceipt, err := sw.ee.PollStatus()
	if err != nil {
		sw.log.Log("message", "unable to receive status message", "error", fmt.Sprintf("%+v", err))
		return
	}

	// Ensure update is in the env required, otherwise, ack without taking action
	update := runReceipt.Run
	if update != nil {
		//
		// Relies on the reserved env var, FLOTILLA_SERVER_MODE to ensure update
		// belongs to -this- mode of Flotilla
		//
		var serverMode string
		if update.Env != nil {
			for _, kv := range *update.Env {
				if kv.Name == "FLOTILLA_SERVER_MODE" {
					serverMode = kv.Value
				}
			}
		}

		shouldProcess := len(serverMode) > 0 && serverMode == sw.conf.GetString("flotilla_mode")
		if shouldProcess {
			run, err := sw.findRun(update.TaskArn)
			if err != nil {
				sw.log.Log("message", "unable to find run to apply update to", "error", fmt.Sprintf("%+v", err))
				return
			}

			_, err = sw.sm.UpdateRun(run.RunID, *update)
			if err != nil {
				sw.log.Log("message", "error applying status update", "run", run.RunID, "error", fmt.Sprintf("%+v", err))
				return
			}

			// emit status update event
			sw.logStatusUpdate(*update)
		}

		sw.log.Log("message", "Acking status update", "arn", update.TaskArn)
		if err = runReceipt.Done(); err != nil {
			sw.log.Log("message", "Acking status update failed", "arn", update.TaskArn, "error", fmt.Sprintf("%+v", err))
		}
	}
}

func (sw *statusWorker) logStatusUpdate(update state.Run) {
	var err error
	var startedAt, finishedAt time.Time
	var env state.EnvList

	if update.StartedAt != nil {
		startedAt = *update.StartedAt
	}

	if update.FinishedAt != nil {
		finishedAt = *update.FinishedAt
	}

	if update.Env != nil {
		env = *update.Env
	}

	if update.ExitCode != nil {
		err = sw.log.Event("eventClassName", "FlotillaTaskStatus",
			"run_id", update.RunID,
			"task_arn", update.TaskArn,
			"definition_id", update.DefinitionID,
			"alias", update.Alias,
			"image", update.Image,
			"cluster_name", update.ClusterName,
			"exit_code", *update.ExitCode,
			"status", update.Status,
			"started_at", startedAt,
			"finished_at", finishedAt,
			"instance_id", update.InstanceID,
			"instance_dns_name", update.InstanceDNSName,
			"group_name", update.GroupName,
			"user", update.User,
			"task_type", update.TaskType,
			"env", env)
	} else {
		err = sw.log.Event("eventClassName", "FlotillaTaskStatus",
			"run_id", update.RunID,
			"task_arn", update.TaskArn,
			"definition_id", update.DefinitionID,
			"alias", update.Alias,
			"image", update.Image,
			"cluster_name", update.ClusterName,
			"status", update.Status,
			"started_at", startedAt,
			"finished_at", finishedAt,
			"instance_id", update.InstanceID,
			"instance_dns_name", update.InstanceDNSName,
			"group_name", update.GroupName,
			"user", update.User,
			"task_type", update.TaskType,
			"env", env)
	}

	if err != nil {
		sw.log.Log("message", "Failed to emit status event", "run_id", update.RunID, "error", err.Error())
	}
}

func (sw *statusWorker) findRun(taskArn string) (state.Run, error) {
	var engines []string
	if sw.engine != nil {
		engines = []string{*sw.engine}
	} else {
		engines = nil
	}

	runs, err := sw.sm.ListRuns(1, 0, "started_at", "asc", map[string][]string{
		"task_arn": {taskArn},
	}, nil, engines)
	if err != nil {
		return state.Run{}, errors.Wrapf(err, "problem finding run by task arn [%s]", taskArn)
	}
	if runs.Total > 0 && len(runs.Runs) > 0 {
		return runs.Runs[0], nil
	}
	return state.Run{}, errors.Errorf("no run found for [%s]", taskArn)
}
<commit_msg>Update status_worker - only update when state change (#166)<commit_after>package worker

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	"github.com/stitchfix/flotilla-os/config"
	"github.com/stitchfix/flotilla-os/execution/engine"
	flotillaLog "github.com/stitchfix/flotilla-os/log"
	"github.com/stitchfix/flotilla-os/state"
	"gopkg.in/tomb.v2"
)

type statusWorker struct {
	sm           state.Manager
	ee           engine.Engine
	conf         config.Config
	log          flotillaLog.Logger
	pollInterval time.Duration
	t            tomb.Tomb
	engine       *string
}

func (sw *statusWorker) Initialize(conf config.Config, sm state.Manager, ee engine.Engine, log flotillaLog.Logger, pollInterval time.Duration, engine *string) error {
	sw.pollInterval = pollInterval
	sw.conf = conf
	sw.sm = sm
	sw.ee = ee
	sw.log = log
	sw.engine = engine
	sw.log.Log("message", "initialized a status worker", "engine", *engine)
	return nil
}

func (sw *statusWorker) GetTomb() *tomb.Tomb {
	return &sw.t
}

//
// Run updates status of tasks
//
func (sw *statusWorker) Run() error {
	for {
		select {
		case <-sw.t.Dying():
			sw.log.Log("message", "A status worker was terminated")
			return nil
		default:
			if *sw.engine == state.ECSEngine {
				sw.runOnceECS()
				time.Sleep(sw.pollInterval)
			}

			if *sw.engine == state.EKSEngine {
				sw.runOnceEKS()
				time.Sleep(time.Second * 30)
			}
		}
	}
}

func (sw *statusWorker) runOnceEKS() {
	rl, err := sw.sm.ListRuns(1000, 0, "status", "asc", map[string][]string{
		"queued_at_since": {
			time.Now().AddDate(0, 0, -1).Format(time.RFC3339),
		},
		"status": {state.StatusNeedsRetry, state.StatusRunning, state.StatusQueued, state.StatusPending},
	}, nil, []string{state.EKSEngine})

	if err != nil {
		_ = sw.log.Log("message", "unable to receive runs", "error", fmt.Sprintf("%+v", err))
		return
	}

	for _, run := range rl.Runs {
		updatedRun, err := sw.ee.FetchUpdateStatus(run)
		if err != nil {
			_ = sw.log.Log("message", "unable to receive eks runs", "error", fmt.Sprintf("%+v", err))
		} else {
			if run.Status != updatedRun.Status {
				_ = sw.log.Log("message", "updating eks run", "run", updatedRun.RunID, "status", updatedRun.Status)
				_, err = sw.sm.UpdateRun(updatedRun.RunID, updatedRun)
				if err != nil {
					_ = sw.log.Log("message", "unable to save eks runs", "error", fmt.Sprintf("%+v", err))
				}
			}
		}
	}
}

func (sw *statusWorker) runOnceECS() {
	runReceipt, err := sw.ee.PollStatus()
	if err != nil {
		sw.log.Log("message", "unable to receive status message", "error", fmt.Sprintf("%+v", err))
		return
	}

	// Ensure update is in the env required, otherwise, ack without taking action
	update := runReceipt.Run
	if update != nil {
		//
		// Relies on the reserved env var, FLOTILLA_SERVER_MODE to ensure update
		// belongs to -this- mode of Flotilla
		//
		var serverMode string
		if update.Env != nil {
			for _, kv := range *update.Env {
				if kv.Name == "FLOTILLA_SERVER_MODE" {
					serverMode = kv.Value
				}
			}
		}

		shouldProcess := len(serverMode) > 0 && serverMode == sw.conf.GetString("flotilla_mode")
		if shouldProcess {
			run, err := sw.findRun(update.TaskArn)
			if err != nil {
				sw.log.Log("message", "unable to find run to apply update to", "error", fmt.Sprintf("%+v", err))
				return
			}

			_, err = sw.sm.UpdateRun(run.RunID, *update)
			if err != nil {
				sw.log.Log("message", "error applying status update", "run", run.RunID, "error", fmt.Sprintf("%+v", err))
				return
			}

			// emit status update event
			sw.logStatusUpdate(*update)
		}

		sw.log.Log("message", "Acking status update", "arn", update.TaskArn)
		if err = runReceipt.Done(); err != nil {
			sw.log.Log("message", "Acking status update failed", "arn", update.TaskArn, "error", fmt.Sprintf("%+v", err))
		}
	}
}

func (sw *statusWorker) logStatusUpdate(update state.Run) {
	var err error
	var startedAt, finishedAt time.Time
	var env state.EnvList

	if update.StartedAt != nil {
		startedAt = *update.StartedAt
	}

	if update.FinishedAt != nil {
		finishedAt = *update.FinishedAt
	}

	if update.Env != nil {
		env = *update.Env
	}

	if update.ExitCode != nil {
		err = sw.log.Event("eventClassName", "FlotillaTaskStatus",
			"run_id", update.RunID,
			"task_arn", update.TaskArn,
			"definition_id", update.DefinitionID,
			"alias", update.Alias,
			"image", update.Image,
			"cluster_name", update.ClusterName,
			"exit_code", *update.ExitCode,
			"status", update.Status,
			"started_at", startedAt,
			"finished_at", finishedAt,
			"instance_id", update.InstanceID,
			"instance_dns_name", update.InstanceDNSName,
			"group_name", update.GroupName,
			"user", update.User,
			"task_type", update.TaskType,
			"env", env)
	} else {
		err = sw.log.Event("eventClassName", "FlotillaTaskStatus",
			"run_id", update.RunID,
			"task_arn", update.TaskArn,
			"definition_id", update.DefinitionID,
			"alias", update.Alias,
			"image", update.Image,
			"cluster_name", update.ClusterName,
			"status", update.Status,
			"started_at", startedAt,
			"finished_at", finishedAt,
			"instance_id", update.InstanceID,
			"instance_dns_name", update.InstanceDNSName,
			"group_name", update.GroupName,
			"user", update.User,
			"task_type", update.TaskType,
			"env", env)
	}

	if err != nil {
		sw.log.Log("message", "Failed to emit status event", "run_id", update.RunID, "error", err.Error())
	}
}

func (sw *statusWorker) findRun(taskArn string) (state.Run, error) {
	var engines []string
	if sw.engine != nil {
		engines = []string{*sw.engine}
	} else {
		engines = nil
	}

	runs, err := sw.sm.ListRuns(1, 0, "started_at", "asc", map[string][]string{
		"task_arn": {taskArn},
	}, nil, engines)
	if err != nil {
		return state.Run{}, errors.Wrapf(err, "problem finding run by task arn [%s]", taskArn)
	}
	if runs.Total > 0 && len(runs.Runs) > 0 {
		return runs.Runs[0], nil
	}
	return state.Run{}, errors.Errorf("no run found for [%s]", taskArn)
}
<|endoftext|>


<commit_before>package workers

import (
	"encoding/json"
	"log"

	"github.com/NaySoftware/go-fcm"
	nsq "github.com/bitly/go-nsq"
	"github.com/boltdb/bolt"
)

var (
	pub         *nsq.Producer
	useNSQ      = false
	useFirebase = false
	nsqPort     string
	nsqHost     string
)

// A buffered channel that we can send work requests on.
var WorkQueue = make(chan WorkRequest, 100)

func AddJob(message WorkRequest) {
	//Add message to the work queue
	WorkQueue <- message
}

func SetQueueType(queue string) {
	if queue == "nsq" {
		useNSQ = true
	} else if queue == "firebase" {
		useFirebase = true
	} else if queue == "both" {
		useNSQ = true
		useFirebase = true
	}
}

func SetupNSQ(host, port string) {
	nsqHost = host
	nsqPort = port
	config := nsq.NewConfig()
	pub, _ = nsq.NewProducer(host+":"+port, config)
}

type Topic struct {
	TopicString string `json:"topic,omitempty"`
}

type WorkRequest struct {
	//Sensor `json:"sensor"`
	Token string          `json:"token"`
	Data  *json.RawMessage `json:"data"`
}

type Payload struct {
	Device *string          `json:"device"`
	Name   *string          `json:"name"`
	Data   *json.RawMessage `json:"payload"`
}

func (work *WorkRequest) PublishToFirebase() error {
	log.Println("Received firebase publish request")
	if work.verifyAPIKey() {
		log.Println("Publishing to Firebase")
		fcmClient := fcm.NewFcmClient(key)
		//log.Println("Data: ", string(work.Data))
		//Use a buffer to concat strings, it's much faster
		//buffer := bytes.NewBuffer(make([]byte, 0, 32))
		//buffer.WriteString("/topics/")
		//buffer.WriteString(work.Token)
		//topic := buffer.String()

		//payload := work.transformToPayload()
		data, err := json.Marshal(work.Data)
		log.Println("API_KEY: ", key)
		//log.Println("Topic: ", topic)
		log.Println("Payload: ", string(data))

		fcmClient.NewFcmMsgTo(work.Token, work.Data)
		fcmClient.SetTimeToLive(0)
		status, err := fcmClient.Send()
		if err != nil {
			status.PrintResults()
			log.Println(err)
			//status.PrintResults()
		}
		return err
	}
	return nil
}

func (work *WorkRequest) PublishToNSQ() error {
	if useNSQ {
		//err := pub.Publish(work.Topic.TopicString, []byte(work.Data))
		//return err
	}
	return nil
}

func (work *WorkRequest) transformToPayload() *Payload {
	//payload := Payload{Device: &work.Sensor.Device, Name: &work.Sensor.Name, Data: &work.Data}
	//return &payload
	return nil
}

func (work *WorkRequest) verifyAPIKey() bool {
	valid := false
	boltDB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(apiBucket))
		data := b.Get([]byte(work.Token))
		if string(data) == "valid" {
			log.Println("Valid API Key Accepted")
			valid = true
		}
		return nil
	})
	return valid
}
<commit_msg>Firebase testing<commit_after>package workers

import (
	"bytes"
	"encoding/json"
	"log"

	"github.com/NaySoftware/go-fcm"
	nsq "github.com/bitly/go-nsq"
	"github.com/boltdb/bolt"
)

var (
	pub         *nsq.Producer
	useNSQ      = false
	useFirebase = false
	nsqPort     string
	nsqHost     string
)

// A buffered channel that we can send work requests on.
var WorkQueue = make(chan WorkRequest, 100)

func AddJob(message WorkRequest) {
	//Add message to the work queue
	WorkQueue <- message
}

func SetQueueType(queue string) {
	if queue == "nsq" {
		useNSQ = true
	} else if queue == "firebase" {
		useFirebase = true
	} else if queue == "both" {
		useNSQ = true
		useFirebase = true
	}
}

func SetupNSQ(host, port string) {
	nsqHost = host
	nsqPort = port
	config := nsq.NewConfig()
	pub, _ = nsq.NewProducer(host+":"+port, config)
}

type Topic struct {
	TopicString string `json:"topic,omitempty"`
}

type WorkRequest struct {
	//Sensor `json:"sensor"`
	Token string          `json:"token"`
	Data  *json.RawMessage `json:"data"`
}

type Payload struct {
	Device *string          `json:"device"`
	Name   *string          `json:"name"`
	Data   *json.RawMessage `json:"payload"`
}

func (work *WorkRequest) PublishToFirebase() error {
	log.Println("Received firebase publish request")
	if work.verifyAPIKey() {
		log.Println("Publishing to Firebase")
		fcmClient := fcm.NewFcmClient(key)
		log.Println("Data: ", string(work.Data))
		//Use a buffer to concat strings, it's much faster
		buffer := bytes.NewBuffer(make([]byte, 0, 32))
		buffer.WriteString("/topics/")
		buffer.WriteString(work.Token)
		topic := buffer.String()

		//payload := work.transformToPayload()
		data, err := json.Marshal(work.Data)
		log.Println("API_KEY: ", key)
		//log.Println("Topic: ", topic)
		log.Println("Payload: ", string(data))

		fcmClient.NewFcmMsgTo(topic, string(data))
		fcmClient.SetTimeToLive(0)
		status, err := fcmClient.Send()
		if err != nil {
			status.PrintResults()
			log.Println(err)
			//status.PrintResults()
		}
		return err
	}
	return nil
}

func (work *WorkRequest) PublishToNSQ() error {
	if useNSQ {
		//err := pub.Publish(work.Topic.TopicString, []byte(work.Data))
		//return err
	}
	return nil
}

func (work *WorkRequest) transformToPayload() *Payload {
	//payload := Payload{Device: &work.Sensor.Device, Name: &work.Sensor.Name, Data: &work.Data}
	//return &payload
	return nil
}

func (work *WorkRequest) verifyAPIKey() bool {
	valid := false
	boltDB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(apiBucket))
		data := b.Get([]byte(work.Token))
		if string(data) == "valid" {
			log.Println("Valid API Key Accepted")
			valid = true
		}
		return nil
	})
	return valid
}
<|endoftext|>


<commit_before>package types

import (
	"fmt"
)

// Coordinates code for coordinates used throughout the API
//
// This is the Go representation of "Coord". It implements Place.
//
// See http://doc.navitia.io/#standard-objects
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// PlaceID formats & escapes the coordinates for use in queries as an ID
//
// Helps satisfy Place.
func (coords Coordinates) PlaceID() string {
	return fmt.Sprintf("%3.3f;%3.3f", coords.Longitude, coords.Latitude)
}

// PlaceName returns a name for this coordinate.
//
// Helps satisfy Place.
func (coords Coordinates) PlaceName() string {
	return coords.PlaceID()
}

// PlaceType returns "coord".
//
// Helps satisfy Place.
func (coords Coordinates) PlaceType() string {
	return "coord"
}

// String pretty-prints a Coordinates and satisfies the Stringer interface
func (coords Coordinates) String() string {
	return fmt.Sprintf("Longitude %3.3f ; Latitude %3.3f", coords.Longitude, coords.Latitude)
}
<commit_msg>Stylistic changes to Coordinates' methods<commit_after>package types

import (
	"fmt"
)

// Coordinates code for coordinates used throughout the API
//
// This is the Go representation of "Coord". It implements Place.
//
// See http://doc.navitia.io/#standard-objects
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// PlaceID formats & escapes the coordinates for use in queries as an ID
//
// Helps satisfy Place.
func (c Coordinates) PlaceID() string {
	return fmt.Sprintf("%3.3f;%3.3f", c.Longitude, c.Latitude)
}

// PlaceName returns a name for this coordinate.
//
// Helps satisfy Place.
func (c Coordinates) PlaceName() string {
	return c.PlaceID()
}

// PlaceType returns "coord".
//
// Helps satisfy Place.
func (c Coordinates) PlaceType() string {
	return "coord"
}

// String pretty-prints a Coordinates and satisfies the Stringer interface
func (c Coordinates) String() string {
	return fmt.Sprintf("Longitude %3.3f ; Latitude %3.3f", c.Longitude, c.Latitude)
}
<|endoftext|>


<commit_before>package core

import (
	"log"
	"sync"

	"github.com/nikhan/go-fetch"
)

// A Block is the basic processing unit in streamtools. It has inbound and outbound routes.
type Block struct {
	Name     string // for logging
	Inputs   map[string]*Input
	Outputs  map[string]*Output
	QuitChan chan bool
	sync.Mutex
	Kernel func(...Message) (map[string]Message, error) // route -> message to be sent
}

// NewBlock returns a block with no inputs and no outputs.
func NewBlock(name string) *Block {
	return &Block{
		Name:     name,
		Inputs:   make(map[string]*Input),
		Outputs:  make(map[string]*Output),
		QuitChan: make(chan bool),
	}
}

// Add a named input to the block
func (b *Block) AddInput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Inputs[id]
	if ok {
		return false
	}
	b.Inputs[id] = NewInput()
	return true
}

// Remove a named input to the block
func (b *Block) RemoveInput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Inputs[id]
	if !ok {
		return false
	}
	delete(b.Inputs, id)
	return true
}

// GetInput returns the input Connection
func (b *Block) GetInput(id string) *Input {
	b.Lock()
	input, ok := b.Inputs[id]
	b.Unlock()
	if !ok {
		return nil
	}
	return input
}

// AddOutput registers a new output for the block
func (b *Block) AddOutput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Outputs[id]
	if ok {
		return false
	}
	b.Outputs[id] = NewOutput()
	return true
}

// RemoveOutput deletes the output from the block
func (b *Block) RemoveOutput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Outputs[id]
	if !ok {
		return false
	}
	delete(b.Outputs, id)
	return true
}

// Stop is called when removing a block from the streamtools pattern. This is the default, and can be overwritten.
func (b *Block) Stop() {
	b.QuitChan <- true
}

// Broadcast is called when sending a message to an Output. If Broadcast returns false your block must immediately return.
func (b Block) Broadcast(m Message, id string) bool {
	for c, _ := range b.Connections(id) {
		select {
		case c <- m:
		case <-b.QuitChan:
			return false
		}
	}
	return true
}

func (b Block) getName() string {
	return b.Name
}

func (b Block) Merge(β Block) *Block {
	out := NewBlock(b.getName() + "_" + β.getName())
	for id, input := range b.Inputs {
		out.Inputs[id] = input
	}
	for id, output := range β.Outputs {
		out.Outputs[id] = output
	}
	out.Kernel = func(msgs ...Message) (map[string]Message, error) {
		outMsg, err := b.Kernel(msgs)
		if err != nil {
			return nil, err
		}
		inMsg := map[string]Message{
			"in": outMsg["out"],
		}
		return β.Kernel(inMsg)
	}
	return out
}

func (b Block) Recieve() bool {
	var err error
	for _, in := range b.Inputs {
		select {
		case m := <-in.Connection:
			in.Value, err = fetch.Run(in.Path, m)
			if err != nil {
				log.Fatal(err)
			}
		case <-b.QuitChan:
			return false
		}
	}
	return true
}
<commit_msg>tidying<commit_after>package core

import (
	"log"
	"sync"

	"github.com/nikhan/go-fetch"
)

// A Block is the basic processing unit in streamtools. It has inbound and outbound routes.
type Block struct {
	Name     string // for logging
	Inputs   map[string]*Input
	Outputs  map[string]*Output
	QuitChan chan bool
	sync.Mutex
	Kernel func(...Message) (map[string]Message, error) // route -> message to be sent
}

// NewBlock returns a block with no inputs and no outputs.
func NewBlock(name string) *Block {
	return &Block{
		Name:     name,
		Inputs:   make(map[string]*Input),
		Outputs:  make(map[string]*Output),
		QuitChan: make(chan bool),
	}
}

// Add a named input to the block
func (b *Block) AddInput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Inputs[id]
	if ok {
		return false
	}
	b.Inputs[id] = NewInput()
	return true
}

// Remove a named input to the block
func (b *Block) RemoveInput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Inputs[id]
	if !ok {
		return false
	}
	delete(b.Inputs, id)
	return true
}

// GetInput returns the input Connection
func (b *Block) GetInput(id string) *Input {
	b.Lock()
	input, ok := b.Inputs[id]
	b.Unlock()
	if !ok {
		return nil
	}
	return input
}

// AddOutput registers a new output for the block
func (b *Block) AddOutput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Outputs[id]
	if ok {
		return false
	}
	b.Outputs[id] = NewOutput()
	return true
}

// RemoveOutput deletes the output from the block
func (b *Block) RemoveOutput(id string) bool {
	b.Lock()
	defer b.Unlock()
	_, ok := b.Outputs[id]
	if !ok {
		return false
	}
	delete(b.Outputs, id)
	return true
}

// Stop is called when removing a block from the streamtools pattern. This is the default, and can be overwritten.
func (b *Block) Stop() {
	b.QuitChan <- true
}

// Broadcast is called when sending a message to an Output. If Broadcast returns false your block must immediately return.
func (b Block) Broadcast(m Message, id string) bool {
	for c, _ := range b.Connections(id) {
		select {
		case c <- m:
		case <-b.QuitChan:
			return false
		}
	}
	return true
}

func (b Block) getName() string {
	return b.Name
}

func (b Block) Merge(β Block) *Block {
	out := NewBlock(b.getName() + "_" + β.getName())
	for id, input := range b.Inputs {
		out.Inputs[id] = input
	}
	for id, output := range β.Outputs {
		out.Outputs[id] = output
	}
	out.Kernel = func(msgs ...Message) (map[string]Message, error) {
		outMsg, err := b.Kernel(msgs)
		if err != nil {
			return nil, err
		}
		inMsg := map[string]Message{
			"in": outMsg["out"],
		}
		return β.Kernel(inMsg)
	}
	return out
}

func (b Block) Receive() bool {
	var err error
	for _, in := range b.Inputs {
		select {
		case m := <-in.Connection:
			in.Value, err = fetch.Run(in.Path, m)
			if err != nil {
				log.Fatal(err)
			}
		case <-b.QuitChan:
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	`encoding/json`
	`log`
	`net`
	`os/exec`
)

type Item struct {
	Type string
}

type Message struct {
	Method string
	Params struct {
		Data struct {
			Item *Item
		}
	}
}

func main() {
	conn, err := net.Dial(`tcp`, `127.0.0.1:9090`)
	if err != nil {
		log.Println(`Couldn't connect to XBMC`)
		return
	}
	dec := json.NewDecoder(conn)

	for {
		m := &Message{}

		if err := dec.Decode(&m); err != nil {
			log.Println(err)
		}

		switch m.Method {
		case `Player.OnPlay`:
			onPlay(m.Params.Data.Item.Type)
		case `Player.OnPause`:
			onPause()
		case `Player.OnStop`:
			onStop()
		case `GUI.OnScreensaverActivated`:
			onScreensaverActivated()
		case `GUI.OnScreensaverDeactivated`:
			onScreensaverDeactivated()
		}
	}
}

func onPlay(t string) {
	switch t {
	case `music`:
		if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--gamma`, `0.8 0.8 0.8`, `--value`, `2.0`, `--saturation`, `2.0`).Output(); err != nil {
			log.Println(err)
		}
	default:
		defaultGamma()
	}

	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--clear`).Output(); err != nil {
		log.Println(err)
	}
}

func onPause() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Red value mood blobs`).Output(); err != nil {
		log.Println(err)
	}
}

func onStop() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Rainbow swirl`).Output(); err != nil {
		log.Println(err)
	}
}

func onScreensaverActivated() {
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--color`, `000000`).Output(); err != nil {
		log.Println(err)
	}
}

func onScreensaverDeactivated() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Rainbow swirl`).Output(); err != nil {
		log.Println(err)
	}
}

func defaultGamma() {
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--gamma`, `2.2 2.2 2.8`, `--value`, `1.0`, `--saturation`, `1.0`).Output(); err != nil {
		log.Println(err)
	}
}
<commit_msg>Bail on XBMC read error<commit_after>package main

import (
	`encoding/json`
	`log`
	`net`
	`os/exec`
)

type Item struct {
	Type string
}

type Message struct {
	Method string
	Params struct {
		Data struct {
			Item *Item
		}
	}
}

func main() {
	conn, err := net.Dial(`tcp`, `127.0.0.1:9090`)
	if err != nil {
		log.Println(`Couldn't connect to XBMC`)
		return
	}
	dec := json.NewDecoder(conn)

	for {
		m := &Message{}

		if err := dec.Decode(&m); err != nil {
			log.Println(err)
			return
		}

		switch m.Method {
		case `Player.OnPlay`:
			onPlay(m.Params.Data.Item.Type)
		case `Player.OnPause`:
			onPause()
		case `Player.OnStop`:
			onStop()
		case `GUI.OnScreensaverActivated`:
			onScreensaverActivated()
		case `GUI.OnScreensaverDeactivated`:
			onScreensaverDeactivated()
		}
	}
}

func onPlay(t string) {
	switch t {
	case `music`:
		if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--gamma`, `0.8 0.8 0.8`, `--value`, `2.0`, `--saturation`, `2.0`).Output(); err != nil {
			log.Println(err)
		}
	default:
		defaultGamma()
	}

	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--clear`).Output(); err != nil {
		log.Println(err)
	}
}

func onPause() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Red value mood blobs`).Output(); err != nil {
		log.Println(err)
	}
}

func onStop() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Rainbow swirl`).Output(); err != nil {
		log.Println(err)
	}
}

func onScreensaverActivated() {
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--color`, `000000`).Output(); err != nil {
		log.Println(err)
	}
}

func onScreensaverDeactivated() {
	defaultGamma()
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--priority`, `86`, `--effect`, `Rainbow swirl`).Output(); err != nil {
		log.Println(err)
	}
}

func defaultGamma() {
	if _, err := exec.Command(`/usr/local/bin/hyperion-remote`, `--gamma`, `2.2 2.2 2.8`, `--value`, `1.0`, `--saturation`, `1.0`).Output(); err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package configv3

import "strconv"

const (
	DefaultColorEnabled = "true"
	// ColorDisabled means that no colors/bolding will be displayed
	ColorDisabled ColorSetting = iota
	// ColorEnabled means colors/bolding will be displayed
	ColorEnabled
	// ColorAuto means that the UI should decide if colors/bolding will be
	// enabled
	ColorAuto
)

// ColorSetting is a trinary operator that represents if the display should
// have colors enabled, disabled, or automatically detected.
type ColorSetting int

// ColorEnabled returns the color setting based off:
//   1. The $CF_COLOR environment variable if set (0/1/t/f/true/false)
//   2. The 'ColorEnabled' value in the .cf/config.json if set
//   3. Defaults to ColorEnabled if nothing is set
func (config *Config) ColorEnabled() ColorSetting {
	if config.ENV.CFColor != "" {
		val, err := strconv.ParseBool(config.ENV.CFColor)
		if err == nil {
			return config.boolToColorSetting(val)
		}
	}

	val, err := strconv.ParseBool(config.ConfigFile.ColorEnabled)
	if err != nil {
		return ColorEnabled
	}
	return config.boolToColorSetting(val)
}

func (config *Config) boolToColorSetting(val bool) ColorSetting {
	if val {
		return ColorEnabled
	}

	return ColorDisabled
}
<commit_msg>change default to empty<commit_after>package configv3

import "strconv"

const (
	DefaultColorEnabled = ""
	// ColorDisabled means that no colors/bolding will be displayed
	ColorDisabled ColorSetting = iota
	// ColorEnabled means colors/bolding will be displayed
	ColorEnabled
	// ColorAuto means that the UI should decide if colors/bolding will be
	// enabled
	ColorAuto
)

// ColorSetting is a trinary operator that represents if the display should
// have colors enabled, disabled, or automatically detected.
type ColorSetting int

// ColorEnabled returns the color setting based off:
//   1. The $CF_COLOR environment variable if set (0/1/t/f/true/false)
//   2. The 'ColorEnabled' value in the .cf/config.json if set
//   3. Defaults to ColorEnabled if nothing is set
func (config *Config) ColorEnabled() ColorSetting {
	if config.ENV.CFColor != "" {
		val, err := strconv.ParseBool(config.ENV.CFColor)
		if err == nil {
			return config.boolToColorSetting(val)
		}
	}

	val, err := strconv.ParseBool(config.ConfigFile.ColorEnabled)
	if err != nil {
		return ColorEnabled
	}
	return config.boolToColorSetting(val)
}

func (config *Config) boolToColorSetting(val bool) ColorSetting {
	if val {
		return ColorEnabled
	}

	return ColorDisabled
}
<|endoftext|>


<commit_before>package mpb_test

import (
	"bytes"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb"
)

func TestBarSetWidth(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	// overwrite default width 80
	customWidth := 60
	bar := p.AddBar(100).SetWidth(customWidth).
		TrimLeftSpace().TrimRightSpace()
	for i := 0; i < 100; i++ {
		bar.Incr(1)
	}
	p.Stop()

	gotWidth := len(buf.Bytes())
	if gotWidth != customWidth+1 { // +1 for new line
		t.Errorf("Expected width: %d, got: %d\n", customWidth, gotWidth)
	}
}

func TestBarSetInvalidWidth(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	bar := p.AddBar(100).SetWidth(1).
		TrimLeftSpace().TrimRightSpace()
	for i := 0; i < 100; i++ {
		bar.Incr(1)
	}
	p.Stop()

	wantWidth := 80
	gotWidth := len(buf.Bytes())
	if gotWidth != wantWidth+1 { // +1 for new line
		t.Errorf("Expected width: %d, got: %d\n", wantWidth, gotWidth)
	}
}

func TestBarFormat(t *testing.T) {
	var buf bytes.Buffer
	cancel := make(chan struct{})
	p := mpb.New().WithCancel(cancel).SetOut(&buf)
	customFormat := "(#>_)"
	bar := p.AddBar(100).Format(customFormat).
		TrimLeftSpace().TrimRightSpace()

	go func() {
		for i := 0; i < 100; i++ {
			time.Sleep(10 * time.Millisecond)
			bar.Incr(1)
		}
	}()

	time.Sleep(250 * time.Millisecond)
	close(cancel)
	p.Stop()

	// removing new line
	bytes := removeLastRune(buf.Bytes())

	seen := make(map[rune]bool)
	for _, r := range string(bytes) {
		if !seen[r] {
			seen[r] = true
		}
	}
	for _, r := range customFormat {
		if !seen[r] {
			t.Errorf("Rune %#U not found in bar\n", r)
		}
	}
}

func TestBarInvalidFormat(t *testing.T) {
	var buf bytes.Buffer
	customWidth := 60
	p := mpb.New().SetWidth(customWidth).SetOut(&buf)
	customFormat := "(#>=_)"
	bar := p.AddBar(100).Format(customFormat).
		TrimLeftSpace().TrimRightSpace()

	for i := 0; i < 100; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Incr(1)
	}

	p.Stop()

	bytes := removeLastRune(buf.Bytes())
	got := string(bytes[len(bytes)-customWidth:])
	want := "[==========================================================]"
	if got != want {
		t.Errorf("Expected format: %s, got %s\n", want, got)
	}
}

func TestBarInProgress(t *testing.T) {
	var buf bytes.Buffer
	cancel := make(chan struct{})
	p := mpb.New().WithCancel(cancel).SetOut(&buf)
	bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace()

	stopped := make(chan struct{})

	go func() {
		defer close(stopped)
		for bar.InProgress() {
			time.Sleep(10 * time.Millisecond)
			bar.Incr(1)
		}
	}()

	time.Sleep(250 * time.Millisecond)
	close(cancel)
	p.Stop()

	select {
	case <-stopped:
	case <-time.After(300 * time.Millisecond):
		t.Error("bar.InProgress returns true after cancel")
	}
}

func TestGetSpinner(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	bar := p.AddBar(0).TrimLeftSpace().TrimRightSpace()

	for i := 0; i < 100; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Incr(1)
	}

	p.Stop()

	spinnerChars := []byte(`-\|/`)
	seen := make(map[byte]bool)
	for _, b := range buf.Bytes() {
		if !seen[b] {
			seen[b] = true
		}
	}
	for _, b := range spinnerChars {
		if !seen[b] {
			t.Errorf("Char %#U not found in bar's output\n", b)
		}
	}
}

func removeLastRune(bytes []byte) []byte {
	_, size := utf8.DecodeLastRune(bytes)
	return bytes[:len(bytes)-size]
}
<commit_msg>TestBarGetID<commit_after>package mpb_test

import (
	"bytes"
	"sync"
	"testing"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb"
)

func TestBarSetWidth(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	// overwrite default width 80
	customWidth := 60
	bar := p.AddBar(100).SetWidth(customWidth).
		TrimLeftSpace().TrimRightSpace()
	for i := 0; i < 100; i++ {
		bar.Incr(1)
	}
	p.Stop()

	gotWidth := len(buf.Bytes())
	if gotWidth != customWidth+1 { // +1 for new line
		t.Errorf("Expected width: %d, got: %d\n", customWidth, gotWidth)
	}
}

func TestBarSetInvalidWidth(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	bar := p.AddBar(100).SetWidth(1).
		TrimLeftSpace().TrimRightSpace()
	for i := 0; i < 100; i++ {
		bar.Incr(1)
	}
	p.Stop()

	wantWidth := 80
	gotWidth := len(buf.Bytes())
	if gotWidth != wantWidth+1 { // +1 for new line
		t.Errorf("Expected width: %d, got: %d\n", wantWidth, gotWidth)
	}
}

func TestBarFormat(t *testing.T) {
	var buf bytes.Buffer
	cancel := make(chan struct{})
	p := mpb.New().WithCancel(cancel).SetOut(&buf)
	customFormat := "(#>_)"
	bar := p.AddBar(100).Format(customFormat).
		TrimLeftSpace().TrimRightSpace()

	go func() {
		for i := 0; i < 100; i++ {
			time.Sleep(10 * time.Millisecond)
			bar.Incr(1)
		}
	}()

	time.Sleep(250 * time.Millisecond)
	close(cancel)
	p.Stop()

	// removing new line
	bytes := removeLastRune(buf.Bytes())

	seen := make(map[rune]bool)
	for _, r := range string(bytes) {
		if !seen[r] {
			seen[r] = true
		}
	}
	for _, r := range customFormat {
		if !seen[r] {
			t.Errorf("Rune %#U not found in bar\n", r)
		}
	}
}

func TestBarInvalidFormat(t *testing.T) {
	var buf bytes.Buffer
	customWidth := 60
	p := mpb.New().SetWidth(customWidth).SetOut(&buf)
	customFormat := "(#>=_)"
	bar := p.AddBar(100).Format(customFormat).
		TrimLeftSpace().TrimRightSpace()

	for i := 0; i < 100; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Incr(1)
	}

	p.Stop()

	bytes := removeLastRune(buf.Bytes())
	got := string(bytes[len(bytes)-customWidth:])
	want := "[==========================================================]"
	if got != want {
		t.Errorf("Expected format: %s, got %s\n", want, got)
	}
}

func TestBarInProgress(t *testing.T) {
	var buf bytes.Buffer
	cancel := make(chan struct{})
	p := mpb.New().WithCancel(cancel).SetOut(&buf)
	bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace()

	stopped := make(chan struct{})

	go func() {
		defer close(stopped)
		for bar.InProgress() {
			time.Sleep(10 * time.Millisecond)
			bar.Incr(1)
		}
	}()

	time.Sleep(250 * time.Millisecond)
	close(cancel)
	p.Stop()

	select {
	case <-stopped:
	case <-time.After(300 * time.Millisecond):
		t.Error("bar.InProgress returns true after cancel")
	}
}

func TestGetSpinner(t *testing.T) {
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)
	bar := p.AddBar(0).TrimLeftSpace().TrimRightSpace()

	for i := 0; i < 100; i++ {
		time.Sleep(10 * time.Millisecond)
		bar.Incr(1)
	}

	p.Stop()

	spinnerChars := []byte(`-\|/`)
	seen := make(map[byte]bool)
	for _, b := range buf.Bytes() {
		if !seen[b] {
			seen[b] = true
		}
	}
	for _, b := range spinnerChars {
		if !seen[b] {
			t.Errorf("Char %#U not found in bar's output\n", b)
		}
	}
}

func TestBarGetID(t *testing.T) {
	var wg sync.WaitGroup
	var buf bytes.Buffer
	p := mpb.New().SetOut(&buf)

	numBars := 3
	wg.Add(numBars)

	bars := make([]*mpb.Bar, numBars)
	for i := 0; i < numBars; i++ {
		bars[i] = p.AddBarWithID(i, 100)

		go func(bar *mpb.Bar) {
			defer wg.Done()
			for i := 0; i < 100; i++ {
				time.Sleep(10 * time.Millisecond)
				bar.Incr(1)
			}
		}(bars[i])
	}

	for wantID, bar := range bars {
		gotID := bar.GetID()
		if gotID != wantID {
			t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID)
		}
	}

	wg.Wait()
	p.Stop()
}

func removeLastRune(bytes []byte) []byte {
	_, size := utf8.DecodeLastRune(bytes)
	return bytes[:len(bytes)-size]
}
<|endoftext|>