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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	illuminancePath   = "/sys/bus/iio/devices/iio:device0/in_illuminance_raw"
	backlightMaxPath  = "/sys/class/backlight/intel_backlight/max_brightness"
	backlightCurrPath = "/sys/class/backlight/intel_backlight/brightness"
)

func sysfileReadInt(f string) (int, error) {
	file, err := os.Open(f)
	if err != nil {
		return -1, err
	}
	defer file.Close()
	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return -1, err
	}
	text := strings.TrimSpace(string(buf))
	return strconv.Atoi(text)
}

func sysfileWriteInt(name string, n int) error {
	buf := fmt.Sprintf("%d\n", n)
	return ioutil.WriteFile(name, []byte(buf), 0644)
}

type poller struct {
	max, min int
	sens     int
	ratio    int
	dryrun   bool
	debug    bool
	wait     time.Duration
}

func (p *poller) poll() {
	maxIn := p.ratio * 100
	blMin := p.sens * p.max / 100
	for {
		blight, err := sysfileReadInt(backlightCurrPath)
		if err != nil {
			log.Fatal("cannot get backlight value: ", err)
		}
		inlight, err := sysfileReadInt(illuminancePath)
		if err != nil {
			log.Fatal("cannot get ambient light value: ", err)
		}
		inlightPercent := inlight * 100 / maxIn
		if inlightPercent > 100 {
			inlightPercent = 100
		}
		nblight := inlightPercent*p.max/100 + p.min
		if nblight > p.max {
			nblight = p.max
		}
		diff := nblight - blight
		if diff < 0 {
			diff = -diff
		}
		if p.debug {
			log.Printf("light = %d (%d%%), back-light = %d, set %d (diff %d, min-diff %d)", inlight, inlightPercent, blight, nblight, diff, blMin)
		}
		// Set backlight if there is more than the minimum change thresold to adjust. Or if we are below min (level was never set.)
		if diff >= blMin || blight < p.min {
			if !p.dryrun {
				if err := sysfileWriteInt(backlightCurrPath, nblight); err != nil {
					log.Fatal("cannot set backlight: ", err)
				}
			} else {
				log.Printf("change backlight to %d%%; illuminance = %d, backlight = %d (was %d)", inlightPercent, inlight, nblight, blight)
			}
		}
		time.Sleep(p.wait)
	}
}

func main() {
	max, err := sysfileReadInt(backlightMaxPath)
	if err != nil {
		log.Fatal("cannot get backlight max value: ", err)
	}
	p := poller{
		min:    20,  // backlight min N
		max:    max, // backlight max N
		sens:   4,   // sensitivity %
		ratio:  10,  // lux = 1%
		dryrun: false,
		debug:  false,
		wait:   2 * time.Second,
	}
	flag.IntVar(&p.min, "min", p.min, "Minimum value `N` for backlight")
	flag.IntVar(&p.max, "max", p.max, "Maximum value `N` for backlight (autodetected)")
	flag.IntVar(&p.sens, "sensitivity", p.sens, "Minimum amount `S` in percent of backlight change to perform")
	flag.IntVar(&p.ratio, "ratio", p.ratio, "Ratio `R` of light change: number of lux for a 1% change in backlight")
	flag.BoolVar(&p.dryrun, "dryrun", p.dryrun, "Do not set backlight, only print what would happen")
	flag.BoolVar(&p.debug, "debug", p.debug, "Print values read from sensors every wait duration")
	flag.DurationVar(&p.wait, "wait", p.wait, "Duration `T` between checks for changed light conditions")
	flag.Parse()
	p.poll()
}
<commit_msg>Compute average of last N probes for gradual changes<commit_after>// Copyright 2015 Giulio Iotti. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	illuminancePath   = "/sys/bus/iio/devices/iio:device0/in_illuminance_raw"
	backlightMaxPath  = "/sys/class/backlight/intel_backlight/max_brightness"
	backlightCurrPath = "/sys/class/backlight/intel_backlight/brightness"
)

func sysfileReadInt(f string) (int, error) {
	file, err := os.Open(f)
	if err != nil {
		return -1, err
	}
	defer file.Close()
	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return -1, err
	}
	text := strings.TrimSpace(string(buf))
	return strconv.Atoi(text)
}

func sysfileWriteInt(name string, n int) error {
	buf := fmt.Sprintf("%d\n", n)
	return ioutil.WriteFile(name, []byte(buf), 0644)
}

type poller struct {
	max, min int
	sens     int
	ratio    int
	dryrun   bool
	debug    bool
	wait     time.Duration
}

func (p *poller) poll() {
	var (
		inIndex  int
		inlights [8]int
	)
	granularity := 100
	maxIn := p.ratio * granularity
	for {
		blight, err := sysfileReadInt(backlightCurrPath)
		if err != nil {
			log.Fatal("cannot get backlight value: ", err)
		}
		inlight, err := sysfileReadInt(illuminancePath)
		if err != nil {
			log.Fatal("cannot get ambient light value: ", err)
		}
		inlights[inIndex] = inlight
		inIndex = (inIndex + 1) % cap(inlights)
		inlight = 0
		n := 0
		// Average light in the last cap(inlights) probes
		for i := 0; i < cap(inlights); i++ {
			if inlights[i] > 0 {
				inlight += inlights[i]
				n++
			}
		}
		inlight = inlight / n
		inlightPercent := inlight * granularity / maxIn
		if inlightPercent > granularity {
			inlightPercent = granularity
		}
		nblight := inlightPercent*p.max/granularity + p.min
		if nblight > p.max {
			nblight = p.max
		}
		diff := nblight - blight
		if diff < 0 {
			diff = -diff
		}
		if p.debug {
			log.Printf("light = %d (%d%%), back-light = %d, set %d (diff %d, min-diff %d)", inlight, inlightPercent, blight, nblight, diff, p.sens)
		}
		// Set backlight if there is more than the minimum change thresold to adjust. Or if we are below min (level was never set.)
		if diff >= p.sens || blight < p.min {
			if !p.dryrun {
				if err := sysfileWriteInt(backlightCurrPath, nblight); err != nil {
					log.Fatal("cannot set backlight: ", err)
				}
			} else {
				log.Printf("change backlight to %d%%; illuminance = %d, backlight = %d (was %d)", inlightPercent, inlight, nblight, blight)
			}
		}
		time.Sleep(p.wait)
	}
}

func main() {
	max, err := sysfileReadInt(backlightMaxPath)
	if err != nil {
		log.Fatal("cannot get backlight max value: ", err)
	}
	p := poller{
		min:    20,  // backlight min N
		max:    max, // backlight max N
		sens:   12,  // sensitivity %
		ratio:  4,   // lux = 1%
		dryrun: false,
		debug:  false,
		wait:   2 * time.Second,
	}
	flag.IntVar(&p.min, "min", p.min, "Minimum value `N` for backlight")
	flag.IntVar(&p.max, "max", p.max, "Maximum value `N` for backlight (autodetected)")
	flag.IntVar(&p.sens, "sensitivity", p.sens, "Minimum amount `S` in percent of backlight change to perform")
	flag.IntVar(&p.ratio, "ratio", p.ratio, "Ratio `R` of light change: number of lux for a 1% change in backlight")
	flag.BoolVar(&p.dryrun, "dryrun", p.dryrun, "Do not set backlight, only print what would happen")
	flag.BoolVar(&p.debug, "debug", p.debug, "Print values read from sensors every wait duration")
	flag.DurationVar(&p.wait, "wait", p.wait, "Duration `T` between checks for changed light conditions")
	flag.Parse()
	p.poll()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"time"
)

var port int
var path string

var names = []string{
	"Serena Williams",
	"Roger Federer",
	"Andy Murray",
	"Maria Sharapova",
	"Rafael Nadal",
}

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	flag.IntVar(&port, "p", 3000, "The port to run serve up your files on.")
	flag.StringVar(&path, "d", ".", "The directory to serve up")
}

func main() {
	flag.Parse()

	name := names[rand.Intn(len(names))]

	fmt.Printf("Move aside %v! We're serving up aces on port %v\n", name, port)

	err := AceServe(port, path)

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

func AceServe(port int, path string) error {
	host := fmt.Sprintf("localhost:%v", port)

	return http.ListenAndServe(host, http.FileServer(http.Dir(path)))
}
<commit_msg>more golang thangs<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"time"
)

var (
	port int
	path string
)

var names = []string{
	"Serena Williams",
	"Roger Federer",
	"Andy Murray",
	"Maria Sharapova",
	"Rafael Nadal",
}

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	flag.IntVar(&port, "p", 3000, "The port to run serve up your files on.")
	flag.StringVar(&path, "d", ".", "The directory to serve up")
}

func main() {
	flag.Parse()

	name := names[rand.Intn(len(names))]

	fmt.Printf("Move aside %v! We're serving up aces on port %v\n", name, port)

	err := AceServe(port, path)

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

func AceServe(port int, path string) error {
	host := fmt.Sprintf("localhost:%v", port)

	return http.ListenAndServe(host, http.FileServer(http.Dir(path)))
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"

	xpost "github.com/jirwin/xpost-quadlek/pkg"
	"go.uber.org/zap"

	"github.com/Bullpeen/infobot"
	"github.com/Bullpeen/slices"
	"github.com/Bullpeen/stox"
	gifs "github.com/jirwin/gifs-quadlek/src"
	"github.com/jirwin/quadlek/plugins/comics"
	"github.com/jirwin/quadlek/plugins/echo"
	"github.com/jirwin/quadlek/plugins/eslogs"
	"github.com/jirwin/quadlek/plugins/karma"
	"github.com/jirwin/quadlek/plugins/nextep"
	"github.com/jirwin/quadlek/plugins/random"
	"github.com/jirwin/quadlek/plugins/spotify"
	"github.com/jirwin/quadlek/plugins/twitter"
	"github.com/jirwin/quadlek/quadlek"

	"github.com/morgabra/cointip/quadlek"
	twitch "github.com/morgabra/libtwitch/quadlek"
	"github.com/urfave/cli"
)

const Version = "0.0.1"

func run(c *cli.Context) error {
	var apiToken string
	if c.IsSet("api-key") {
		apiToken = c.String("api-key")
	} else {
		cli.ShowAppHelp(c)
		return cli.NewExitError("Missing --api-key arg.", 1)
	}

	var verificationToken string
	if c.IsSet("verification-token") {
		verificationToken = c.String("verification-token")
	} else {
		cli.ShowAppHelp(c)
		return cli.NewExitError("Missing --verification-token arg.", 1)
	}

	dbPath := c.String("db-path")

	bot, err := quadlek.NewBot(context.Background(), apiToken, verificationToken, dbPath)
	if err != nil {
		zap.L().Error("error creating bot", zap.Error(err))
		return nil
	}

	err = bot.RegisterPlugin(echo.Register())
	if err != nil {
		fmt.Printf("error registering echo plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(karma.Register())
	if err != nil {
		fmt.Printf("error registering karma plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(random.Register())
	if err != nil {
		fmt.Printf("error registering random plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(spotify.Register())
	if err != nil {
		fmt.Printf("error registering spotify plugin: %s\n", err.Error())
		return nil
	}

	if c.IsSet("tvdb-key") {
		tvdbKey := c.String("tvdb-key")

		err = bot.RegisterPlugin(nextep.Register(tvdbKey))
		if err != nil {
			fmt.Printf("error registering nextep plugin: %s\n", err.Error())
			return nil
		}
	}

	err = bot.RegisterPlugin(infobot.Register())
	if err != nil {
		fmt.Printf("error registering infobot plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(twitter.Register(
		c.String("twitter-consumer-key"),
		c.String("twitter-consumer-secret"),
		c.String("twitter-access-token"),
		c.String("twitter-access-secret"),
		// These must be twitter user ids, not names. https://tweeterid.com/ for easy conversion between the two.
		map[string]string{
			"25073877":            "politics-feed", // @realDonaldTrump
			"830896623689547776":  "politics-feed", // @PresVillain
			"934474767645724672":  "politics-feed", // @realtrumpweathr
			"138203134":           "politics-feed", // @AOC
			"783792992":           "politics-feed", // @IlhanMN
			"31013444":            "politics-feed", // @AyannaPressley
			"1079769536730140672": "politics-feed", // @RepRashida
			"976366106561490944":  "artfolio",      // @DrawnDavidsOff
			"921111554371682304":  "artfolio",      // @DrawnDavidson
			"1581511":             "wwdc",          //@macrumorslive
			//added for retweet testing
			"778682": "quadlek-chat", // @jirwin

		},
	))

	coinbasePlugin := cointip.Register(
		c.String("coinbase-key"),
		c.String("coinbase-secret"),
		c.String("coinbase-account"),
	)
	if coinbasePlugin != nil {
		err = bot.RegisterPlugin(coinbasePlugin)
		if err != nil {
			panic(err)
		}
	}

	err = bot.RegisterPlugin(comics.Register(
		c.String("imgur-client-id"),
		"/opt/quad-assets/Arial.ttf",
	))
	if err != nil {
		fmt.Printf("error registering comic plugin: %s\n", err.Error())
		return err
	}
	esPlugin, err := eslogs.Register(c.String("es-endpoint"), c.String("es-index"))
	if err != nil {
		fmt.Printf("Error creating eslogs plugin: %s\n", err.Error())
		return err
	}
	err = bot.RegisterPlugin(esPlugin)
	if err != nil {
		fmt.Printf("Error registering eslogs plugin: %s\n", err.Error())
		return err
	}

	xpostPlugin := xpost.Register()
	err = bot.RegisterPlugin(xpostPlugin)
	if err != nil {
		fmt.Printf("error registering xpost plugin: %s\n", err.Error())
		return err
	}

	stoxPlugin := stox.Register(c.String("av-key"))
	err = bot.RegisterPlugin(stoxPlugin)
	if err != nil {
		fmt.Printf("Error registering stox plugin: %s\n", err.Error())
		return err
	}

	gifPlugin := gifs.Register(c.String("giphy-api-key"))
	err = bot.RegisterPlugin(gifPlugin)
	if err != nil {
		fmt.Printf("Error registering gifs plugin: %s\n", err.Error())
		return err
	}

	twitchFollows := []*twitch.TwitchFollow{
		{
			SlackChannels: []string{"kitboga"},
			TwitchUser:    "kitboga",
			WatchStream:   true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "telewyn",
			SlackUser:     "telewyn",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "khryo72",
			SlackUser:     "morgabra",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "mekilek",
			SlackUser:     "jirwin",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "sonicdm",
			SlackUser:     "sonicdm",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "sakatana",
			SlackUser:     "saka",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "pountaar",
			SlackUser:     "purdyk",
			WatchStream:   true,
			WatchFollows:  true,
		},
	}

	twitchPlugin := twitch.Register(c.String("twitch-oauth-client-id"), "", "https://quadlek.jirw.in/slack/plugin/twitch", false, twitchFollows)
	if twitchPlugin != nil {
		err = bot.RegisterPlugin(twitchPlugin)
		if err != nil {
			fmt.Printf("error registering twitch plugin: %s\n", err.Error())
			return err
		}
	}

	err = bot.RegisterPlugin(slices.Register([]string{
		"76561197980107683", // sonicdm
		"76561197976367183", // morgabra
		"76561198057633471", // greenjeans
		"76561198002272597", // newsomr
		"76561197974723967", // purdyk
		"1967806609958425",  // bh
		//"76561197969022064", // schonstal?
	}))
	if err != nil {
		fmt.Printf("error registering slices plugin: %s\n", err.Error())
		return nil
	}

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

	bot.Start()
	<-signals
	bot.Stop()

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "quadlek"
	app.Version = Version
	app.Usage = "a slack bot"
	app.Action = run
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "api-key",
			Usage:  "The slack api token for the bot",
			EnvVar: "QUADLEK_API_TOKEN",
		},
		cli.StringFlag{
			Name:   "verification-token",
			Usage:  "The slack webhook verification token.",
			EnvVar: "QUADLEK_VERIFICATION_TOKEN",
		},
		cli.StringFlag{
			Name:   "db-path",
			Usage:  "The path where the database is stored.",
			Value:  "quadlek.db",
			EnvVar: "QUADLEK_DB_PATH",
		},
		cli.StringFlag{
			Name:   "tvdb-key",
			Usage:  "The TVDB api key for the bot, used by the nextep command",
			EnvVar: "QUADLEK_TVDB_TOKEN",
		},
		cli.StringFlag{
			Name:   "twitter-consumer-key",
			Usage:  "The consumer key for the twitter api",
			EnvVar: "QUADLEK_TWITTER_CONSUMER_KEY",
		},
		cli.StringFlag{
			Name:   "twitter-consumer-secret",
			Usage:  "The consumer secret for the twitter api",
			EnvVar: "QUADLEK_TWITTER_CONSUMER_SECRET",
		},
		cli.StringFlag{
			Name:   "twitter-access-token",
			Usage:  "The access key for the twitter api",
			EnvVar: "QUADLEK_TWITTER_ACCESS_TOKEN",
		},
		cli.StringFlag{
			Name:   "twitter-access-secret",
			Usage:  "The access secret for the twitter api",
			EnvVar: "QUADLEK_TWITTER_ACCESS_SECRET",
		},
		cli.StringFlag{
			Name:   "coinbase-key",
			Usage:  "The access key for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_KEY",
		},
		cli.StringFlag{
			Name:   "coinbase-secret",
			Usage:  "The access secret for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_SECRET",
		},
		cli.StringFlag{
			Name:   "coinbase-account",
			Usage:  "The bank account for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_BANK_ACCOUNT",
		},
		cli.StringFlag{
			Name:   "imgur-client-id",
			Usage:  "The imgur client id",
			EnvVar: "QUADLEK_IMGUR_CLIENT_ID",
		},
		cli.StringFlag{
			Name:   "es-endpoint",
			Usage:  "The elastic search endpoint",
			EnvVar: "QUADLEK_ES_ENDPOINT",
		},
		cli.StringFlag{
			Name:   "es-index",
			Usage:  "The elastic search index",
			EnvVar: "QUADLEK_ES_INDEX",
		},
		cli.StringFlag{
			Name:   "av-key",
			Usage:  "Alpha Vantage Api Key",
			EnvVar: "QUADLEK_AV_KEY",
		},
		cli.StringFlag{
			Name:   "giphy-api-key",
			Usage:  "Giphy API Key",
			EnvVar: "QUADLEK_GIPHY_KEY",
		},
		cli.StringFlag{
			Name:   "twitch-oauth-client-id",
			Usage:  "OAuth application client id for twitch API",
			EnvVar: "QUADLEK_TWITCH_OAUTH_CLIENT_ID",
		},
	}

	app.Run(os.Args)
}
<commit_msg>Add @schonstal to slices<commit_after>package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"

	xpost "github.com/jirwin/xpost-quadlek/pkg"
	"go.uber.org/zap"

	"github.com/Bullpeen/infobot"
	"github.com/Bullpeen/slices"
	"github.com/Bullpeen/stox"
	gifs "github.com/jirwin/gifs-quadlek/src"
	"github.com/jirwin/quadlek/plugins/comics"
	"github.com/jirwin/quadlek/plugins/echo"
	"github.com/jirwin/quadlek/plugins/eslogs"
	"github.com/jirwin/quadlek/plugins/karma"
	"github.com/jirwin/quadlek/plugins/nextep"
	"github.com/jirwin/quadlek/plugins/random"
	"github.com/jirwin/quadlek/plugins/spotify"
	"github.com/jirwin/quadlek/plugins/twitter"
	"github.com/jirwin/quadlek/quadlek"

	"github.com/morgabra/cointip/quadlek"
	twitch "github.com/morgabra/libtwitch/quadlek"
	"github.com/urfave/cli"
)

const Version = "0.0.1"

func run(c *cli.Context) error {
	var apiToken string
	if c.IsSet("api-key") {
		apiToken = c.String("api-key")
	} else {
		cli.ShowAppHelp(c)
		return cli.NewExitError("Missing --api-key arg.", 1)
	}

	var verificationToken string
	if c.IsSet("verification-token") {
		verificationToken = c.String("verification-token")
	} else {
		cli.ShowAppHelp(c)
		return cli.NewExitError("Missing --verification-token arg.", 1)
	}

	dbPath := c.String("db-path")

	bot, err := quadlek.NewBot(context.Background(), apiToken, verificationToken, dbPath)
	if err != nil {
		zap.L().Error("error creating bot", zap.Error(err))
		return nil
	}

	err = bot.RegisterPlugin(echo.Register())
	if err != nil {
		fmt.Printf("error registering echo plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(karma.Register())
	if err != nil {
		fmt.Printf("error registering karma plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(random.Register())
	if err != nil {
		fmt.Printf("error registering random plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(spotify.Register())
	if err != nil {
		fmt.Printf("error registering spotify plugin: %s\n", err.Error())
		return nil
	}

	if c.IsSet("tvdb-key") {
		tvdbKey := c.String("tvdb-key")

		err = bot.RegisterPlugin(nextep.Register(tvdbKey))
		if err != nil {
			fmt.Printf("error registering nextep plugin: %s\n", err.Error())
			return nil
		}
	}

	err = bot.RegisterPlugin(infobot.Register())
	if err != nil {
		fmt.Printf("error registering infobot plugin: %s\n", err.Error())
		return nil
	}

	err = bot.RegisterPlugin(twitter.Register(
		c.String("twitter-consumer-key"),
		c.String("twitter-consumer-secret"),
		c.String("twitter-access-token"),
		c.String("twitter-access-secret"),
		// These must be twitter user ids, not names. https://tweeterid.com/ for easy conversion between the two.
		map[string]string{
			"25073877":            "politics-feed", // @realDonaldTrump
			"830896623689547776":  "politics-feed", // @PresVillain
			"934474767645724672":  "politics-feed", // @realtrumpweathr
			"138203134":           "politics-feed", // @AOC
			"783792992":           "politics-feed", // @IlhanMN
			"31013444":            "politics-feed", // @AyannaPressley
			"1079769536730140672": "politics-feed", // @RepRashida
			"976366106561490944":  "artfolio",      // @DrawnDavidsOff
			"921111554371682304":  "artfolio",      // @DrawnDavidson
			"1581511":             "wwdc",          //@macrumorslive
			//added for retweet testing
			"778682": "quadlek-chat", // @jirwin

		},
	))

	coinbasePlugin := cointip.Register(
		c.String("coinbase-key"),
		c.String("coinbase-secret"),
		c.String("coinbase-account"),
	)
	if coinbasePlugin != nil {
		err = bot.RegisterPlugin(coinbasePlugin)
		if err != nil {
			panic(err)
		}
	}

	err = bot.RegisterPlugin(comics.Register(
		c.String("imgur-client-id"),
		"/opt/quad-assets/Arial.ttf",
	))
	if err != nil {
		fmt.Printf("error registering comic plugin: %s\n", err.Error())
		return err
	}
	esPlugin, err := eslogs.Register(c.String("es-endpoint"), c.String("es-index"))
	if err != nil {
		fmt.Printf("Error creating eslogs plugin: %s\n", err.Error())
		return err
	}
	err = bot.RegisterPlugin(esPlugin)
	if err != nil {
		fmt.Printf("Error registering eslogs plugin: %s\n", err.Error())
		return err
	}

	xpostPlugin := xpost.Register()
	err = bot.RegisterPlugin(xpostPlugin)
	if err != nil {
		fmt.Printf("error registering xpost plugin: %s\n", err.Error())
		return err
	}

	stoxPlugin := stox.Register(c.String("av-key"))
	err = bot.RegisterPlugin(stoxPlugin)
	if err != nil {
		fmt.Printf("Error registering stox plugin: %s\n", err.Error())
		return err
	}

	gifPlugin := gifs.Register(c.String("giphy-api-key"))
	err = bot.RegisterPlugin(gifPlugin)
	if err != nil {
		fmt.Printf("Error registering gifs plugin: %s\n", err.Error())
		return err
	}

	twitchFollows := []*twitch.TwitchFollow{
		{
			SlackChannels: []string{"kitboga"},
			TwitchUser:    "kitboga",
			WatchStream:   true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "telewyn",
			SlackUser:     "telewyn",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "khryo72",
			SlackUser:     "morgabra",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "mekilek",
			SlackUser:     "jirwin",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "sonicdm",
			SlackUser:     "sonicdm",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "sakatana",
			SlackUser:     "saka",
			WatchStream:   true,
			WatchFollows:  true,
		},
		{
			SlackChannels: []string{"vidyagames"},
			TwitchUser:    "pountaar",
			SlackUser:     "purdyk",
			WatchStream:   true,
			WatchFollows:  true,
		},
	}

	twitchPlugin := twitch.Register(c.String("twitch-oauth-client-id"), "", "https://quadlek.jirw.in/slack/plugin/twitch", false, twitchFollows)
	if twitchPlugin != nil {
		err = bot.RegisterPlugin(twitchPlugin)
		if err != nil {
			fmt.Printf("error registering twitch plugin: %s\n", err.Error())
			return err
		}
	}

	err = bot.RegisterPlugin(slices.Register([]string{
		"76561197980107683", // sonicdm
		"76561197976367183", // morgabra
		"76561198057633471", // greenjeans
		"76561198002272597", // newsomr
		"76561197974723967", // purdyk
		"1967806609958425",  // bh
		"1964439323566513",  // schonstal
	}))
	if err != nil {
		fmt.Printf("error registering slices plugin: %s\n", err.Error())
		return nil
	}

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

	bot.Start()
	<-signals
	bot.Stop()

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "quadlek"
	app.Version = Version
	app.Usage = "a slack bot"
	app.Action = run
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "api-key",
			Usage:  "The slack api token for the bot",
			EnvVar: "QUADLEK_API_TOKEN",
		},
		cli.StringFlag{
			Name:   "verification-token",
			Usage:  "The slack webhook verification token.",
			EnvVar: "QUADLEK_VERIFICATION_TOKEN",
		},
		cli.StringFlag{
			Name:   "db-path",
			Usage:  "The path where the database is stored.",
			Value:  "quadlek.db",
			EnvVar: "QUADLEK_DB_PATH",
		},
		cli.StringFlag{
			Name:   "tvdb-key",
			Usage:  "The TVDB api key for the bot, used by the nextep command",
			EnvVar: "QUADLEK_TVDB_TOKEN",
		},
		cli.StringFlag{
			Name:   "twitter-consumer-key",
			Usage:  "The consumer key for the twitter api",
			EnvVar: "QUADLEK_TWITTER_CONSUMER_KEY",
		},
		cli.StringFlag{
			Name:   "twitter-consumer-secret",
			Usage:  "The consumer secret for the twitter api",
			EnvVar: "QUADLEK_TWITTER_CONSUMER_SECRET",
		},
		cli.StringFlag{
			Name:   "twitter-access-token",
			Usage:  "The access key for the twitter api",
			EnvVar: "QUADLEK_TWITTER_ACCESS_TOKEN",
		},
		cli.StringFlag{
			Name:   "twitter-access-secret",
			Usage:  "The access secret for the twitter api",
			EnvVar: "QUADLEK_TWITTER_ACCESS_SECRET",
		},
		cli.StringFlag{
			Name:   "coinbase-key",
			Usage:  "The access key for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_KEY",
		},
		cli.StringFlag{
			Name:   "coinbase-secret",
			Usage:  "The access secret for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_SECRET",
		},
		cli.StringFlag{
			Name:   "coinbase-account",
			Usage:  "The bank account for the coinbase api",
			EnvVar: "QUADLEK_COINBASE_BANK_ACCOUNT",
		},
		cli.StringFlag{
			Name:   "imgur-client-id",
			Usage:  "The imgur client id",
			EnvVar: "QUADLEK_IMGUR_CLIENT_ID",
		},
		cli.StringFlag{
			Name:   "es-endpoint",
			Usage:  "The elastic search endpoint",
			EnvVar: "QUADLEK_ES_ENDPOINT",
		},
		cli.StringFlag{
			Name:   "es-index",
			Usage:  "The elastic search index",
			EnvVar: "QUADLEK_ES_INDEX",
		},
		cli.StringFlag{
			Name:   "av-key",
			Usage:  "Alpha Vantage Api Key",
			EnvVar: "QUADLEK_AV_KEY",
		},
		cli.StringFlag{
			Name:   "giphy-api-key",
			Usage:  "Giphy API Key",
			EnvVar: "QUADLEK_GIPHY_KEY",
		},
		cli.StringFlag{
			Name:   "twitch-oauth-client-id",
			Usage:  "OAuth application client id for twitch API",
			EnvVar: "QUADLEK_TWITCH_OAUTH_CLIENT_ID",
		},
	}

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


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/antonlindstrom/mesos_stats"
	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	addr           string
	masterURL      string
	metricsPath    string
	port           int
	scrapeInterval time.Duration
)

var httpClient = http.Client{
	Timeout: 5 * time.Second,
}

func init() {
	flag.StringVar(&addr, "web.listen-address", ":9105", "expose metrics on port")
	flag.StringVar(&metricsPath, "web.telemetry-path", "/metrics", "address to listen on for web interface and telemetry")
	flag.StringVar(&masterURL, "exporter.mesos-master", "http://mesos-master.example.com", "mesos master URL")
	flag.DurationVar(&scrapeInterval, "exporter.interval", (60 * time.Second), "scrape interval duration")
	flag.Parse()
}

type PeriodicExporter struct {
	sync.RWMutex
	slaves struct {
		sync.Mutex
		hostnames []string
	}
	errors  *prometheus.CounterVec
	metrics []prometheus.Gauge
}

func NewMesosExporter(interval time.Duration) *PeriodicExporter {
	e := &PeriodicExporter{
		errors: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Namespace: "exporter",
				Name:      "scrape_errors",
				Help:      "Current total scrape errors ",
			},
			[]string{"mesos_slave"},
		),
		metrics: make([]prometheus.Gauge, 0),
	}

	// Update nr. of mesos slave every 10 minute
	go e.runEvery(e.updateSlaves, (10 * time.Minute))
	// Fetch slave metrics every interval
	go e.runEvery(e.scrapeSlaves, interval)

	return e
}

func (e *PeriodicExporter) Describe(ch chan<- *prometheus.Desc) {
	e.rLockMetrics(func() {
		for _, m := range e.metrics {
			m.Describe(ch)
		}
	})
	e.errors.MetricVec.Describe(ch)
}

func (e *PeriodicExporter) Collect(ch chan<- prometheus.Metric) {
	e.rLockMetrics(func() {
		for _, m := range e.metrics {
			m.Collect(ch)
		}
	})
	e.errors.MetricVec.Collect(ch)
}

func (e *PeriodicExporter) fetch(host string, ch chan prometheus.Gauge) error {
	monitorURL := fmt.Sprintf("http://%s:5051/monitor/statistics.json", host)
	resp, err := httpClient.Get(monitorURL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var stats []mesos_stats.Monitor
	if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
		return err
	}

	for _, stat := range stats {
		cpuLimitVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_limit",
				Help:      "Fractional CPU limit.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuLimitVal.Set(stat.Statistics.CpusSystemTimeSecs)

		cpuSysVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_system_seconds_total",
				Help:      "Cumulative system CPU time in seconds.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuSysVal.Set(stat.Statistics.CpusSystemTimeSecs)

		cpuUsrVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_user_seconds_total",
				Help:      "Cumulative user CPU time in seconds.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuUsrVal.Set(stat.Statistics.CpusUserTimeSecs)

		memLimitVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "memory_limit_bytes",
				Help:      "Task memory limit in bytes.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		memLimitVal.Set(float64(stat.Statistics.MemLimitBytes))

		memRssVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "memory_rss_bytes",
				Help:      "Task memory RSS usage in bytes.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		memRssVal.Set(float64(stat.Statistics.MemRssBytes))

		ch <- cpuLimitVal
		ch <- cpuSysVal
		ch <- cpuUsrVal
		ch <- memLimitVal
		ch <- memRssVal
	}

	return nil
}

func (e *PeriodicExporter) rLockMetrics(f func()) {
	e.RLock()
	defer e.RUnlock()
	f()
}

func (e *PeriodicExporter) runEvery(f func(), interval time.Duration) {
	f()
	for {
		select {
		case <-time.After(interval):
			f()
		}
	}
}

func (e *PeriodicExporter) setMetrics(ch chan prometheus.Gauge) {
	metrics := make([]prometheus.Gauge, 0)
	for metric := range ch {
		metrics = append(metrics, metric)
	}

	e.Lock()
	e.metrics = metrics
	e.Unlock()
}

func (e *PeriodicExporter) scrapeSlaves() {
	e.slaves.Lock()
	hostnames := e.slaves.hostnames
	e.slaves.Unlock()

	glog.V(6).Infof("active slaves: %d", len(hostnames))

	ch := make(chan prometheus.Gauge)
	go e.setMetrics(ch)

	var wg sync.WaitGroup
	wg.Add(len(hostnames))
	for _, host := range hostnames {
		go func(host string, ch chan prometheus.Gauge) {
			defer wg.Done()

			if err := e.fetch(host, ch); err != nil {
				glog.Warningf("%s failed. Error: %s", host, err)
				e.errors.WithLabelValues(host).Inc()
			}
		}(host, ch)
	}
	wg.Wait()

	close(ch)
}

func (e *PeriodicExporter) updateSlaves() {
	glog.V(6).Info("discovering slaves...")

	// This will redirect us to the elected mesos master
	redirectURL := fmt.Sprintf("%s:5050/master/redirect", masterURL)
	rReq, _ := http.NewRequest("GET", redirectURL, nil)

	tr := http.Transport{}
	rresp, err := tr.RoundTrip(rReq)
	if err != nil {
		glog.Warningf("GET %s failed. Error: %s", redirectURL, err)
		return
	}
	defer rresp.Body.Close()

	// This will/should return http://master.ip:5050
	masterLoc := rresp.Header.Get("Location")
	if masterLoc == "" {
		glog.Warningf("%d response missing Location header", rresp.StatusCode)
		return
	}

	// Find all active slaves
	stateURL := fmt.Sprintf("%s/master/state.json", masterLoc)
	resp, err := http.Get(stateURL)
	if err != nil {
		glog.Warningf("GET %s failed. Error: %s", stateURL, err)
		return
	}
	defer resp.Body.Close()

	type slave struct {
		Active   bool   `json:"active"`
		Hostname string `json:"hostname"`
	}

	var req struct {
		Slaves []*slave `json:"slaves"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&req); err != nil {
		glog.Warningf("failed to deserialize request: %s", err)
		return
	}

	var slaveHostnames []string
	for _, slave := range req.Slaves {
		if slave.Active {
			slaveHostnames = append(slaveHostnames, slave.Hostname)
		}
	}

	glog.V(6).Infof("%d slaves discovered", len(slaveHostnames))

	e.slaves.Lock()
	defer e.slaves.Unlock()
	e.slaves.hostnames = slaveHostnames
}

func main() {

	exporter := NewMesosExporter(scrapeInterval)
	prometheus.MustRegister(exporter)

	http.Handle(metricsPath, prometheus.Handler())
	http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "OK")
	})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, metricsPath, http.StatusMovedPermanently)
	})

	glog.Info("starting mesos_exporter on ", addr)

	log.Fatal(http.ListenAndServe(addr, nil))
}
<commit_msg>Removed defer, just for consistency<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/antonlindstrom/mesos_stats"
	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	addr           string
	masterURL      string
	metricsPath    string
	port           int
	scrapeInterval time.Duration
)

var httpClient = http.Client{
	Timeout: 5 * time.Second,
}

func init() {
	flag.StringVar(&addr, "web.listen-address", ":9105", "expose metrics on port")
	flag.StringVar(&metricsPath, "web.telemetry-path", "/metrics", "address to listen on for web interface and telemetry")
	flag.StringVar(&masterURL, "exporter.mesos-master", "http://mesos-master.example.com", "mesos master URL")
	flag.DurationVar(&scrapeInterval, "exporter.interval", (60 * time.Second), "scrape interval duration")
	flag.Parse()
}

type PeriodicExporter struct {
	sync.RWMutex
	slaves struct {
		sync.Mutex
		hostnames []string
	}
	errors  *prometheus.CounterVec
	metrics []prometheus.Gauge
}

func NewMesosExporter(interval time.Duration) *PeriodicExporter {
	e := &PeriodicExporter{
		errors: prometheus.NewCounterVec(
			prometheus.CounterOpts{
				Namespace: "exporter",
				Name:      "scrape_errors",
				Help:      "Current total scrape errors ",
			},
			[]string{"mesos_slave"},
		),
		metrics: make([]prometheus.Gauge, 0),
	}

	// Update nr. of mesos slave every 10 minute
	go e.runEvery(e.updateSlaves, (10 * time.Minute))
	// Fetch slave metrics every interval
	go e.runEvery(e.scrapeSlaves, interval)

	return e
}

func (e *PeriodicExporter) Describe(ch chan<- *prometheus.Desc) {
	e.rLockMetrics(func() {
		for _, m := range e.metrics {
			m.Describe(ch)
		}
	})
	e.errors.MetricVec.Describe(ch)
}

func (e *PeriodicExporter) Collect(ch chan<- prometheus.Metric) {
	e.rLockMetrics(func() {
		for _, m := range e.metrics {
			m.Collect(ch)
		}
	})
	e.errors.MetricVec.Collect(ch)
}

func (e *PeriodicExporter) fetch(host string, ch chan prometheus.Gauge) error {
	monitorURL := fmt.Sprintf("http://%s:5051/monitor/statistics.json", host)
	resp, err := httpClient.Get(monitorURL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var stats []mesos_stats.Monitor
	if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
		return err
	}

	for _, stat := range stats {
		cpuLimitVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_limit",
				Help:      "Fractional CPU limit.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuLimitVal.Set(stat.Statistics.CpusSystemTimeSecs)

		cpuSysVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_system_seconds_total",
				Help:      "Cumulative system CPU time in seconds.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuSysVal.Set(stat.Statistics.CpusSystemTimeSecs)

		cpuUsrVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "cpu_user_seconds_total",
				Help:      "Cumulative user CPU time in seconds.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		cpuUsrVal.Set(stat.Statistics.CpusUserTimeSecs)

		memLimitVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "memory_limit_bytes",
				Help:      "Task memory limit in bytes.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		memLimitVal.Set(float64(stat.Statistics.MemLimitBytes))

		memRssVal := prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: "mesos_task",
				Name:      "memory_rss_bytes",
				Help:      "Task memory RSS usage in bytes.",
				ConstLabels: prometheus.Labels{
					"task":         stat.Source,
					"mesos_slave":  host,
					"framework_id": stat.FrameworkId,
				},
			},
		)
		memRssVal.Set(float64(stat.Statistics.MemRssBytes))

		ch <- cpuLimitVal
		ch <- cpuSysVal
		ch <- cpuUsrVal
		ch <- memLimitVal
		ch <- memRssVal
	}

	return nil
}

func (e *PeriodicExporter) rLockMetrics(f func()) {
	e.RLock()
	defer e.RUnlock()
	f()
}

func (e *PeriodicExporter) runEvery(f func(), interval time.Duration) {
	f()
	for {
		select {
		case <-time.After(interval):
			f()
		}
	}
}

func (e *PeriodicExporter) setMetrics(ch chan prometheus.Gauge) {
	metrics := make([]prometheus.Gauge, 0)
	for metric := range ch {
		metrics = append(metrics, metric)
	}

	e.Lock()
	e.metrics = metrics
	e.Unlock()
}

func (e *PeriodicExporter) scrapeSlaves() {
	e.slaves.Lock()
	hostnames := e.slaves.hostnames
	e.slaves.Unlock()

	glog.V(6).Infof("active slaves: %d", len(hostnames))

	ch := make(chan prometheus.Gauge)
	go e.setMetrics(ch)

	var wg sync.WaitGroup
	wg.Add(len(hostnames))
	for _, host := range hostnames {
		go func(host string, ch chan prometheus.Gauge) {
			defer wg.Done()

			if err := e.fetch(host, ch); err != nil {
				glog.Warningf("%s failed. Error: %s", host, err)
				e.errors.WithLabelValues(host).Inc()
			}
		}(host, ch)
	}
	wg.Wait()

	close(ch)
}

func (e *PeriodicExporter) updateSlaves() {
	glog.V(6).Info("discovering slaves...")

	// This will redirect us to the elected mesos master
	redirectURL := fmt.Sprintf("%s:5050/master/redirect", masterURL)
	rReq, _ := http.NewRequest("GET", redirectURL, nil)

	tr := http.Transport{}
	rresp, err := tr.RoundTrip(rReq)
	if err != nil {
		glog.Warningf("GET %s failed. Error: %s", redirectURL, err)
		return
	}
	defer rresp.Body.Close()

	// This will/should return http://master.ip:5050
	masterLoc := rresp.Header.Get("Location")
	if masterLoc == "" {
		glog.Warningf("%d response missing Location header", rresp.StatusCode)
		return
	}

	// Find all active slaves
	stateURL := fmt.Sprintf("%s/master/state.json", masterLoc)
	resp, err := http.Get(stateURL)
	if err != nil {
		glog.Warningf("GET %s failed. Error: %s", stateURL, err)
		return
	}
	defer resp.Body.Close()

	type slave struct {
		Active   bool   `json:"active"`
		Hostname string `json:"hostname"`
	}

	var req struct {
		Slaves []*slave `json:"slaves"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&req); err != nil {
		glog.Warningf("failed to deserialize request: %s", err)
		return
	}

	var slaveHostnames []string
	for _, slave := range req.Slaves {
		if slave.Active {
			slaveHostnames = append(slaveHostnames, slave.Hostname)
		}
	}

	glog.V(6).Infof("%d slaves discovered", len(slaveHostnames))

	e.slaves.Lock()
	e.slaves.hostnames = slaveHostnames
	e.slaves.Unlock()
}

func main() {

	exporter := NewMesosExporter(scrapeInterval)
	prometheus.MustRegister(exporter)

	http.Handle(metricsPath, prometheus.Handler())
	http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "OK")
	})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, metricsPath, http.StatusMovedPermanently)
	})

	glog.Info("starting mesos_exporter on ", addr)

	log.Fatal(http.ListenAndServe(addr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"

	"github.com/eirka/eirka-libs/auth"
	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/cors"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/validate"

	local "github.com/eirka/eirka-get/config"
	c "github.com/eirka/eirka-get/controllers"
	m "github.com/eirka/eirka-get/middleware"
)

var (
	version = "1.0.5"
)

func init() {
	// Database connection settings
	dbase := db.Database{

		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

	// redis settings
	r := redis.Redis{
		// Redis address and max pool connections
		Protocol:       local.Settings.Redis.Protocol,
		Address:        local.Settings.Redis.Address,
		MaxIdle:        local.Settings.Redis.MaxIdle,
		MaxConnections: local.Settings.Redis.MaxConnections,
	}

	// Set up Redis connection
	r.NewRedisCache()

	// set auth middleware secret
	auth.Secret = local.Settings.Session.Secret

	// print the starting info
	StartInfo()

	// Print out config
	config.Print()

	// Print out config
	local.Print()

	// set cors domains
	cors.SetDomains(local.Settings.CORS.Sites, strings.Split("GET", ","))

}

func main() {
	r := gin.Default()

	// add CORS headers
	r.Use(cors.CORS())
	// validate all route parameters
	r.Use(validate.ValidateParams())

	r.GET("/uptime", c.UptimeController)
	r.NoRoute(c.ErrorController)

	// public cached pages
	public := r.Group("/")
	public.Use(m.AntiSpamCookie())
	public.Use(auth.Auth(false))
	public.Use(m.Analytics())
	public.Use(m.Cache())

	public.GET("/index/:ib/:page", c.IndexController)
	public.GET("/thread/:ib/:thread/:page", c.ThreadController)
	public.GET("/tag/:ib/:tag/:page", c.TagController)
	public.GET("/image/:ib/:id", c.ImageController)
	public.GET("/post/:ib/:thread/:id", c.PostController)
	public.GET("/tags/:ib/:page", c.TagsController)
	public.GET("/tagsearch/:ib", c.TagSearchController)
	public.GET("/directory/:ib", c.DirectoryController)
	public.GET("/popular/:ib", c.PopularController)
	public.GET("/new/:ib", c.NewController)
	public.GET("/favorited/:ib", c.FavoritedController)
	public.GET("/tagtypes", c.TagTypesController)
	public.GET("/imageboards", c.ImageboardsController)

	// user pages
	users := r.Group("/user")
	users.Use(auth.Auth(true))

	users.GET("/whoami/:ib", c.UserController)
	users.GET("/favorite/:id", c.FavoriteController)
	users.GET("/favorites/:ib/:page", c.FavoritesController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Get.Address, local.Settings.Get.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}

func StartInfo() {

	fmt.Println(strings.Repeat("*", 60))
	fmt.Printf("%-20v\n\n", "PRAM-GET")
	fmt.Printf("%-20v%40v\n", "Version", version)
	fmt.Println(strings.Repeat("*", 60))

}
<commit_msg>new user lib<commit_after>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/cors"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
	"github.com/eirka/eirka-libs/validate"

	local "github.com/eirka/eirka-get/config"
	c "github.com/eirka/eirka-get/controllers"
	m "github.com/eirka/eirka-get/middleware"
)

var (
	version = "1.0.5"
)

func init() {
	// Database connection settings
	dbase := db.Database{

		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

	// redis settings
	r := redis.Redis{
		// Redis address and max pool connections
		Protocol:       local.Settings.Redis.Protocol,
		Address:        local.Settings.Redis.Address,
		MaxIdle:        local.Settings.Redis.MaxIdle,
		MaxConnections: local.Settings.Redis.MaxConnections,
	}

	// Set up Redis connection
	r.NewRedisCache()

	// set auth middleware secret
	user.Secret = local.Settings.Session.Secret

	// print the starting info
	StartInfo()

	// Print out config
	config.Print()

	// Print out config
	local.Print()

	// set cors domains
	cors.SetDomains(local.Settings.CORS.Sites, strings.Split("GET", ","))

}

func main() {
	r := gin.Default()

	// add CORS headers
	r.Use(cors.CORS())
	// validate all route parameters
	r.Use(validate.ValidateParams())

	r.GET("/uptime", c.UptimeController)
	r.NoRoute(c.ErrorController)

	// public cached pages
	public := r.Group("/")
	public.Use(m.AntiSpamCookie())
	public.Use(user.Auth(false))
	public.Use(m.Analytics())
	public.Use(m.Cache())

	public.GET("/index/:ib/:page", c.IndexController)
	public.GET("/thread/:ib/:thread/:page", c.ThreadController)
	public.GET("/tag/:ib/:tag/:page", c.TagController)
	public.GET("/image/:ib/:id", c.ImageController)
	public.GET("/post/:ib/:thread/:id", c.PostController)
	public.GET("/tags/:ib/:page", c.TagsController)
	public.GET("/tagsearch/:ib", c.TagSearchController)
	public.GET("/directory/:ib", c.DirectoryController)
	public.GET("/popular/:ib", c.PopularController)
	public.GET("/new/:ib", c.NewController)
	public.GET("/favorited/:ib", c.FavoritedController)
	public.GET("/tagtypes", c.TagTypesController)
	public.GET("/imageboards", c.ImageboardsController)

	// user pages
	users := r.Group("/user")
	users.Use(user.Auth(true))

	users.GET("/whoami/:ib", c.UserController)
	users.GET("/favorite/:id", c.FavoriteController)
	users.GET("/favorites/:ib/:page", c.FavoritesController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Get.Address, local.Settings.Get.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}

func StartInfo() {

	fmt.Println(strings.Repeat("*", 60))
	fmt.Printf("%-20v\n\n", "PRAM-GET")
	fmt.Printf("%-20v%40v\n", "Version", version)
	fmt.Println(strings.Repeat("*", 60))

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"

	"github.com/gin-gonic/gin"
	"github.com/nesurion/milight-daemon/milight"
)

func main() {
	ginMode := flag.String("mode", gin.ReleaseMode, "Gin Mode (debug, release, test)")
	flag.Parse()
	SetMode(*ginMode)
	router := gin.Default()

	c, err := milight.NewConfig("milight-daemon.conf")
	if err != nil {
		panic("failed to parse config file")
	}
	host := fmt.Sprintf("0.0.0.0:%d", c.Port)
	fmt.Println("=== Milight Daemon ===")
	fmt.Printf("Running on %s\n", host)

	// create limitless controller
	mc := milight.NewClient(c)

	router.POST("/on", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.On(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "on",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/off", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Off(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "off",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/rgb", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		rgb, err := ParseRGB(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Rgb(id, rgb)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "rgb",
			"rgb":     rgb,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/brightness", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		bl, err := ParseBrightnessLevel(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Brightness(id, bl)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "brightness",
			"level":   bl,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/color", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		color, err := ParseColor(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Color(id, color)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "color",
			"color":   fmt.Sprintf("%x", color),
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/white", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.White(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "white",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/night", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Night(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "night",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/disco", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		speed, err := parseSpeed(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Disco(id, speed)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "disco",
			"speed":   speed,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.Run(host)
}

func SetMode(mode string) {
	switch mode {
	case "release":
		gin.SetMode(gin.ReleaseMode)
	case "debug":
		gin.SetMode(gin.DebugMode)
	case "test":
		gin.SetMode(gin.TestMode)
	default:
		panic("mode unavailable. (debug, release, test)")
	}
}
<commit_msg>adds version constant<commit_after>package main

import (
	"flag"
	"fmt"

	"github.com/gin-gonic/gin"
	"github.com/nesurion/milight-daemon/milight"
)

const (
	VERSION = "0.0.1"
)

func main() {
	ginMode := flag.String("mode", gin.ReleaseMode, "Gin Mode (debug, release, test)")
	flag.Parse()
	SetMode(*ginMode)
	router := gin.Default()

	c, err := milight.NewConfig("milight-daemon.conf")
	if err != nil {
		panic("failed to parse config file")
	}
	host := fmt.Sprintf("0.0.0.0:%d", c.Port)
	fmt.Println("=== Milight Daemon ===")
	fmt.Printf("Version %s\n", VERSION)
	fmt.Printf("Running on %s\n", host)

	// create limitless controller
	mc := milight.NewClient(c)

	router.POST("/on", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.On(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "on",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/off", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Off(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "off",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/rgb", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		rgb, err := ParseRGB(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Rgb(id, rgb)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "rgb",
			"rgb":     rgb,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/brightness", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		bl, err := ParseBrightnessLevel(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Brightness(id, bl)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "brightness",
			"level":   bl,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/color", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		color, err := ParseColor(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Color(id, color)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "color",
			"color":   fmt.Sprintf("%x", color),
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/white", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.White(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "white",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/night", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Night(id)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "night",
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.POST("/disco", func(c *gin.Context) {
		id, err := ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		speed, err := parseSpeed(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		err = mc.Disco(id, speed)
		if err != nil {
			c.AbortWithError(500, err)
			return
		}
		msg := gin.H{
			"command": "disco",
			"speed":   speed,
			"group":   id + 1,
		}
		c.JSON(200, msg)
	})

	router.Run(host)
}

func SetMode(mode string) {
	switch mode {
	case "release":
		gin.SetMode(gin.ReleaseMode)
	case "debug":
		gin.SetMode(gin.DebugMode)
	case "test":
		gin.SetMode(gin.TestMode)
	default:
		panic("mode unavailable. (debug, release, test)")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
)

// Data struct for JIRA JSON parsing.
type Data struct {
	WebhookEvent string
	User         struct {
		Name        string
		AvatarUrls  map[string]string
		DisplayName string
	}
	Issue struct {
		Self   string
		Key    string
		Fields struct {
			Issuetype struct {
					  IconURL string
					  Name    string
			}
			Summary string
		}
	}
	Comment struct {
		Body string
	}
	Changelog struct {
		Items []struct {
			Field      string
			FromString string
			ToString   string
		}
	}
}

// Message structure for Mattermost JSON creation.
type Message struct {
	Text     string `json:"text"`
	Username string `json:"username"`
	IconURL  string `json:"icon_url"`
}

func getMessage(request *http.Request) []byte {
	// Parse JSON from JIRA
	decoder := json.NewDecoder(request.Body)
	var data Data
	decoder.Decode(&data)

	// Get JIRA URL from "issue" section in JSON
	u, _ := url.Parse(data.Issue.Self)

	// Select action
	var action, comment string
	switch data.WebhookEvent {
	case "jira:issue_created":
		action = "created"
	case "jira:issue_updated":
		action = "updated"
	case "jira:issue_deleted":
		action = "deleted"
	}

	//Process new comment
	if len(data.Comment.Body) > 0 {
		comment = fmt.Sprintf("\nComment:\n>%s", data.Comment.Body)
	}

	// Process changelog
	var changelog string
	if len(data.Changelog.Items) > 0 {
		for _, item := range data.Changelog.Items {
			itemName := strings.ToUpper(string(item.Field[0])) + item.Field[1:]
			if item.FromString == "" {
				item.FromString = "None"
			}
			changelog += fmt.Sprintf(
				"\n%s: ~~%s~~ %s",
				itemName,
				item.FromString,
				item.ToString,
			)
		}
	}

	// Create message for Mattermost
	text := fmt.Sprintf(
		//Message format:
		//![user_icon](user_icon_link)[UserFirstName UserSecondName](user_link) commented task ![task_icon](task_icon link)[TSK-42](issue_link) "Test task"
		//Status: ~~Done~~ Finished
		//>Comment text
		"![user_icon](%s) [%s](%s://%s/secure/ViewProfile.jspa?name=%s) %s %s ![task_icon](%s) [%s](%s://%s/browse/%s) \"%s\"%s%s",
		data.User.AvatarUrls["16x16"],
		data.User.DisplayName,
		u.Scheme,
		u.Host,
		data.User.Name,
		action,
		strings.ToLower(data.Issue.Fields.Issuetype.Name),
		data.Issue.Fields.Issuetype.IconURL,
		data.Issue.Key,
		u.Scheme,
		u.Host,
		data.Issue.Key,
		data.Issue.Fields.Summary,
		changelog,
		comment,
	)

	message := Message{
		Text:     text,
		Username: "JIRA",
		IconURL:  "https://design.atlassian.com/images/logo/favicon.png",
	}

	JSONMessage, _ := json.Marshal(message)

	return JSONMessage
}

func index(_ http.ResponseWriter, r *http.Request) {

	// Get mattermost URL
	mattermostHookURL := r.URL.Query().Get("mattermost_hook_url")

	if len(mattermostHookURL) > 0 {
		// Get message from JIRA JSON request
		message := getMessage(r)

		// Create http-client
		req, _ := http.NewRequest("POST", mattermostHookURL, bytes.NewBuffer(message))
		req.Header.Set("Content-Type", "application/json")

		// Send data to Mattermost
		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		defer resp.Body.Close()
	}
}

func main() {

	port := os.Getenv("PORT")
	if port == "" {
		port = "5000"
	}
	http.HandleFunc("/", index)
	http.ListenAndServe(":"+port, nil)
}
<commit_msg>Fix comment text bug<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
)

// Data struct for JIRA JSON parsing.
type Data struct {
	WebhookEvent string
	User         struct {
		Name        string
		AvatarUrls  map[string]string
		DisplayName string
	}
	Issue struct {
		Self   string
		Key    string
		Fields struct {
			Issuetype struct {
					  IconURL string
					  Name    string
			}
			Summary string
		}
	}
	Comment struct {
		Body string
	}
	Changelog struct {
		Items []struct {
			Field      string
			FromString string
			ToString   string
		}
	}
}

// Message structure for Mattermost JSON creation.
type Message struct {
	Text     string `json:"text"`
	Username string `json:"username"`
	IconURL  string `json:"icon_url"`
}

func getMessage(request *http.Request) []byte {
	// Parse JSON from JIRA
	decoder := json.NewDecoder(request.Body)
	var data Data
	decoder.Decode(&data)

	// Get JIRA URL from "issue" section in JSON
	u, _ := url.Parse(data.Issue.Self)

	// Select action
	var action, comment string
	switch data.WebhookEvent {
	case "jira:issue_created":
		action = "created"
	case "jira:issue_updated":
		action = "updated"
	case "jira:issue_deleted":
		action = "deleted"
	}

	//Process new comment
	if len(data.Comment.Body) > 0 {
		comment = fmt.Sprintf("\nComment:\n```\n%s\n```", data.Comment.Body)
	}

	// Process changelog
	var changelog string
	if len(data.Changelog.Items) > 0 {
		for _, item := range data.Changelog.Items {
			itemName := strings.ToUpper(string(item.Field[0])) + item.Field[1:]
			if item.FromString == "" {
				item.FromString = "None"
			}
			changelog += fmt.Sprintf(
				"\n%s: ~~%s~~ %s",
				itemName,
				item.FromString,
				item.ToString,
			)
		}
	}

	// Create message for Mattermost
	text := fmt.Sprintf(
		//Message format:
		//![user_icon](user_icon_link)[UserFirstName UserSecondName](user_link) commented task ![task_icon](task_icon link)[TSK-42](issue_link) "Test task"
		//Status: ~~Done~~ Finished
		//>Comment text
		"![user_icon](%s) [%s](%s://%s/secure/ViewProfile.jspa?name=%s) %s %s ![task_icon](%s) [%s](%s://%s/browse/%s) \"%s\"%s%s",
		data.User.AvatarUrls["16x16"],
		data.User.DisplayName,
		u.Scheme,
		u.Host,
		data.User.Name,
		action,
		strings.ToLower(data.Issue.Fields.Issuetype.Name),
		data.Issue.Fields.Issuetype.IconURL,
		data.Issue.Key,
		u.Scheme,
		u.Host,
		data.Issue.Key,
		data.Issue.Fields.Summary,
		changelog,
		comment,
	)

	message := Message{
		Text:     text,
		Username: "JIRA",
		IconURL:  "https://design.atlassian.com/images/logo/favicon.png",
	}

	JSONMessage, _ := json.Marshal(message)

	return JSONMessage
}

func index(_ http.ResponseWriter, r *http.Request) {

	// Get mattermost URL
	mattermostHookURL := r.URL.Query().Get("mattermost_hook_url")

	if len(mattermostHookURL) > 0 {
		// Get message from JIRA JSON request
		message := getMessage(r)

		// Create http-client
		req, _ := http.NewRequest("POST", mattermostHookURL, bytes.NewBuffer(message))
		req.Header.Set("Content-Type", "application/json")

		// Send data to Mattermost
		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		defer resp.Body.Close()
	}
}

func main() {

	port := os.Getenv("PORT")
	if port == "" {
		port = "5000"
	}
	http.HandleFunc("/", index)
	http.ListenAndServe(":"+port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"expvar"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	cfg "github.com/alyu/configparser"
	"github.com/dgryski/carbonzipper/mlog"
	"github.com/dgryski/httputil"
	whisper "github.com/grobian/go-whisper"
	g2g "github.com/peterbourgon/g2g"
)

var config = struct {
	WhisperData  string
	GraphiteHost string
	MaxGlobs     int
	Buckets      int
}{
	WhisperData: "/var/lib/carbon/whisper",
	MaxGlobs:    10,
	Buckets:     10,
}

// grouped expvars for /debug/vars and graphite
var Metrics = struct {
	MetricsReceived *expvar.Int
}{
	MetricsReceived: expvar.NewInt("metrics_received"),
}

var BuildVersion string = "(development build)"

var logger mlog.Level

func handleConnection(conn net.Conn, schemas []*StorageSchema, aggrs []*StorageAggregation) {
	bufconn := bufio.NewReader(conn)

	for {
		line, err := bufconn.ReadBytes('\n')
		if err != nil {
			conn.Close()
			if err != io.EOF {
				logger.Logf("read failed: %s", err.Error())
			}
			break
		}

		elems := strings.Split(string(line), " ")
		if len(elems) != 3 {
			logger.Logf("invalid line: %s", string(line))
			continue
		}

		metric := elems[0]

		value, err := strconv.ParseFloat(elems[1], 64)
		if err != nil {
			logger.Logf("invalue value '%s': %s", elems[1], err.Error())
			continue
		}

		elems[2] = strings.TrimRight(elems[2], "\n")
		tsf, err := strconv.ParseFloat(elems[2], 64)
		if err != nil {
			logger.Logf("invalid timestamp '%s': %s", elems[2], err.Error())
			continue
		}
		ts := int(tsf)

		if metric == "" {
			logger.Logf("invalid line: %s", string(line))
			continue
		}

		if ts == 0 {
			logger.Logf("invalid timestamp (0): %s", string(line))
			continue
		}

		logger.Debugf("metric: %s, value: %f, ts: %d", metric, value, ts)

		// catch panics from whisper-go library
		defer func() {
			if r := recover(); r != nil {
				logger.Logf("recovering from whisper panic (metric: %s): %v", metric, r)
				err := conn.Close()
				if err != nil {
					logger.Logf("error while closing connection after whisper panic: %v", err)
				}
			}
		}()

		// do what we want to do
		path := config.WhisperData + "/" + strings.Replace(metric, ".", "/", -1) + ".wsp"
		w, err := whisper.Open(path)
		if err != nil {
			var schema *StorageSchema = nil
			for _, s := range schemas {
				if s.pattern.MatchString(metric) {
					schema = s
					break
				}
			}
			if schema == nil {
				logger.Logf("no storage schema defined for %s", metric)
				continue
			}
			logger.Debugf("%s: found schema: %s", metric, schema.name)

			var aggr *StorageAggregation = nil
			for _, a := range aggrs {
				if a.pattern.MatchString(metric) {
					aggr = a
					break
				}
			}

			// http://graphite.readthedocs.org/en/latest/config-carbon.html#storage-aggregation-conf
			aggrName := "(default)"
			aggrStr := "average"
			aggrType := whisper.Average
			xfilesf := float32(0.5)
			if aggr != nil {
				aggrName = aggr.name
				aggrStr = aggr.aggregationMethodStr
				aggrType = aggr.aggregationMethod
				xfilesf = float32(aggr.xFilesFactor)
			}

			logger.Logf("creating %s: %s, retention: %s (section %s), aggregationMethod: %s, xFilesFactor: %f (section %s)",
				metric, path, schema.retentionStr, schema.name,
				aggrStr, xfilesf, aggrName)

			// whisper.Create doesn't mkdir, so let's do it ourself
			lastslash := strings.LastIndex(path, "/")
			if lastslash != -1 {
				os.MkdirAll(path[0:lastslash], os.ModeDir|os.ModePerm)
			}
			w, err = whisper.Create(path, schema.retentions, aggrType, xfilesf)
			if err != nil {
				logger.Logf("failed to create new whisper file %s: %s",
					path, err.Error())
				continue
			}
		}

		w.Update(value, int(ts))
		w.Close()

		Metrics.MetricsReceived.Add(1)
	}
}

func listenAndServe(listen string, schemas []*StorageSchema, aggrs []*StorageAggregation) {
	l, err := net.Listen("tcp", listen)
	if err != nil {
		logger.Logf("failed to listen on %s: %s", listen, err.Error())
		os.Exit(1)
	}
	defer l.Close()
	for {
		conn, err := l.Accept()
		if err != nil {
			logger.Logf("failed to accept connection: %s", err.Error())
			continue
		}
		go handleConnection(conn, schemas, aggrs)
	}
}

type StorageSchema struct {
	name         string
	pattern      *regexp.Regexp
	retentionStr string
	retentions   whisper.Retentions
}

func readStorageSchemas(file string) ([]*StorageSchema, error) {
	config, err := cfg.Read(file)
	if err != nil {
		return nil, err
	}

	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	var ret []*StorageSchema
	for _, s := range sections {
		var sschema StorageSchema
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		sschema.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if sschema.name == "" {
			continue
		}
		sschema.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logger.Logf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), sschema.name, err.Error())
			continue
		}
		sschema.retentionStr = s.ValueOf("retentions")
		sschema.retentions, err = whisper.ParseRetentionDefs(sschema.retentionStr)
		logger.Debugf("adding schema [%s] pattern = %s retentions = %s",
			sschema.name, s.ValueOf("pattern"), sschema.retentionStr)

		ret = append(ret, &sschema)
	}

	return ret, nil
}

type StorageAggregation struct {
	name                 string
	pattern              *regexp.Regexp
	xFilesFactor         float64
	aggregationMethodStr string
	aggregationMethod    whisper.AggregationMethod
}

func readStorageAggregations(file string) ([]*StorageAggregation, error) {
	config, err := cfg.Read(file)
	if err != nil {
		return nil, err
	}

	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	var ret []*StorageAggregation
	for _, s := range sections {
		var saggr StorageAggregation
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		saggr.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if saggr.name == "" {
			continue
		}
		saggr.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logger.Logf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), saggr.name, err.Error())
			continue
		}
		saggr.xFilesFactor, err = strconv.ParseFloat(s.ValueOf("xFilesFactor"), 64)
		if err != nil {
			logger.Logf("failed to parse xFilesFactor '%s' in %s: %s",
				s.ValueOf("xFilesFactor"), saggr.name, err.Error())
			continue
		}

		saggr.aggregationMethodStr = s.ValueOf("aggregationMethod")
		switch saggr.aggregationMethodStr {
		case "average", "avg":
			saggr.aggregationMethod = whisper.Average
		case "sum":
			saggr.aggregationMethod = whisper.Sum
		case "last":
			saggr.aggregationMethod = whisper.Last
		case "max":
			saggr.aggregationMethod = whisper.Max
		case "min":
			saggr.aggregationMethod = whisper.Min
		default:
			logger.Logf("unknown aggregation method '%s'",
				s.ValueOf("aggregationMethod"))
			continue
		}

		logger.Debugf("adding aggregation [%s] pattern = %s aggregationMethod = %s xFilesFactor = %f",
			saggr.name, s.ValueOf("pattern"),
			saggr.aggregationMethodStr, saggr.xFilesFactor)
		ret = append(ret, &saggr)
	}

	return ret, nil
}

func main() {
	port := flag.Int("p", 2003, "port to bind to")
	reportport := flag.Int("reportport", 8080, "port to bind http report interface to")
	verbose := flag.Bool("v", false, "enable verbose logging")
	debug := flag.Bool("vv", false, "enable more verbose (debug) logging")
	whisperdata := flag.String("w", config.WhisperData, "location where whisper files are stored")
	maxprocs := flag.Int("maxprocs", runtime.NumCPU()*80/100, "GOMAXPROCS")
	logdir := flag.String("logdir", "/var/log/carbonwriter/", "logging directory")
	schemafile := flag.String("schemafile", "/etc/carbon/storage-schemas.conf", "storage-schemas.conf location")
	aggrfile := flag.String("aggrfile", "/etc/carbon/storage-aggregation.conf", "storage-aggregation.conf location")
	logtostdout := flag.Bool("stdout", false, "log also to stdout")

	flag.Parse()

	mlog.SetOutput(*logdir, "carbonwriter", *logtostdout)

	expvar.NewString("BuildVersion").Set(BuildVersion)
	log.Println("starting carbonwriter", BuildVersion)

	loglevel := mlog.Normal
	if *verbose {
		loglevel = mlog.Debug
	}
	if *debug {
		loglevel = mlog.Trace
	}

	logger = mlog.Level(loglevel)

	schemas, err := readStorageSchemas(*schemafile)
	if err != nil {
		logger.Logf("failed to read %s: %s", *schemafile, err.Error())
		os.Exit(1)
	}

	aggrs, err := readStorageAggregations(*aggrfile)
	if err != nil {
		logger.Logf("failed to read %s: %s", *aggrfile, err.Error())
		os.Exit(1)
	}

	config.WhisperData = strings.TrimRight(*whisperdata, "/")
	logger.Logf("writing whisper files to: %s", config.WhisperData)
	logger.Logf("reading storage schemas from: %s", *schemafile)
	logger.Logf("reading aggregation rules from: %s", *aggrfile)

	runtime.GOMAXPROCS(*maxprocs)
	logger.Logf("set GOMAXPROCS=%d", *maxprocs)

	httputil.PublishTrackedConnections("httptrack")

	// nothing in the config? check the environment
	if config.GraphiteHost == "" {
		if host := os.Getenv("GRAPHITEHOST") + ":" + os.Getenv("GRAPHITEPORT"); host != ":" {
			config.GraphiteHost = host
		}
	}

	// only register g2g if we have a graphite host
	if config.GraphiteHost != "" {

		logger.Logf("Using graphite host %v", config.GraphiteHost)

		// register our metrics with graphite
		graphite, err := g2g.NewGraphite(config.GraphiteHost, 60*time.Second, 10*time.Second)
		if err != nil {
			log.Fatalf("unable to connect to to graphite: %v: %v", config.GraphiteHost, err)
		}

		hostname, _ := os.Hostname()
		hostname = strings.Replace(hostname, ".", "_", -1)

		graphite.Register(fmt.Sprintf("carbon.writer.%s.metricsReceived", hostname), Metrics.MetricsReceived)
	}

	listen := fmt.Sprintf(":%d", *port)
	httplisten := fmt.Sprintf(":%d", *reportport)
	logger.Logf("listening on %s, statistics via %s", listen, httplisten)
	go listenAndServe(listen, schemas, aggrs)
	err = http.ListenAndServe(httplisten, nil)
	if err != nil {
		log.Fatalf("%s", err)
	}
	logger.Logf("stopped")
}
<commit_msg>clean up dead config entries<commit_after>package main

import (
	"bufio"
	"expvar"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	cfg "github.com/alyu/configparser"
	"github.com/dgryski/carbonzipper/mlog"
	"github.com/dgryski/httputil"
	whisper "github.com/grobian/go-whisper"
	g2g "github.com/peterbourgon/g2g"
)

var config = struct {
	WhisperData  string
	GraphiteHost string
}{
	WhisperData: "/var/lib/carbon/whisper",
}

// grouped expvars for /debug/vars and graphite
var Metrics = struct {
	MetricsReceived *expvar.Int
}{
	MetricsReceived: expvar.NewInt("metrics_received"),
}

var BuildVersion string = "(development build)"

var logger mlog.Level

func handleConnection(conn net.Conn, schemas []*StorageSchema, aggrs []*StorageAggregation) {
	bufconn := bufio.NewReader(conn)

	for {
		line, err := bufconn.ReadBytes('\n')
		if err != nil {
			conn.Close()
			if err != io.EOF {
				logger.Logf("read failed: %s", err.Error())
			}
			break
		}

		elems := strings.Split(string(line), " ")
		if len(elems) != 3 {
			logger.Logf("invalid line: %s", string(line))
			continue
		}

		metric := elems[0]

		value, err := strconv.ParseFloat(elems[1], 64)
		if err != nil {
			logger.Logf("invalue value '%s': %s", elems[1], err.Error())
			continue
		}

		elems[2] = strings.TrimRight(elems[2], "\n")
		tsf, err := strconv.ParseFloat(elems[2], 64)
		if err != nil {
			logger.Logf("invalid timestamp '%s': %s", elems[2], err.Error())
			continue
		}
		ts := int(tsf)

		if metric == "" {
			logger.Logf("invalid line: %s", string(line))
			continue
		}

		if ts == 0 {
			logger.Logf("invalid timestamp (0): %s", string(line))
			continue
		}

		logger.Debugf("metric: %s, value: %f, ts: %d", metric, value, ts)

		// catch panics from whisper-go library
		defer func() {
			if r := recover(); r != nil {
				logger.Logf("recovering from whisper panic (metric: %s): %v", metric, r)
				err := conn.Close()
				if err != nil {
					logger.Logf("error while closing connection after whisper panic: %v", err)
				}
			}
		}()

		// do what we want to do
		path := config.WhisperData + "/" + strings.Replace(metric, ".", "/", -1) + ".wsp"
		w, err := whisper.Open(path)
		if err != nil {
			var schema *StorageSchema = nil
			for _, s := range schemas {
				if s.pattern.MatchString(metric) {
					schema = s
					break
				}
			}
			if schema == nil {
				logger.Logf("no storage schema defined for %s", metric)
				continue
			}
			logger.Debugf("%s: found schema: %s", metric, schema.name)

			var aggr *StorageAggregation = nil
			for _, a := range aggrs {
				if a.pattern.MatchString(metric) {
					aggr = a
					break
				}
			}

			// http://graphite.readthedocs.org/en/latest/config-carbon.html#storage-aggregation-conf
			aggrName := "(default)"
			aggrStr := "average"
			aggrType := whisper.Average
			xfilesf := float32(0.5)
			if aggr != nil {
				aggrName = aggr.name
				aggrStr = aggr.aggregationMethodStr
				aggrType = aggr.aggregationMethod
				xfilesf = float32(aggr.xFilesFactor)
			}

			logger.Logf("creating %s: %s, retention: %s (section %s), aggregationMethod: %s, xFilesFactor: %f (section %s)",
				metric, path, schema.retentionStr, schema.name,
				aggrStr, xfilesf, aggrName)

			// whisper.Create doesn't mkdir, so let's do it ourself
			lastslash := strings.LastIndex(path, "/")
			if lastslash != -1 {
				os.MkdirAll(path[0:lastslash], os.ModeDir|os.ModePerm)
			}
			w, err = whisper.Create(path, schema.retentions, aggrType, xfilesf)
			if err != nil {
				logger.Logf("failed to create new whisper file %s: %s",
					path, err.Error())
				continue
			}
		}

		w.Update(value, int(ts))
		w.Close()

		Metrics.MetricsReceived.Add(1)
	}
}

func listenAndServe(listen string, schemas []*StorageSchema, aggrs []*StorageAggregation) {
	l, err := net.Listen("tcp", listen)
	if err != nil {
		logger.Logf("failed to listen on %s: %s", listen, err.Error())
		os.Exit(1)
	}
	defer l.Close()
	for {
		conn, err := l.Accept()
		if err != nil {
			logger.Logf("failed to accept connection: %s", err.Error())
			continue
		}
		go handleConnection(conn, schemas, aggrs)
	}
}

type StorageSchema struct {
	name         string
	pattern      *regexp.Regexp
	retentionStr string
	retentions   whisper.Retentions
}

func readStorageSchemas(file string) ([]*StorageSchema, error) {
	config, err := cfg.Read(file)
	if err != nil {
		return nil, err
	}

	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	var ret []*StorageSchema
	for _, s := range sections {
		var sschema StorageSchema
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		sschema.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if sschema.name == "" {
			continue
		}
		sschema.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logger.Logf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), sschema.name, err.Error())
			continue
		}
		sschema.retentionStr = s.ValueOf("retentions")
		sschema.retentions, err = whisper.ParseRetentionDefs(sschema.retentionStr)
		logger.Debugf("adding schema [%s] pattern = %s retentions = %s",
			sschema.name, s.ValueOf("pattern"), sschema.retentionStr)

		ret = append(ret, &sschema)
	}

	return ret, nil
}

type StorageAggregation struct {
	name                 string
	pattern              *regexp.Regexp
	xFilesFactor         float64
	aggregationMethodStr string
	aggregationMethod    whisper.AggregationMethod
}

func readStorageAggregations(file string) ([]*StorageAggregation, error) {
	config, err := cfg.Read(file)
	if err != nil {
		return nil, err
	}

	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	var ret []*StorageAggregation
	for _, s := range sections {
		var saggr StorageAggregation
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		saggr.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if saggr.name == "" {
			continue
		}
		saggr.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logger.Logf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), saggr.name, err.Error())
			continue
		}
		saggr.xFilesFactor, err = strconv.ParseFloat(s.ValueOf("xFilesFactor"), 64)
		if err != nil {
			logger.Logf("failed to parse xFilesFactor '%s' in %s: %s",
				s.ValueOf("xFilesFactor"), saggr.name, err.Error())
			continue
		}

		saggr.aggregationMethodStr = s.ValueOf("aggregationMethod")
		switch saggr.aggregationMethodStr {
		case "average", "avg":
			saggr.aggregationMethod = whisper.Average
		case "sum":
			saggr.aggregationMethod = whisper.Sum
		case "last":
			saggr.aggregationMethod = whisper.Last
		case "max":
			saggr.aggregationMethod = whisper.Max
		case "min":
			saggr.aggregationMethod = whisper.Min
		default:
			logger.Logf("unknown aggregation method '%s'",
				s.ValueOf("aggregationMethod"))
			continue
		}

		logger.Debugf("adding aggregation [%s] pattern = %s aggregationMethod = %s xFilesFactor = %f",
			saggr.name, s.ValueOf("pattern"),
			saggr.aggregationMethodStr, saggr.xFilesFactor)
		ret = append(ret, &saggr)
	}

	return ret, nil
}

func main() {
	port := flag.Int("p", 2003, "port to bind to")
	reportport := flag.Int("reportport", 8080, "port to bind http report interface to")
	verbose := flag.Bool("v", false, "enable verbose logging")
	debug := flag.Bool("vv", false, "enable more verbose (debug) logging")
	whisperdata := flag.String("w", config.WhisperData, "location where whisper files are stored")
	maxprocs := flag.Int("maxprocs", runtime.NumCPU()*80/100, "GOMAXPROCS")
	logdir := flag.String("logdir", "/var/log/carbonwriter/", "logging directory")
	schemafile := flag.String("schemafile", "/etc/carbon/storage-schemas.conf", "storage-schemas.conf location")
	aggrfile := flag.String("aggrfile", "/etc/carbon/storage-aggregation.conf", "storage-aggregation.conf location")
	logtostdout := flag.Bool("stdout", false, "log also to stdout")

	flag.Parse()

	mlog.SetOutput(*logdir, "carbonwriter", *logtostdout)

	expvar.NewString("BuildVersion").Set(BuildVersion)
	log.Println("starting carbonwriter", BuildVersion)

	loglevel := mlog.Normal
	if *verbose {
		loglevel = mlog.Debug
	}
	if *debug {
		loglevel = mlog.Trace
	}

	logger = mlog.Level(loglevel)

	schemas, err := readStorageSchemas(*schemafile)
	if err != nil {
		logger.Logf("failed to read %s: %s", *schemafile, err.Error())
		os.Exit(1)
	}

	aggrs, err := readStorageAggregations(*aggrfile)
	if err != nil {
		logger.Logf("failed to read %s: %s", *aggrfile, err.Error())
		os.Exit(1)
	}

	config.WhisperData = strings.TrimRight(*whisperdata, "/")
	logger.Logf("writing whisper files to: %s", config.WhisperData)
	logger.Logf("reading storage schemas from: %s", *schemafile)
	logger.Logf("reading aggregation rules from: %s", *aggrfile)

	runtime.GOMAXPROCS(*maxprocs)
	logger.Logf("set GOMAXPROCS=%d", *maxprocs)

	httputil.PublishTrackedConnections("httptrack")

	// nothing in the config? check the environment
	if config.GraphiteHost == "" {
		if host := os.Getenv("GRAPHITEHOST") + ":" + os.Getenv("GRAPHITEPORT"); host != ":" {
			config.GraphiteHost = host
		}
	}

	// only register g2g if we have a graphite host
	if config.GraphiteHost != "" {

		logger.Logf("Using graphite host %v", config.GraphiteHost)

		// register our metrics with graphite
		graphite, err := g2g.NewGraphite(config.GraphiteHost, 60*time.Second, 10*time.Second)
		if err != nil {
			log.Fatalf("unable to connect to to graphite: %v: %v", config.GraphiteHost, err)
		}

		hostname, _ := os.Hostname()
		hostname = strings.Replace(hostname, ".", "_", -1)

		graphite.Register(fmt.Sprintf("carbon.writer.%s.metricsReceived", hostname), Metrics.MetricsReceived)
	}

	listen := fmt.Sprintf(":%d", *port)
	httplisten := fmt.Sprintf(":%d", *reportport)
	logger.Logf("listening on %s, statistics via %s", listen, httplisten)
	go listenAndServe(listen, schemas, aggrs)
	err = http.ListenAndServe(httplisten, nil)
	if err != nil {
		log.Fatalf("%s", err)
	}
	logger.Logf("stopped")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	sparta "github.com/mweagle/Sparta"
	"github.com/mweagle/SpartaCodePipeline/pipeline"
	"github.com/spf13/cobra"
	"gopkg.in/go-playground/validator.v9"
)

// PipelineName is the name of the stack to provision that supports the pipeline
var pipelineOptions pipeline.ProvisionOptions

func init() {
	sparta.RegisterCodePipelineEnvironment("test", map[string]string{
		"MESSAGE":          "Hello Test!",
		"ENVIRONMENT_NAME": "test",
	})
	sparta.RegisterCodePipelineEnvironment("production", map[string]string{
		"MESSAGE":          "Hello Production!",
		"ENVIRONMENT_NAME": "prod",
	})
}

// Standard AWS Lambda function
func helloSpartaWorld() (string, error) {
	messageText := os.Getenv("MESSAGE")
	if "" == messageText {
		messageText = "$MESSAGE not defined"
	}
	return messageText, nil
}

////////////////////////////////////////////////////////////////////////////////
// Add a command to provision a CI pipeline
var pipelineProvisionCommand = &cobra.Command{
	Use:   "provisionPipeline",
	Short: "Provision a CI/CD pipeline for this stack",
	RunE: func(cmd *cobra.Command, args []string) error {
		validate := validator.New()
		cliErrors := validate.Struct(&pipelineOptions)
		if cliErrors != nil {
			return cliErrors
		}
		return pipeline.Provision(&pipelineOptions)
	},
}

////////////////////////////////////////////////////////////////////////////////
// Main
func main() {
	// Register the provisionPipeline command
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.PipelineName, "pipeline", "p", "", "pipeline name")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.GithubRepo, "repo", "r", "", "GitHub Repo URL")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.GithubOAuthToken, "oauth", "o", "", "GitHub OAuth token")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.S3Bucket,
		"s3Bucket",
		"s",
		"",
		"S3 Bucket to use for Lambda source")
	pipelineProvisionCommand.PersistentFlags().BoolVarP(&pipelineOptions.Noop, "noop",
		"n",
		false,
		"Dry-run behavior only (do not perform mutations)")
	sparta.CommandLineOptions.Root.AddCommand(pipelineProvisionCommand)

	// Normal execution
	lambdaFn := sparta.HandleAWSLambda(fmt.Sprintf("HelloWorld-%s", os.Getenv("ENVIRONMENT_NAME")),
		helloSpartaWorld,
		sparta.IAMRoleDefinition{})
	var lambdaFunctions []*sparta.LambdaAWSInfo
	lambdaFunctions = append(lambdaFunctions, lambdaFn)
	err := sparta.Main("SpartaCodePipeline",
		fmt.Sprintf("SpartaCodePipeline CodePipeline example"),
		lambdaFunctions,
		nil,
		nil)

	if err != nil {
		os.Exit(1)
	}
}
<commit_msg>Create valid prop name<commit_after>package main

import (
	"fmt"
	"os"

	sparta "github.com/mweagle/Sparta"
	"github.com/mweagle/SpartaCodePipeline/pipeline"
	"github.com/spf13/cobra"
	"gopkg.in/go-playground/validator.v9"
)

// PipelineName is the name of the stack to provision that supports the pipeline
var pipelineOptions pipeline.ProvisionOptions

func init() {
	sparta.RegisterCodePipelineEnvironment("test", map[string]string{
		"MESSAGE":     "Hello Test!",
		"ENVIRONMENT": "test",
	})
	sparta.RegisterCodePipelineEnvironment("production", map[string]string{
		"MESSAGE":     "Hello Production!",
		"ENVIRONMENT": "prod",
	})
}

// Standard AWS Lambda function
func helloSpartaWorld() (string, error) {
	messageText := os.Getenv("MESSAGE")
	if "" == messageText {
		messageText = "$MESSAGE not defined"
	}
	return messageText, nil
}

////////////////////////////////////////////////////////////////////////////////
// Add a command to provision a CI pipeline
var pipelineProvisionCommand = &cobra.Command{
	Use:   "provisionPipeline",
	Short: "Provision a CI/CD pipeline for this stack",
	RunE: func(cmd *cobra.Command, args []string) error {
		validate := validator.New()
		cliErrors := validate.Struct(&pipelineOptions)
		if cliErrors != nil {
			return cliErrors
		}
		return pipeline.Provision(&pipelineOptions)
	},
}

////////////////////////////////////////////////////////////////////////////////
// Main
func main() {
	// Register the provisionPipeline command
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.PipelineName, "pipeline", "p", "", "pipeline name")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.GithubRepo, "repo", "r", "", "GitHub Repo URL")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.GithubOAuthToken, "oauth", "o", "", "GitHub OAuth token")
	pipelineProvisionCommand.PersistentFlags().StringVarP(&pipelineOptions.S3Bucket,
		"s3Bucket",
		"s",
		"",
		"S3 Bucket to use for Lambda source")
	pipelineProvisionCommand.PersistentFlags().BoolVarP(&pipelineOptions.Noop, "noop",
		"n",
		false,
		"Dry-run behavior only (do not perform mutations)")
	sparta.CommandLineOptions.Root.AddCommand(pipelineProvisionCommand)

	// Normal execution
	lambdaFn := sparta.HandleAWSLambda(fmt.Sprintf("HelloWorld-%s", os.Getenv("ENVIRONMENT")),
		helloSpartaWorld,
		sparta.IAMRoleDefinition{})
	var lambdaFunctions []*sparta.LambdaAWSInfo
	lambdaFunctions = append(lambdaFunctions, lambdaFn)
	err := sparta.Main("SpartaCodePipeline",
		fmt.Sprintf("SpartaCodePipeline CodePipeline example"),
		lambdaFunctions,
		nil,
		nil)

	if err != nil {
		os.Exit(1)
	}
}
<|endoftext|>