<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/alexflint/go-arg"
	"github.com/brentp/gargs/process"
	"github.com/fatih/color"
	isatty "github.com/mattn/go-isatty"
	"github.com/valyala/fasttemplate"
)

// Version is the current version
const Version = "0.3.6"

// ExitCode is the highest exit code seen in any command
var ExitCode = 0

// Params are the user-specified command-line arguments
type Params struct {
	Procs       int      `arg:"-p,help:number of processes to use."`
	Nlines      int      `arg:"-n,help:number of lines to consume for each command. -s and -n are mutually exclusive."`
	Retry       int      `arg:"-r,help:number of times to retry a command if it fails (default is 0)."`
	Ordered     bool     `arg:"-o,help:keep output in order of input."`
	Sep         string   `arg:"-s,help:regular expression split line with to fill multiple template spots default is not to split. -s and -n are mutually exclusive."`
	Verbose     bool     `arg:"-v,help:print commands to stderr as they are executed."`
	StopOnError bool     `arg:"-s,--stop-on-error,help:stop execution on any error. default is to report errors and continue execution."`
	DryRun      bool     `arg:"-d,--dry-run,help:print (but do not run) the commands."`
	Log         string   `arg:"-l,--log,help:file to log commands. Successful commands are prefixed with '#'."`
	Command     string   `arg:"positional,required,help:command to execute."`
	log         *os.File `arg:"-"`
}

// Version string for go-args
func (p Params) Version() string {
	return "gargs " + Version
}

// isStdin checks if we are getting data from stdin.
func isStdin() bool {
	// http://stackoverflow.com/a/26567513
	stat, err := os.Stdin.Stat()
	if err != nil {
		return false
	}
	return (stat.Mode() & os.ModeCharDevice) == 0
}

func main() {
	args := Params{Procs: 1, Nlines: 1}
	p := arg.MustParse(&args)
	if args.Sep != "" && args.Nlines > 1 {
		p.Fail("must specify either sep (-s) or n-lines (-n), not both")
	}
	// if neither is specified then we default to whitespace
	if args.Nlines == 1 && args.Sep == "" {
		args.Sep = "\\s+"
	}
	if !isStdin() {
		fmt.Fprintln(os.Stderr, color.RedString("ERROR: expecting input on STDIN"))
		os.Exit(255)
	}
	if args.Log != "" {
		var err error
		args.log, err = os.Create(args.Log)
		check(err)
	}
	runtime.GOMAXPROCS(args.Procs)
	run(args)
	os.Exit(ExitCode)
}

func check(e error) {
	if e != nil {
		log.Fatal(e)
	}
}

func handleCommand(args *Params, cmd string, ch chan string) {
	if args.DryRun {
		fmt.Fprintf(os.Stdout, "%s\n", cmd)
		return
	}
	ch <- cmd
}

func fillTmplMap(toks []string, line string) map[string]interface{} {
	m := make(map[string]interface{}, 5)
	if toks != nil {
		for i, t := range toks {
			m[strconv.FormatInt(int64(i), 10)] = t
		}
	}
	m["Line"] = line
	return m
}

func getScanner() *bufio.Scanner {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Buffer(make([]byte, 0, 16384), 5e9)
	return scanner
}

func genCommands(args *Params, tmpl *fasttemplate.Template) <-chan string {
	ch := make(chan string)
	var resep *regexp.Regexp
	if args.Sep != "" {
		resep = regexp.MustCompile(args.Sep)
	}

	scanner := getScanner()
	go func() {
		var lines []string
		if resep == nil {
			lines = make([]string, 0, args.Nlines)
		}
		var buf bytes.Buffer
		for scanner.Scan() {
			buf.Reset()
			line := scanner.Text()
			serr := scanner.Err()
			if serr == nil || (serr == io.EOF && len(line) > 0) {
				if resep != nil {
					toks := resep.Split(line, -1)
					targs := fillTmplMap(toks, line)
					_, err := tmpl.Execute(&buf, targs)
					check(err)
					handleCommand(args, buf.String(), ch)
				} else {
					lines = append(lines, line)
				}
			} else {
				if serr == io.EOF {
					break
				}
				log.Fatal(serr)
			}
			if len(lines) >= args.Nlines {
				targs := fillTmplMap(lines, strings.Join(lines, " "))
				_, err := tmpl.Execute(&buf, targs)
				check(err)
				lines = lines[:0]
				handleCommand(args, buf.String(), ch)
			}
		}
		if len(lines) > 0 {
			targs := fillTmplMap(lines, strings.Join(lines, " "))
			_, err := tmpl.Execute(&buf, targs)
			check(err)
			handleCommand(args, buf.String(), ch)
		}
		close(ch)
	}()
	return ch
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func init() {
	color.NoColor = !isatty.IsTerminal(os.Stderr.Fd())
}

func run(args Params) {

	tmpl := makeCommandTmpl(args.Command)
	cmds := genCommands(&args, tmpl)

	stdout := bufio.NewWriter(os.Stdout)
	defer stdout.Flush()

	cancel := make(chan bool)
	defer close(cancel)
	fails := 0

	// flush stdout every 2 seconds.
	last := time.Now().Add(2 * time.Second)
	opts := process.Options{Retries: args.Retry, Ordered: args.Ordered}
	for p := range process.Runner(cmds, cancel, &opts) {

		if ex := p.ExitCode(); ex != 0 {
			c := color.New(color.BgRed).Add(color.Bold)
			fmt.Fprintf(os.Stderr, "%s\n", c.SprintFunc()(fmt.Sprintf("ERROR with command: %s", p)))
			ExitCode = max(ExitCode, ex)
			fails++
			if args.StopOnError {
				break
			}
		}
		if args.Verbose {
			fmt.Fprintf(os.Stderr, "%s\n", p)
		}
		_, err := io.Copy(stdout, p)
		check(err)

		p.Cleanup()
		if t := time.Now(); t.After(last) {
			stdout.Flush()
			last = t.Add(2 * time.Second)
		}
		if args.log != nil {
			// if no error prefix the command with '#'
			if p.ExitCode() == 0 {
				args.log.WriteString("# " + strings.Replace(p.CmdStr, "\n", "\n# ", -1) + "\n")
			} else {
				args.log.WriteString(p.CmdStr + "\n")
			}
			stdout.Flush()
		}
	}
	stdout.Flush()
	if ExitCode == 0 && args.log != nil {
		args.log.WriteString("# SUCCESS\n")
	} else if args.log != nil {
		fmt.Fprintf(args.log, "# FAILED %d commands\n", fails)
	}

}

func makeCommandTmpl(cmd string) *fasttemplate.Template {
	v := strings.Replace(cmd, "{}", "{Line}", -1)
	return fasttemplate.New(v, "{", "}")
}
<commit_msg>re-order and simplify help.<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/alexflint/go-arg"
	"github.com/brentp/gargs/process"
	"github.com/fatih/color"
	isatty "github.com/mattn/go-isatty"
	"github.com/valyala/fasttemplate"
)

// Version is the current version
const Version = "0.3.6"

// ExitCode is the highest exit code seen in any command
var ExitCode = 0

// Params are the user-specified command-line arguments
type Params struct {
	Procs       int      `arg:"-p,help:number of processes to use."`
	Sep         string   `arg:"-s,help:regex to split line to fill multiple template place-holders."`
	Nlines      int      `arg:"-n,help:lines to consume for each command. -s and -n are mutually exclusive."`
	Retry       int      `arg:"-r,help:times to retry a command if it fails (default is 0)."`
	Ordered     bool     `arg:"-o,help:keep output in order of input."`
	Verbose     bool     `arg:"-v,help:print commands to stderr as they are executed."`
	StopOnError bool     `arg:"-s,--stop-on-error,help:stop all processes on any error."`
	DryRun      bool     `arg:"-d,--dry-run,help:print (but do not run) the commands."`
	Log         string   `arg:"-l,--log,help:file to log commands. Successful commands are prefixed with '#'."`
	Command     string   `arg:"positional,required,help:command to execute."`
	log         *os.File `arg:"-"`
}

// Version string for go-args
func (p Params) Version() string {
	return "gargs " + Version
}

// isStdin checks if we are getting data from stdin.
func isStdin() bool {
	// http://stackoverflow.com/a/26567513
	stat, err := os.Stdin.Stat()
	if err != nil {
		return false
	}
	return (stat.Mode() & os.ModeCharDevice) == 0
}

func main() {
	args := Params{Procs: 1, Nlines: 1}
	p := arg.MustParse(&args)
	if args.Sep != "" && args.Nlines > 1 {
		p.Fail("must specify either sep (-s) or n-lines (-n), not both")
	}
	// if neither is specified then we default to whitespace
	if args.Nlines == 1 && args.Sep == "" {
		args.Sep = "\\s+"
	}
	if !isStdin() {
		fmt.Fprintln(os.Stderr, color.RedString("ERROR: expecting input on STDIN"))
		os.Exit(255)
	}
	if args.Log != "" {
		var err error
		args.log, err = os.Create(args.Log)
		check(err)
	}
	runtime.GOMAXPROCS(args.Procs)
	run(args)
	os.Exit(ExitCode)
}

func check(e error) {
	if e != nil {
		log.Fatal(e)
	}
}

func handleCommand(args *Params, cmd string, ch chan string) {
	if args.DryRun {
		fmt.Fprintf(os.Stdout, "%s\n", cmd)
		return
	}
	ch <- cmd
}

func fillTmplMap(toks []string, line string) map[string]interface{} {
	m := make(map[string]interface{}, 5)
	if toks != nil {
		for i, t := range toks {
			m[strconv.FormatInt(int64(i), 10)] = t
		}
	}
	m["Line"] = line
	return m
}

func getScanner() *bufio.Scanner {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Buffer(make([]byte, 0, 16384), 5e9)
	return scanner
}

func genCommands(args *Params, tmpl *fasttemplate.Template) <-chan string {
	ch := make(chan string)
	var resep *regexp.Regexp
	if args.Sep != "" {
		resep = regexp.MustCompile(args.Sep)
	}

	scanner := getScanner()
	go func() {
		var lines []string
		if resep == nil {
			lines = make([]string, 0, args.Nlines)
		}
		var buf bytes.Buffer
		for scanner.Scan() {
			buf.Reset()
			line := scanner.Text()
			serr := scanner.Err()
			if serr == nil || (serr == io.EOF && len(line) > 0) {
				if resep != nil {
					toks := resep.Split(line, -1)
					targs := fillTmplMap(toks, line)
					_, err := tmpl.Execute(&buf, targs)
					check(err)
					handleCommand(args, buf.String(), ch)
				} else {
					lines = append(lines, line)
				}
			} else {
				if serr == io.EOF {
					break
				}
				log.Fatal(serr)
			}
			if len(lines) >= args.Nlines {
				targs := fillTmplMap(lines, strings.Join(lines, " "))
				_, err := tmpl.Execute(&buf, targs)
				check(err)
				lines = lines[:0]
				handleCommand(args, buf.String(), ch)
			}
		}
		if len(lines) > 0 {
			targs := fillTmplMap(lines, strings.Join(lines, " "))
			_, err := tmpl.Execute(&buf, targs)
			check(err)
			handleCommand(args, buf.String(), ch)
		}
		close(ch)
	}()
	return ch
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func init() {
	color.NoColor = !isatty.IsTerminal(os.Stderr.Fd())
}

func run(args Params) {

	tmpl := makeCommandTmpl(args.Command)
	cmds := genCommands(&args, tmpl)

	stdout := bufio.NewWriter(os.Stdout)
	defer stdout.Flush()

	cancel := make(chan bool)
	defer close(cancel)
	fails := 0

	// flush stdout every 2 seconds.
	last := time.Now().Add(2 * time.Second)
	opts := process.Options{Retries: args.Retry, Ordered: args.Ordered}
	for p := range process.Runner(cmds, cancel, &opts) {

		if ex := p.ExitCode(); ex != 0 {
			c := color.New(color.BgRed).Add(color.Bold)
			fmt.Fprintf(os.Stderr, "%s\n", c.SprintFunc()(fmt.Sprintf("ERROR with command: %s", p)))
			ExitCode = max(ExitCode, ex)
			fails++
			if args.StopOnError {
				break
			}
		}
		if args.Verbose {
			fmt.Fprintf(os.Stderr, "%s\n", p)
		}
		_, err := io.Copy(stdout, p)
		check(err)

		p.Cleanup()
		if t := time.Now(); t.After(last) {
			stdout.Flush()
			last = t.Add(2 * time.Second)
		}
		if args.log != nil {
			// if no error prefix the command with '#'
			if p.ExitCode() == 0 {
				args.log.WriteString("# " + strings.Replace(p.CmdStr, "\n", "\n# ", -1) + "\n")
			} else {
				args.log.WriteString(p.CmdStr + "\n")
			}
			stdout.Flush()
		}
	}
	stdout.Flush()
	if ExitCode == 0 && args.log != nil {
		args.log.WriteString("# SUCCESS\n")
	} else if args.log != nil {
		fmt.Fprintf(args.log, "# FAILED %d commands\n", fails)
	}

}

func makeCommandTmpl(cmd string) *fasttemplate.Template {
	v := strings.Replace(cmd, "{}", "{Line}", -1)
	return fasttemplate.New(v, "{", "}")
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"html"
	"io"
	"os"
	"regexp"
	"time"

	rss "github.com/jteeuwen/go-pkg-rss"
	"github.com/justincampbell/timeago"
)

const usage = `lastpost v1.0.0 - github.com/justincampbell/lastpost
usage: lastpost URL`

func main() {
	flag.Parse()
	url := flag.Arg(0)

	if url == "" {
		fmt.Println(usage)
		os.Exit(1)
	}

	feed := rss.New(5, true, nil, itemHandler)
	if err := feed.Fetch(url, charsetReader); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func itemHandler(_ *rss.Feed, _ *rss.Channel, items []*rss.Item) {
	item := items[0]
	c, err := extractContent(item)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	c = formatContent(c)

	t, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", item.PubDate)
	if err == nil {
		fmt.Printf("%s (%s)\n\n%s", item.Title, timeago.FromTime(t), c)
	} else {
		fmt.Printf("%s\n\n%s", item.Title, c)
	}

}

func charsetReader(_ string, r io.Reader) (io.Reader, error) {
	return r, nil
}

func extractContent(item *rss.Item) (string, error) {
	if item == nil {
		return "", errors.New("No item")

	}

	if item.Content != nil && item.Content.Text != "" {
		return item.Content.Text, nil
	}

	if item.Description != "" {
		return item.Description, nil
	}

	return "", errors.New("No content or description found")
}

func formatContent(c string) string {
	c = html.UnescapeString(c)
	c = fmt.Sprintf("\n%s", c)

	for _, pair := range [][]string{
		[]string{" ", " "},
		[]string{"…", "..."},
		[]string{"–", "-"},
		[]string{"×", "×"},
		[]string{"</\\w+(?:.*)>", "\n"},
		[]string{"<\\w+(?:.*)>", ""},
		[]string{"\n+", "\n"},
		[]string{"\\s\\s+", " "},
		[]string{"^\n*", ""},
		[]string{"\n*$", "\n"},
	} {
		re, replacement := pair[0], pair[1]
		c = regexp.MustCompile(re).ReplaceAllString(c, replacement)
	}

	return c
}
<commit_msg>Remove trailing spaces<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"html"
	"io"
	"os"
	"regexp"
	"time"

	rss "github.com/jteeuwen/go-pkg-rss"
	"github.com/justincampbell/timeago"
)

const usage = `lastpost v1.0.0 - github.com/justincampbell/lastpost
usage: lastpost URL`

func main() {
	flag.Parse()
	url := flag.Arg(0)

	if url == "" {
		fmt.Println(usage)
		os.Exit(1)
	}

	feed := rss.New(5, true, nil, itemHandler)
	if err := feed.Fetch(url, charsetReader); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func itemHandler(_ *rss.Feed, _ *rss.Channel, items []*rss.Item) {
	item := items[0]
	c, err := extractContent(item)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	c = formatContent(c)

	t, err := time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", item.PubDate)
	if err == nil {
		fmt.Printf("%s (%s)\n\n%s", item.Title, timeago.FromTime(t), c)
	} else {
		fmt.Printf("%s\n\n%s", item.Title, c)
	}

}

func charsetReader(_ string, r io.Reader) (io.Reader, error) {
	return r, nil
}

func extractContent(item *rss.Item) (string, error) {
	if item == nil {
		return "", errors.New("No item")

	}

	if item.Content != nil && item.Content.Text != "" {
		return item.Content.Text, nil
	}

	if item.Description != "" {
		return item.Description, nil
	}

	return "", errors.New("No content or description found")
}

func formatContent(c string) string {
	c = html.UnescapeString(c)
	c = fmt.Sprintf("\n%s", c)

	for _, pair := range [][]string{
		[]string{" ", " "},
		[]string{"…", "..."},
		[]string{"–", "-"},
		[]string{"×", "×"},
		[]string{"</\\w+(?:.*)>", "\n"},
		[]string{"<\\w+(?:.*)>", ""},
		[]string{"\n+", "\n"},
		[]string{"\\s\\s+", " "},
		[]string{"^\n*", ""},
		[]string{"\n*$", "\n"},
		[]string{"\\s+\n", "\n"},
	} {
		re, replacement := pair[0], pair[1]
		c = regexp.MustCompile(re).ReplaceAllString(c, replacement)
	}

	return c
}
<|endoftext|>


<commit_before>package main
import (
	"fmt"
	"net/http"
	"encoding/json"
	"time"
    "bytes"
	"os/exec"
    "strings"
    "strconv"
)

type ParamToAgent struct {
    Metric      string      `json:"metric"`
    Endpoint    string      `json:"endpoint"`
    Value       interface{} `json:"value"`
    CounterType string      `json:"counterType"`
    Tags        string      `json:"tags"`
    Timestamp   int64       `json:"timestamp"`
    Step        int64       `json:"step"`
}

type SamplingTarget struct {
    Address     string
    ISP         string
    Province    string
    City        string
    ServerRoom  string
}

type Statistic struct {
    Timestamp      int64

    /**
     * Value could be:
     *     Packet Loss - int
     *     Transmission Time - float64
     */
    Value          interface{}
}

func main() {
    urlPush := "http://10.20.30.40:1988/v1/push"
    //connectionID := "nqm-agent@10.20.30.40"

	var samplingTargetList []SamplingTarget
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.150.145", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.146.33", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.232.53", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.145", "Chinanet", "Zhejiang", "Wenzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.150", "Chinanet", "Zhejiang", "Wenzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.70", "Chinanet", "Zhejiang", "Wenzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.110", "ChinaTelecom", "Anhui", "Hefei", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.114", "ChinaTelecom", "Anhui", "Hefei", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.222", "ChinaTelecom", "Anhui", "Hefei", "Room-2"})

    statisticsOfPacketsSent, statisticsOfPacketsReceived, statisticsOfTransmissionTime := Probe(samplingTargetList)

    var params [] ParamToAgent
    params = append(params, FormParams("packets-sent" ,statisticsOfPacketsSent)...)
    params = append(params, FormParams("packets-received", statisticsOfPacketsReceived)...)
    params = append(params, FormParams("transmission-time", statisticsOfTransmissionTime)...)

    paramsBody, err := json.Marshal(params)
    if err != nil {
        fmt.Println(urlPush+", format body error,", err)
	}

	postReq, err := http.NewRequest("POST", urlPush, bytes.NewBuffer(paramsBody))
	postReq.Header.Set("Content-Type", "application/json; charset=UTF-8")
	postReq.Header.Set("Connection", "close")

    httpClient := &http.Client{}
    postResp, err := httpClient.Do(postReq)
	if err != nil {
		fmt.Println(urlPush+", sending post request occurs error,", err)
	}
	defer postResp.Body.Close()

    fmt.Println("URL:", urlPush)
    fmt.Println("Body:", string(paramsBody))
}

func FormParams(metric string, statistics map[SamplingTarget]Statistic) []ParamToAgent {
    var params [] ParamToAgent

    for samplingTarget, statistic := range statistics {
        endpoint := "nqm-agent-1@10.20.30.40"
        value := statistic.Value
        counterType := "GAUGE"
        tags := "target="+samplingTarget.Address+
                ",isp="+samplingTarget.ISP+
                ",province="+samplingTarget.Province+
                ",city="+samplingTarget.City+
                ",name_tag="+samplingTarget.ServerRoom
        timestamp := statistic.Timestamp
        step := int64(60)

        param := ParamToAgent{metric, endpoint, value, counterType, tags, timestamp, step}
        params = append(params, param)
    }
    return params
}

func Probe(samplingTargetList []SamplingTarget) (map[SamplingTarget]Statistic, map[SamplingTarget]Statistic, map[SamplingTarget]Statistic) {
    statisticsOfPacketsSent := make(map[SamplingTarget]Statistic)
    statisticsOfPacketsReceived := make(map[SamplingTarget]Statistic)
    statisticsOfTransmissionTime := make(map[SamplingTarget]Statistic)
    for _, samplingTarget := range samplingTargetList {
        fpingCommand := exec.Command("fping", "-p", "20", "-i", "10", "-c", "4", "-q", "-a", samplingTarget.Address)
        cmdOutput, err := fpingCommand.CombinedOutput()
        if err != nil {
            fmt.Println("error occured:")
            fmt.Printf("%s", err)
        }
        fpingResult := string(cmdOutput)
        fmt.Print(fpingResult)

        parsedFpingResult := strings.FieldsFunc(fpingResult, func(r rune) bool {
            switch r {
                case ' ', '\n', ':', '/', '%', '=', ',':
                    return true
            }
            return false
        })
        fmt.Println(parsedFpingResult)
        if len(parsedFpingResult) != 13 {
            delete(statisticsOfPacketsSent, samplingTarget)
            delete(statisticsOfPacketsReceived, samplingTarget)
            delete(statisticsOfTransmissionTime, samplingTarget)
            continue
        }
        xmt, err := strconv.Atoi(parsedFpingResult[4])
        xmtStatistic := Statistic{time.Now().Unix(), xmt}
        statisticsOfPacketsSent[samplingTarget] = xmtStatistic

        rcv, err := strconv.Atoi(parsedFpingResult[5])
        rcvStatistic := Statistic{time.Now().Unix(), rcv}
        statisticsOfPacketsReceived[samplingTarget] = rcvStatistic

        tt, err := strconv.ParseFloat(parsedFpingResult[11],64)
        ttStatistic := Statistic{time.Now().Unix(), tt}
        statisticsOfTransmissionTime[samplingTarget] = ttStatistic
    }

    return statisticsOfPacketsSent, statisticsOfPacketsReceived, statisticsOfTransmissionTime
}<commit_msg>Parallelize the fping command<commit_after>package main
import (
	"fmt"
	"net/http"
	"encoding/json"
	"time"
    "bytes"
	"os/exec"
    "strings"
    "strconv"
)

type ParamToAgent struct {
    Metric      string      `json:"metric"`
    Endpoint    string      `json:"endpoint"`
    Value       interface{} `json:"value"`
    CounterType string      `json:"counterType"`
    Tags        string      `json:"tags"`
    Timestamp   int64       `json:"timestamp"`
    Step        int64       `json:"step"`
}

type SamplingTarget struct {
    Address     string
    ISP         string
    Province    string
    City        string
    NameTag  string
}

type Statistic struct {
    Timestamp      int64

    /**
     * Value could be:
     *     Packet Loss - int
     *     Transmission Time - float64
     */
    Value          interface{}
}

func main() {
    urlPush := "http://10.20.30.40:1988/v1/push"
    //connectionID := "nqm-agent@10.20.30.40"

	var samplingTargetList []SamplingTarget
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.150.145", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.146.33", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"203.208.232.53", "ChinaTelecom", "Zhejiang", "Hangzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.145", "Chinanet", "Zhejiang", "Wenzhou", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.150", "Chinanet", "Zhejiang", "Wenzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"211.160.177.70", "Chinanet", "Zhejiang", "Wenzhou", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.110", "ChinaTelecom", "Anhui", "Hefei", "Room-1"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.114", "ChinaTelecom", "Anhui", "Hefei", "Room-2"})
    samplingTargetList = append(samplingTargetList, SamplingTarget{"61.190.194.222", "ChinaTelecom", "Anhui", "Hefei", "Room-2"})

    statisticsOfPacketsSent, statisticsOfPacketsReceived, statisticsOfTransmissionTime := Probe(samplingTargetList)

    var params [] ParamToAgent
    params = append(params, FormParams("packets-sent" ,statisticsOfPacketsSent)...)
    params = append(params, FormParams("packets-received", statisticsOfPacketsReceived)...)
    params = append(params, FormParams("transmission-time", statisticsOfTransmissionTime)...)

    paramsBody, err := json.Marshal(params)
    if err != nil {
        fmt.Println(urlPush+", format body error,", err)
	}

	postReq, err := http.NewRequest("POST", urlPush, bytes.NewBuffer(paramsBody))
	postReq.Header.Set("Content-Type", "application/json; charset=UTF-8")
	postReq.Header.Set("Connection", "close")

    httpClient := &http.Client{}
    postResp, err := httpClient.Do(postReq)
	if err != nil {
		fmt.Println(urlPush+", sending post request occurs error,", err)
	}
	defer postResp.Body.Close()

    fmt.Println("URL:", urlPush)
    fmt.Println("Body:", string(paramsBody))
}

func FormParams(metric string, statistics map[SamplingTarget]Statistic) []ParamToAgent {
    var params [] ParamToAgent

    for samplingTarget, statistic := range statistics {
        endpoint := "nqm-agent-1@10.20.30.40"
        value := statistic.Value
        counterType := "GAUGE"
        tags := "target="+samplingTarget.Address+
                ",isp="+samplingTarget.ISP+
                ",province="+samplingTarget.Province+
                ",city="+samplingTarget.City+
                ",name_tag="+samplingTarget.NameTag
        timestamp := statistic.Timestamp
        step := int64(60)

        param := ParamToAgent{metric, endpoint, value, counterType, tags, timestamp, step}
        params = append(params, param)
    }
    return params
}

func Probe(samplingTargetList []SamplingTarget) (map[SamplingTarget]Statistic, map[SamplingTarget]Statistic, map[SamplingTarget]Statistic) {
    statisticsOfPacketsSent := make(map[SamplingTarget]Statistic)
    statisticsOfPacketsReceived := make(map[SamplingTarget]Statistic)
    statisticsOfTransmissionTime := make(map[SamplingTarget]Statistic)
    var targetAddressList []string
    for _, samplingTarget := range samplingTargetList {
        targetAddressList = append(targetAddressList, samplingTarget.Address)
    }
    commandTemplate := []string{"-p", "20", "-i", "10", "-c", "100", "-q", "-a"}
    commandTemplate = append(commandTemplate, targetAddressList...)
    fpingCommand := exec.Command("fping", commandTemplate...)
    cmdOutput, err := fpingCommand.CombinedOutput()
    if err != nil {
        fmt.Println("error occured:")
        fmt.Printf("%s", err)
    }
    fpingResults := strings.Split(string(cmdOutput),"\n")
    fpingResults = fpingResults[:len(fpingResults)-1]
    for i, result := range fpingResults {
        fmt.Print("Result ", i+1, ": ")
        fmt.Println(result)
    }
    for i, fpingResult := range fpingResults {
        parsedFpingResult := strings.FieldsFunc(fpingResult, func(r rune) bool {
            switch r {
                case ' ', '\n', ':', '/', '%', '=', ',':
                    return true
            }
            return false
        })
        fmt.Println(parsedFpingResult)
        if len(parsedFpingResult) != 13 {
            delete(statisticsOfPacketsSent, samplingTargetList[i])
            delete(statisticsOfPacketsReceived, samplingTargetList[i])
            delete(statisticsOfTransmissionTime, samplingTargetList[i])
            continue
        }
        xmt, err := strconv.Atoi(parsedFpingResult[4])
        if err != nil {
            fmt.Println("error occured:")
            fmt.Printf("%s", err)
        }
        xmtStatistic := Statistic{time.Now().Unix(), xmt}
        statisticsOfPacketsSent[samplingTargetList[i]] = xmtStatistic

        rcv, err := strconv.Atoi(parsedFpingResult[5])
        if err != nil {
            fmt.Println("error occured:")
            fmt.Printf("%s", err)
        }
        rcvStatistic := Statistic{time.Now().Unix(), rcv}
        statisticsOfPacketsReceived[samplingTargetList[i]] = rcvStatistic

        tt, err := strconv.ParseFloat(parsedFpingResult[11],64)
        if err != nil {
            fmt.Println("error occured:")
            fmt.Printf("%s", err)
        }
        ttStatistic := Statistic{time.Now().Unix(), tt}
        statisticsOfTransmissionTime[samplingTargetList[i]] = ttStatistic
    }

    return statisticsOfPacketsSent, statisticsOfPacketsReceived, statisticsOfTransmissionTime
}<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

// mostly hardcoded program settings
const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

// Keep debug global
var debugMode bool

// Simple struct for our connection
type MuckServer struct {
	name string
	host string
	port uint
	ssl  bool
}

// Simplify returning connection strings by making it the String method
func (m *MuckServer) String() string {
	s := fmt.Sprintf("%s:%d", m.host, m.port)
	return s
}

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Print("DEBUG: ")
		fmt.Println(log...)
	}
}

func checkError(err error) {
	if err != nil {
		debugLog("checkError caught", err.Error())
		s := fmt.Sprintln("fatal error", err.Error())
		panic(s)
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initArgs() MuckServer {
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	ssl := flag.Bool("ssl", false, "Enable ssl")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	p, err := strconv.Atoi(args[2])
	checkError(err)

	s := MuckServer{name: args[0], host: args[1], port: uint(p), ssl: *ssl}

	debugLog("name:", s.name)
	debugLog("host:", s.host)
	debugLog("port:", s.port)
	debugLog("SSL?:", s.ssl)

	return s
}

func getWorkingDir(main string, sub string) string {
	u, err := user.Current()
	checkError(err)
	h := u.HomeDir
	debugLog("Home directory", h)

	w := filepath.Join(h, main, sub)
	debugLog("working directory", w)
	return w
}

func setupConnection(s *MuckServer) net.Conn {
	tcpAddr, err := net.ResolveTCPAddr("tcp4", s.String())
	checkError(err)
	debugLog("server resolves to", tcpAddr)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	fmt.Println("~Connected at", getTimestamp())

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	keepalive := 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)
	return connection
}

func setupTLSConnextion(s *MuckServer) net.Conn {
	var connection net.Conn
	return connection

}

func makeFIFO(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("if you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES\n" {
			fmt.Println("Canceling. Please remove FIFO before running")
			panic("User Canceled at FIFO removal prompt")
		}
		errUn := syscall.Unlink(file)
		checkError(errUn)
		debugLog(file, "unlinked")
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	debugLog("FIFO created as", file)
	f, err := os.OpenFile(file, syscall.O_RDONLY|syscall.O_NONBLOCK, 0666)
	checkError(err)
	debugLog("FIFO opened as", f.Name())
	return f
}

func readtoConn(f *os.File, c net.Conn, quit chan bool) {
	tmpError := fmt.Sprintf("read %v: resource temporarily unavailable", f.Name())
	for {
		select {
		case <-quit:
			debugLog("readtoConn got quit, returning")
			return
		default:
			buf := make([]byte, 512)
			bi, err := f.Read(buf)
			if err != nil && err.Error() != "EOF" && err.Error() != tmpError {
				checkError(err)
			} else if bi == 0 {
				continue
			}
			debugLog(bi, "bytes read from FIFO")
			bo, err := c.Write(buf[:bi])
			checkError(err)
			debugLog(bo, "bytes written to file")
		}
	}
}

func readToFile(c net.Conn, f *os.File, quit chan bool) {
	for {
		buf := make([]byte, 512)
		bi, err := c.Read(buf)
		if err != nil {
			fmt.Println("Connection broken,", err.Error())
			quit <- true
			return
		}
		debugLog(bi, "bytes read from connection")

		bo, err := f.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func closeConnection(c net.Conn) {
	fmt.Println("~Closing connection at", getTimestamp())
	err := c.Close()
	if err != nil {
		debugLog(err.Error())
	}
	debugLog("Connection closed")
}

func closeFIFO(f *os.File) {
	n := f.Name()
	debugLog("closing and deleting FIFO", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	errU := syscall.Unlink(n)
	if errU != nil {
		debugLog(errU.Error())
	}
	debugLog(n, "closed and deleted")
}

func closeLog(f *os.File) {
	n := f.Name()
	debugLog("closing and rotating file", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	if _, err := os.Stat(n); err != nil {
		fmt.Println("out file doesn't exist? not rotating")
		return
	}
	errR := os.Rename(outFile, getTimestamp())
	if errR != nil {
		debugLog(errR.Error())
	}
	debugLog(n, "closed and rotated")
}

func main() {
	// checkError throws a panic, catch it at the end and return error to user
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("FATAL ERROR", r)
		}
	}()

	fmt.Println("~Started at", getTimestamp())
	server := initArgs()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, server.name)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	//create connection
	var connection net.Conn
	if server.ssl == true {
		connection = setupTLSConnextion(&server)
	} else {
		connection = setupConnection(&server)
	}
	defer closeConnection(connection)

	// Make the in FIFO
	in := makeFIFO(inFile)
	defer closeFIFO(in)

	// Make the out file
	out, err := os.Create(outFile)
	checkError(err)
	debugLog("Logfile created as", out.Name())
	defer closeLog(out)

	quit := make(chan bool)
	go readToFile(connection, out, quit)
	readtoConn(in, connection, quit)

	debugLog("End of main hit")
}
<commit_msg>Clean up all messaging<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

// mostly hardcoded program settings
const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

// Keep debug global
var debugMode bool

// Simple struct for our connection
type MuckServer struct {
	name string
	host string
	port uint
	ssl  bool
}

// Simplify returning connection strings by making it the String method
func (m *MuckServer) String() string {
	s := fmt.Sprintf("%s:%d", m.host, m.port)
	return s
}

func debugLog(log ...interface{}) {
	if debugMode {
		fmt.Print("DEBUG: ")
		fmt.Println(log...)
	}
}

func checkError(err error) {
	if err != nil {
		debugLog("checkError caught", err.Error())
		panic(err.Error())
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initArgs() MuckServer {
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	ssl := flag.Bool("ssl", false, "Enable ssl")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	p, err := strconv.Atoi(args[2])
	checkError(err)

	s := MuckServer{name: args[0], host: args[1], port: uint(p), ssl: *ssl}

	debugLog("name:", s.name)
	debugLog("host:", s.host)
	debugLog("port:", s.port)
	debugLog("SSL?:", s.ssl)

	return s
}

func getWorkingDir(main string, sub string) string {
	u, err := user.Current()
	checkError(err)
	h := u.HomeDir
	debugLog("home directory", h)

	w := filepath.Join(h, main, sub)
	debugLog("working directory", w)
	return w
}

func makeFIFO(file string) *os.File {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("If you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES\n" {
			fmt.Println("Canceling. Please remove FIFO before running")
			panic("User Canceled at FIFO removal prompt")
		}
		errUn := syscall.Unlink(file)
		checkError(errUn)
		debugLog(file, "unlinked")
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
	debugLog("FIFO created as", file)
	f, err := os.OpenFile(file, syscall.O_RDONLY|syscall.O_NONBLOCK, 0666)
	checkError(err)
	debugLog("FIFO opened as", f.Name())
	return f
}

func setupConnection(s *MuckServer) net.Conn {
	tcpAddr, err := net.ResolveTCPAddr("tcp4", s.String())
	checkError(err)
	debugLog("server resolves to", tcpAddr)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	debugLog("connected to Server")

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	keepalive := 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)
	return connection
}

func setupTLSConnextion(s *MuckServer) net.Conn {
	var connection net.Conn
	return connection

}

func readtoConn(f *os.File, c net.Conn, quit chan bool) {
	tmpError := fmt.Sprintf("read %v: resource temporarily unavailable", f.Name())
	for {
		select {
		case <-quit:
			debugLog("readtoConn recieved quit; returning")
			return
		default:
			buf := make([]byte, 512)
			bi, err := f.Read(buf)
			if err != nil && err.Error() != "EOF" && err.Error() != tmpError {
				checkError(err)
			} else if bi == 0 {
				continue
			}
			debugLog(bi, "bytes read from FIFO")
			bo, err := c.Write(buf[:bi])
			checkError(err)
			debugLog(bo, "bytes written to file")
		}
	}
}

func readToFile(c net.Conn, f *os.File, quit chan bool) {
	f.WriteString(fmt.Sprintf("~Connected at %v\n", getTimestamp()))
	for {
		buf := make([]byte, 512)
		bi, err := c.Read(buf)
		if err != nil {
			fmt.Println("Server disconnected with", err.Error())
			f.WriteString(fmt.Sprintf("~Connection lost at %v\n", getTimestamp()))
			quit <- true
			return
		}
		debugLog(bi, "bytes read from connection")

		bo, err := f.Write(buf[:bi])
		checkError(err)
		debugLog(bo, "bytes written to file")
	}
}

func closeConnection(c net.Conn) {
	err := c.Close()
	if err != nil {
		debugLog(err.Error())
	}
	debugLog("connection closed")
}

func closeFIFO(f *os.File) {
	n := f.Name()
	debugLog("closing and deleting FIFO", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	errU := syscall.Unlink(n)
	if errU != nil {
		debugLog(errU.Error())
	}
	debugLog(n, "closed and deleted")
}

func closeLog(f *os.File) {
	n := f.Name()
	debugLog("closing and rotating file", n)
	errC := f.Close()
	if errC != nil {
		debugLog(errC.Error())
	}
	if _, err := os.Stat(n); err != nil {
		fmt.Println(n, "file doesn't exist? Not rotating.")
		return
	}
	errR := os.Rename(outFile, getTimestamp())
	if errR != nil {
		debugLog(errR.Error())
	}
	debugLog(n, "closed and rotated")
}

func main() {
	// checkError throws a panic, catch it at the end and return error to user
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("FATAL ERROR", r)
		}
	}()

	fmt.Println("Started at", getTimestamp())
	server := initArgs()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, server.name)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	// Make the in FIFO
	in := makeFIFO(inFile)
	defer closeFIFO(in)

	// Make the out file
	out, err := os.Create(outFile)
	checkError(err)
	debugLog("logfile created as", out.Name())
	defer closeLog(out)

	//create connection
	var connection net.Conn
	if server.ssl == true {
		connection = setupTLSConnextion(&server)
	} else {
		connection = setupConnection(&server)
	}
	defer closeConnection(connection)

	quit := make(chan bool)
	go readToFile(connection, out, quit)
	readtoConn(in, connection, quit)

	fmt.Println("Quit at", getTimestamp())
	fmt.Println("Thanks for playing!")
	debugLog("end of main hit")
}
<|endoftext|>


<commit_before>// Copyright 2016, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// sshtunnel is daemon for setting up forward and reverse SSH tunnels.
//
// The daemon is started by executing sshtunnel with the path to a JSON
// configuration file. The configuration takes the following form:
//
//	{
//		"KeyFiles": ["/path/to/key.priv"],
//		"KnownHostFiles": ["/path/to/known_hosts"],
//		"Tunnels": [{
//			// Forward tunnel (locally binded socket proxies to remote target).
//			"Tunnel": "bind_address:port -> dial_address:port",
//			"Server": "user@host:port",
//		}, {
//			// Reverse tunnel (remotely binded socket proxies to local target).
//			"Tunnel": "dial_address:port <- bind_address:port",
//			"Server": "user@host:port",
//		}],
//	}
//
// See the TunnelConfig struct for more details.
package main

import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"os/user"
	"path"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/dsnet/golib/jsonutil"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/knownhosts"
)

// Version of the sshtunnel binary. May be set by linker when building.
var version string

type TunnelConfig struct {
	// LogFile is where the proxy daemon will direct its output log.
	// If the path is empty, then the server will output to os.Stderr.
	LogFile string `json:",omitempty"`

	// KeyFiles is a list of SSH private key files.
	KeyFiles []string

	// KnownHostFiles is a list of key database files for host public keys
	// in the OpenSSH known_hosts file format.
	KnownHostFiles []string

	// KeepAlive sets the keep alive settings for each SSH connection.
	// It is recommended that these values match the AliveInterval and
	// AliveCountMax parameters on the remote OpenSSH server.
	// If unset, then the default is an interval of 30s with 2 max counts.
	KeepAlive *KeepAliveConfig `json:",omitempty"`

	// Tunnels is a list of tunnels to establish.
	// The same set of SSH keys will be used to authenticate the
	// SSH connection for each server.
	Tunnels []struct {
		// Tunnel is a pair of host:port endpoints that can be configured
		// to either operate as a forward tunnel or a reverse tunnel.
		//
		// The syntax of a forward tunnel is:
		//	"bind_address:port -> dial_address:port"
		//
		// A forward tunnel opens a listening TCP socket on the
		// local side (at bind_address:port) and proxies all traffic to a
		// socket on the remote side (at dial_address:port).
		//
		// The syntax of a reverse tunnel is:
		//	"dial_address:port <- bind_address:port"
		//
		// A reverse tunnel opens a listening TCP socket on the
		// remote side (at bind_address:port) and proxies all traffic to a
		// socket on the local side (at dial_address:port).
		Tunnel string

		// Server is a remote SSH host. It has the following syntax:
		//	"user@host:port"
		//
		// If the user is missing, then it defaults to the current process user.
		// If the port is missing, then it defaults to 22.
		Server string

		// KeepAlive is a tunnel-specific setting of the global KeepAlive.
		// If unspecified, it uses the global KeepAlive settings.
		KeepAlive *KeepAliveConfig `json:",omitempty"`
	}
}

type KeepAliveConfig struct {
	// Interval is the amount of time in seconds to wait before the
	// tunnel client will send a keep-alive message to ensure some minimum
	// traffic on the SSH connection.
	Interval uint

	// CountMax is the maximum number of consecutive failed responses to
	// keep-alive messages the client is willing to tolerate before considering
	// the SSH connection as dead.
	CountMax uint
}

func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func() error) {
	var logBuf bytes.Buffer
	logger = log.New(io.MultiWriter(os.Stderr, &logBuf), "", log.Ldate|log.Ltime|log.Lshortfile)

	var hash string
	if b, _ := ioutil.ReadFile(os.Args[0]); len(b) > 0 {
		hash = fmt.Sprintf("%x", sha256.Sum256(b))
	}

	// Load configuration file.
	var config TunnelConfig
	c, err := ioutil.ReadFile(conf)
	if err != nil {
		logger.Fatalf("unable to read config: %v", err)
	}
	c, _ = jsonutil.Minify(c)
	if err := json.Unmarshal(c, &config); err != nil {
		logger.Fatalf("unable to decode config: %v", err)
	}
	for _, t := range config.Tunnels {
		if config.KeepAlive == nil && t.KeepAlive == nil {
			config.KeepAlive = &KeepAliveConfig{Interval: 30, CountMax: 2}
			break
		}
	}

	// Print the configuration.
	var b bytes.Buffer
	enc := json.NewEncoder(&b)
	enc.SetEscapeHTML(false)
	enc.SetIndent("", "\t")
	enc.Encode(struct {
		TunnelConfig
		BinaryVersion string `json:",omitempty"`
		BinarySHA256  string `json:",omitempty"`
	}{config, version, hash})
	logger.Printf("loaded config:\n%s", b.String())

	// Setup the log output.
	if config.LogFile == "" {
		logger.SetOutput(os.Stderr)
		closer = func() error { return nil }
	} else {
		f, err := os.OpenFile(config.LogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0664)
		if err != nil {
			logger.Fatalf("error opening log file: %v", err)
		}
		f.Write(logBuf.Bytes()) // Write log output prior to this point
		logger.Printf("suppress stderr logging (redirected to %s)", f.Name())
		logger.SetOutput(f)
		closer = f.Close
	}

	// Parse all of the private keys.
	var keys []ssh.Signer
	if len(config.KeyFiles) == 0 {
		logger.Fatal("no private keys specified")
	}
	for _, kf := range config.KeyFiles {
		b, err := ioutil.ReadFile(kf)
		if err != nil {
			logger.Fatalf("private key error: %v", err)
		}
		k, err := ssh.ParsePrivateKey(b)
		if err != nil {
			logger.Fatalf("private key error: %v", err)
		}
		keys = append(keys, k)
	}
	auth := []ssh.AuthMethod{ssh.PublicKeys(keys...)}

	// Parse all of the host public keys.
	if len(config.KnownHostFiles) == 0 {
		logger.Fatal("no host public keys specified")
	}
	hostKeys, err := knownhosts.New(config.KnownHostFiles...)
	if err != nil {
		logger.Fatalf("public key error: %v", err)
	}

	// Parse all of the tunnels.
	for _, t := range config.Tunnels {
		var tunn tunnel
		tt := strings.Fields(t.Tunnel)
		if len(tt) != 3 {
			logger.Fatalf("invalid tunnel syntax: %s", t.Tunnel)
		}

		// Parse for the tunnel endpoints.
		switch tt[1] {
		case "->":
			tunn.bindAddr, tunn.mode, tunn.dialAddr = tt[0], '>', tt[2]
		case "<-":
			tunn.dialAddr, tunn.mode, tunn.bindAddr = tt[0], '<', tt[2]
		default:
			logger.Fatalf("invalid tunnel syntax: %s", t.Tunnel)
		}
		for _, addr := range []string{tunn.bindAddr, tunn.dialAddr} {
			if _, _, err := net.SplitHostPort(addr); err != nil {
				logger.Fatalf("invalid endpoint: %s", addr)
			}
		}

		// Parse for the SSH target host.
		tunn.hostAddr = t.Server
		if i := strings.IndexByte(t.Server, '@'); i >= 0 {
			tunn.user = t.Server[:i]
			tunn.hostAddr = t.Server[i+1:]
		}
		if _, _, err := net.SplitHostPort(tunn.hostAddr); err != nil {
			tunn.hostAddr = net.JoinHostPort(tunn.hostAddr, "22")
		}
		if _, _, err := net.SplitHostPort(tunn.hostAddr); err != nil {
			logger.Fatalf("invalid server: %s", t.Server)
		}

		// Parse for the SSH user.
		if tunn.user == "" {
			u, err := user.Current()
			if err != nil {
				logger.Fatalf("unexpected error: %v", err)
			}
			tunn.user = u.Username
		}

		if t.KeepAlive == nil {
			tunn.keepAlive = *config.KeepAlive
		} else {
			tunn.keepAlive = *t.KeepAlive
		}
		tunn.retryInterval = 30 * time.Second
		tunn.auth = auth
		tunn.hostKeys = hostKeys
		tunn.log = logger
		tunns = append(tunns, tunn)
	}

	return tunns, logger, closer
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "Usage:\n")
		fmt.Fprintf(os.Stderr, "\t%s CONFIG_PATH\n", os.Args[0])
		os.Exit(1)
	}
	tunns, logger, closer := loadConfig(os.Args[1])
	defer closer()

	// Setup signal handler to initiate shutdown.
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		sigc := make(chan os.Signal, 1)
		signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
		logger.Printf("received %v - initiating shutdown", <-sigc)
		cancel()
	}()

	// Start a bridge for each tunnel.
	var wg sync.WaitGroup
	logger.Printf("%s starting", path.Base(os.Args[0]))
	defer logger.Printf("%s shutdown", path.Base(os.Args[0]))
	for _, t := range tunns {
		wg.Add(1)
		go t.bindTunnel(ctx, &wg)
	}
	wg.Wait()
}
<commit_msg>Use jsonfmt instead jsonutil<commit_after>// Copyright 2016, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// sshtunnel is daemon for setting up forward and reverse SSH tunnels.
//
// The daemon is started by executing sshtunnel with the path to a JSON
// configuration file. The configuration takes the following form:
//
//	{
//		"KeyFiles": ["/path/to/key.priv"],
//		"KnownHostFiles": ["/path/to/known_hosts"],
//		"Tunnels": [{
//			// Forward tunnel (locally binded socket proxies to remote target).
//			"Tunnel": "bind_address:port -> dial_address:port",
//			"Server": "user@host:port",
//		}, {
//			// Reverse tunnel (remotely binded socket proxies to local target).
//			"Tunnel": "dial_address:port <- bind_address:port",
//			"Server": "user@host:port",
//		}],
//	}
//
// See the TunnelConfig struct for more details.
package main

import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"os/user"
	"path"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/dsnet/golib/jsonfmt"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/knownhosts"
)

// Version of the sshtunnel binary. May be set by linker when building.
var version string

type TunnelConfig struct {
	// LogFile is where the proxy daemon will direct its output log.
	// If the path is empty, then the server will output to os.Stderr.
	LogFile string `json:",omitempty"`

	// KeyFiles is a list of SSH private key files.
	KeyFiles []string

	// KnownHostFiles is a list of key database files for host public keys
	// in the OpenSSH known_hosts file format.
	KnownHostFiles []string

	// KeepAlive sets the keep alive settings for each SSH connection.
	// It is recommended that these values match the AliveInterval and
	// AliveCountMax parameters on the remote OpenSSH server.
	// If unset, then the default is an interval of 30s with 2 max counts.
	KeepAlive *KeepAliveConfig `json:",omitempty"`

	// Tunnels is a list of tunnels to establish.
	// The same set of SSH keys will be used to authenticate the
	// SSH connection for each server.
	Tunnels []struct {
		// Tunnel is a pair of host:port endpoints that can be configured
		// to either operate as a forward tunnel or a reverse tunnel.
		//
		// The syntax of a forward tunnel is:
		//	"bind_address:port -> dial_address:port"
		//
		// A forward tunnel opens a listening TCP socket on the
		// local side (at bind_address:port) and proxies all traffic to a
		// socket on the remote side (at dial_address:port).
		//
		// The syntax of a reverse tunnel is:
		//	"dial_address:port <- bind_address:port"
		//
		// A reverse tunnel opens a listening TCP socket on the
		// remote side (at bind_address:port) and proxies all traffic to a
		// socket on the local side (at dial_address:port).
		Tunnel string

		// Server is a remote SSH host. It has the following syntax:
		//	"user@host:port"
		//
		// If the user is missing, then it defaults to the current process user.
		// If the port is missing, then it defaults to 22.
		Server string

		// KeepAlive is a tunnel-specific setting of the global KeepAlive.
		// If unspecified, it uses the global KeepAlive settings.
		KeepAlive *KeepAliveConfig `json:",omitempty"`
	}
}

type KeepAliveConfig struct {
	// Interval is the amount of time in seconds to wait before the
	// tunnel client will send a keep-alive message to ensure some minimum
	// traffic on the SSH connection.
	Interval uint

	// CountMax is the maximum number of consecutive failed responses to
	// keep-alive messages the client is willing to tolerate before considering
	// the SSH connection as dead.
	CountMax uint
}

func loadConfig(conf string) (tunns []tunnel, logger *log.Logger, closer func() error) {
	var logBuf bytes.Buffer
	logger = log.New(io.MultiWriter(os.Stderr, &logBuf), "", log.Ldate|log.Ltime|log.Lshortfile)

	var hash string
	if b, _ := ioutil.ReadFile(os.Args[0]); len(b) > 0 {
		hash = fmt.Sprintf("%x", sha256.Sum256(b))
	}

	// Load configuration file.
	var config TunnelConfig
	c, err := ioutil.ReadFile(conf)
	if err != nil {
		logger.Fatalf("unable to read config: %v", err)
	}
	c, _ = jsonfmt.Format(c, jsonfmt.Minify())
	if err := json.Unmarshal(c, &config); err != nil {
		logger.Fatalf("unable to decode config: %v", err)
	}
	for _, t := range config.Tunnels {
		if config.KeepAlive == nil && t.KeepAlive == nil {
			config.KeepAlive = &KeepAliveConfig{Interval: 30, CountMax: 2}
			break
		}
	}

	// Print the configuration.
	var b bytes.Buffer
	enc := json.NewEncoder(&b)
	enc.SetEscapeHTML(false)
	enc.SetIndent("", "\t")
	enc.Encode(struct {
		TunnelConfig
		BinaryVersion string `json:",omitempty"`
		BinarySHA256  string `json:",omitempty"`
	}{config, version, hash})
	logger.Printf("loaded config:\n%s", b.String())

	// Setup the log output.
	if config.LogFile == "" {
		logger.SetOutput(os.Stderr)
		closer = func() error { return nil }
	} else {
		f, err := os.OpenFile(config.LogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0664)
		if err != nil {
			logger.Fatalf("error opening log file: %v", err)
		}
		f.Write(logBuf.Bytes()) // Write log output prior to this point
		logger.Printf("suppress stderr logging (redirected to %s)", f.Name())
		logger.SetOutput(f)
		closer = f.Close
	}

	// Parse all of the private keys.
	var keys []ssh.Signer
	if len(config.KeyFiles) == 0 {
		logger.Fatal("no private keys specified")
	}
	for _, kf := range config.KeyFiles {
		b, err := ioutil.ReadFile(kf)
		if err != nil {
			logger.Fatalf("private key error: %v", err)
		}
		k, err := ssh.ParsePrivateKey(b)
		if err != nil {
			logger.Fatalf("private key error: %v", err)
		}
		keys = append(keys, k)
	}
	auth := []ssh.AuthMethod{ssh.PublicKeys(keys...)}

	// Parse all of the host public keys.
	if len(config.KnownHostFiles) == 0 {
		logger.Fatal("no host public keys specified")
	}
	hostKeys, err := knownhosts.New(config.KnownHostFiles...)
	if err != nil {
		logger.Fatalf("public key error: %v", err)
	}

	// Parse all of the tunnels.
	for _, t := range config.Tunnels {
		var tunn tunnel
		tt := strings.Fields(t.Tunnel)
		if len(tt) != 3 {
			logger.Fatalf("invalid tunnel syntax: %s", t.Tunnel)
		}

		// Parse for the tunnel endpoints.
		switch tt[1] {
		case "->":
			tunn.bindAddr, tunn.mode, tunn.dialAddr = tt[0], '>', tt[2]
		case "<-":
			tunn.dialAddr, tunn.mode, tunn.bindAddr = tt[0], '<', tt[2]
		default:
			logger.Fatalf("invalid tunnel syntax: %s", t.Tunnel)
		}
		for _, addr := range []string{tunn.bindAddr, tunn.dialAddr} {
			if _, _, err := net.SplitHostPort(addr); err != nil {
				logger.Fatalf("invalid endpoint: %s", addr)
			}
		}

		// Parse for the SSH target host.
		tunn.hostAddr = t.Server
		if i := strings.IndexByte(t.Server, '@'); i >= 0 {
			tunn.user = t.Server[:i]
			tunn.hostAddr = t.Server[i+1:]
		}
		if _, _, err := net.SplitHostPort(tunn.hostAddr); err != nil {
			tunn.hostAddr = net.JoinHostPort(tunn.hostAddr, "22")
		}
		if _, _, err := net.SplitHostPort(tunn.hostAddr); err != nil {
			logger.Fatalf("invalid server: %s", t.Server)
		}

		// Parse for the SSH user.
		if tunn.user == "" {
			u, err := user.Current()
			if err != nil {
				logger.Fatalf("unexpected error: %v", err)
			}
			tunn.user = u.Username
		}

		if t.KeepAlive == nil {
			tunn.keepAlive = *config.KeepAlive
		} else {
			tunn.keepAlive = *t.KeepAlive
		}
		tunn.retryInterval = 30 * time.Second
		tunn.auth = auth
		tunn.hostKeys = hostKeys
		tunn.log = logger
		tunns = append(tunns, tunn)
	}

	return tunns, logger, closer
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "Usage:\n")
		fmt.Fprintf(os.Stderr, "\t%s CONFIG_PATH\n", os.Args[0])
		os.Exit(1)
	}
	tunns, logger, closer := loadConfig(os.Args[1])
	defer closer()

	// Setup signal handler to initiate shutdown.
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		sigc := make(chan os.Signal, 1)
		signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
		logger.Printf("received %v - initiating shutdown", <-sigc)
		cancel()
	}()

	// Start a bridge for each tunnel.
	var wg sync.WaitGroup
	logger.Printf("%s starting", path.Base(os.Args[0]))
	defer logger.Printf("%s shutdown", path.Base(os.Args[0]))
	for _, t := range tunns {
		wg.Add(1)
		go t.bindTunnel(ctx, &wg)
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/k8s-community/github-integration/handlers"
	_ "github.com/lib/pq" // postgresql driver
	"github.com/takama/router"
	"gopkg.in/reform.v1"
	"gopkg.in/reform.v1/dialects/postgresql"
)

const (
	apiPrefix = "/api/v1"
)

// main function
func main() {
	var errors []error

	// Database settings
	dbHost, err := getFromEnv("COCKROACHDB_PUBLIC_SERVICE_HOST")
	if err != nil {
		errors = append(errors, err)
	}

	dbPort, err := getFromEnv("COCKROACHDB_PUBLIC_SERVICE_PORT")
	if err != nil {
		errors = append(errors, err)
	}

	dbUser, err := getFromEnv("COCKROACHDB_USER")
	if err != nil {
		errors = append(errors, err)
	}

	dbPass, err := getFromEnv("COCKROACHDB_PASSWORD")
	if err != nil {
		errors = append(errors, err)
	}

	dbName, err := getFromEnv("COCKROACHDB_NAME")
	if err != nil {
		errors = append(errors, err)
	}

	db, err := startupDB(dbHost, dbPort, dbUser, dbPass, dbName)
	if err != nil {
		log.Fatalf("Couldn't start up DB: %+v", err)
	}

	if len(errors) > 0 {
		log.Fatalf("Couldn't start service because required DB parameters are not set: %+v", errors)
	}

	keys := []string{
		"GITHUBINT_LOCAL_PORT", "GITHUBINT_BRANCH",
		"GITHUBINT_TOKEN", "GITHUBINT_PRIV_KEY", "GITHUBINT_INTEGRATION_ID",
		"USERMAN_BASE_URL", "CICD_BASE_URL",
	}

	h := &handlers.Handler{
		DB:      db,
		Infolog: log.New(os.Stdout, "[GITHUBINT:INFO]: ", log.LstdFlags),
		Errlog:  log.New(os.Stderr, "[GITHUBINT:ERROR]: ", log.LstdFlags),
		Env:     make(map[string]string, len(keys)),
	}

	for _, key := range keys {
		value := os.Getenv(key)
		if value == "" {
			h.Errlog.Fatalf("%s environment variable was not set", key)
		}
		h.Env[key] = value
	}

	r := router.New()
	r.PanicHandler = handlers.Panic

	r.GET(apiPrefix+"/", h.HomeHandler)

	r.GET("/healthz", h.HealthzHandler)
	r.GET("/info", h.InfoHandler)

	r.GET(apiPrefix+"/home", h.HomeHandler)
	r.POST(apiPrefix+"/webhook", h.WebHookHandler)
	r.POST(apiPrefix+"/auth-callback", h.AuthCallbackHandler)
	r.POST(apiPrefix+"/build-cb", h.BuildCallbackHandler)
	h.Infolog.Printf("start listening port %s", h.Env["GITHUBINT_SERVICE_PORT"])
	h.Infolog.Printf("Registered routes are: %+v", r.Routes())

	go r.Listen(":" + h.Env["GITHUBINT_SERVICE_PORT"])

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
	killSignal := <-interrupt
	h.Infolog.Println("Got signal:", killSignal)

	if killSignal == os.Kill {
		h.Infolog.Println("Service was killed")
	} else {
		h.Infolog.Println("Service was terminated by system signal")
	}

	h.Infolog.Println("shutdown")
}

func getFromEnv(name string) (string, error) {
	value := os.Getenv(name)
	if len(value) == 0 {
		return "", fmt.Errorf("Environement variable %s must be set", name)
	}

	return value, nil
}

// startupDB makes connection with DB, initializes reform DB level.
func startupDB(host, port, user, password, name string) (*reform.DB, error) {
	dataSource := fmt.Sprintf(
		"postgres://%s:%s@%s:%s/%s?sslmode=disable", user, password, host, port, name,
	)

	conn, err := sql.Open("postgres", dataSource)
	if err != nil {
		return nil, err
	}

	if err = conn.Ping(); err != nil {
		return nil, err
	}

	db := reform.NewDB(conn, postgresql.Dialect, reform.NewPrintfLogger(log.Printf))
	if err != nil {
		return nil, err
	}

	return db, nil
}
<commit_msg>Fix var<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/k8s-community/github-integration/handlers"
	_ "github.com/lib/pq" // postgresql driver
	"github.com/takama/router"
	"gopkg.in/reform.v1"
	"gopkg.in/reform.v1/dialects/postgresql"
)

const (
	apiPrefix = "/api/v1"
)

// main function
func main() {
	var errors []error

	// Database settings
	dbHost, err := getFromEnv("COCKROACHDB_PUBLIC_SERVICE_HOST")
	if err != nil {
		errors = append(errors, err)
	}

	dbPort, err := getFromEnv("COCKROACHDB_PUBLIC_SERVICE_PORT")
	if err != nil {
		errors = append(errors, err)
	}

	dbUser, err := getFromEnv("COCKROACHDB_USER")
	if err != nil {
		errors = append(errors, err)
	}

	dbPass, err := getFromEnv("COCKROACHDB_PASSWORD")
	if err != nil {
		errors = append(errors, err)
	}

	dbName, err := getFromEnv("COCKROACHDB_NAME")
	if err != nil {
		errors = append(errors, err)
	}

	db, err := startupDB(dbHost, dbPort, dbUser, dbPass, dbName)
	if err != nil {
		log.Fatalf("Couldn't start up DB: %+v", err)
	}

	if len(errors) > 0 {
		log.Fatalf("Couldn't start service because required DB parameters are not set: %+v", errors)
	}

	keys := []string{
		"GITHUBINT_LOCAL_PORT", "GITHUBINT_BRANCH",
		"GITHUBINT_TOKEN", "GITHUBINT_PRIV_KEY", "GITHUBINT_INTEGRATION_ID",
		"USERMAN_BASE_URL", "CICD_BASE_URL",
	}

	h := &handlers.Handler{
		DB:      db,
		Infolog: log.New(os.Stdout, "[GITHUBINT:INFO]: ", log.LstdFlags),
		Errlog:  log.New(os.Stderr, "[GITHUBINT:ERROR]: ", log.LstdFlags),
		Env:     make(map[string]string, len(keys)),
	}

	for _, key := range keys {
		value := os.Getenv(key)
		if value == "" {
			h.Errlog.Fatalf("%s environment variable was not set", key)
		}
		h.Env[key] = value
	}

	r := router.New()
	r.PanicHandler = handlers.Panic

	r.GET(apiPrefix+"/", h.HomeHandler)

	r.GET("/healthz", h.HealthzHandler)
	r.GET("/info", h.InfoHandler)

	r.GET(apiPrefix+"/home", h.HomeHandler)
	r.POST(apiPrefix+"/webhook", h.WebHookHandler)
	r.POST(apiPrefix+"/auth-callback", h.AuthCallbackHandler)
	r.POST(apiPrefix+"/build-cb", h.BuildCallbackHandler)
	h.Infolog.Printf("start listening port %s", h.Env["GITHUBINT_LOCAL_PORT"])
	h.Infolog.Printf("Registered routes are: %+v", r.Routes())

	go r.Listen(":" + h.Env["GITHUBINT_LOCAL_PORT"])

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
	killSignal := <-interrupt
	h.Infolog.Println("Got signal:", killSignal)

	if killSignal == os.Kill {
		h.Infolog.Println("Service was killed")
	} else {
		h.Infolog.Println("Service was terminated by system signal")
	}

	h.Infolog.Println("shutdown")
}

func getFromEnv(name string) (string, error) {
	value := os.Getenv(name)
	if len(value) == 0 {
		return "", fmt.Errorf("Environement variable %s must be set", name)
	}

	return value, nil
}

// startupDB makes connection with DB, initializes reform DB level.
func startupDB(host, port, user, password, name string) (*reform.DB, error) {
	dataSource := fmt.Sprintf(
		"postgres://%s:%s@%s:%s/%s?sslmode=disable", user, password, host, port, name,
	)

	conn, err := sql.Open("postgres", dataSource)
	if err != nil {
		return nil, err
	}

	if err = conn.Ping(); err != nil {
		return nil, err
	}

	db := reform.NewDB(conn, postgresql.Dialect, reform.NewPrintfLogger(log.Printf))
	if err != nil {
		return nil, err
	}

	return db, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"runtime"

	m "github.com/CasualSuperman/Diorite/multiverse"
)

var local = flag.Bool("local", false, "Connect to a server running on localhost.")

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(runtime.NumCPU())

	canSaveMultiverse := true
	multiverseLoaded := false

	err := os.MkdirAll(StorageDir, os.ModePerm|os.ModeDir)

	if err != nil {
		log.Println("Unable to create application storage directory. Multiverse will not be saved.")
		canSaveMultiverse = false
	}

	var multiverse m.Multiverse

	if canSaveMultiverse {
		multiverseFile, err := os.Open(MultiverseFileName)

		if err != nil {
			if os.IsNotExist(err) || os.IsPermission(err) {
				log.Println("No local database available. A local copy will be downloaded.")
			} else {
				log.Fatalln(err)
			}
		} else {
			log.Println("Loading local multiverse.")
			multiverse, err = m.Read(multiverseFile)
			multiverseFile.Close()

			if err != nil {
				log.Printf("Unable to load multiverse: %s\n", err)
			} else {
				log.Println("Multiverse loaded.")
				multiverseLoaded = true
			}
		}

	}

	if multiverseLoaded {
		log.Println("Checking for multiverse updates.")
	} else {
		log.Println("Downloading online multiverse.")
	}

	var server serverConnection

	if *local {
		server, err = connectToLocalServer()
	} else {
		server, err = connectToDefaultServer()
	}

	if err != nil {
		log.Println(err)
		if multiverseLoaded == false {
			log.Fatalln("No local multiverse available, and unable to download copy. Unable to continue.")
		}
		log.Println("Warning: Online database unavailable. Your card index may be out of date.")
	} else if server.Modified().After(multiverse.Modified) {
		var saveTo io.Writer

		if canSaveMultiverse {
			saveTo, err = os.Create(MultiverseFileName)
			if err != nil {
				log.Println("Unable to save update to multiverse. Continuing, but it will be redownloaded on next startup.")
				saveTo = nil
			}
		}

		log.Println("Multiverse update available! Downloading now.")
		newM, err := server.DownloadMultiverse(saveTo)

		if err != nil {
			log.Printf("Error downloading: %s\n", err)
			if !multiverseLoaded {
				log.Fatalln("Downloading multiverse failed and no local database available. Unable to continue.")
			}
			log.Println("Unable to download most recent multiverse. Continuing with an out-of-date version.")
		} else {
			log.Println("Multiverse downloaded!")
			log.Println("Cards in multiverse:", newM.Cards.List.Len())
			multiverse = newM
		}
		server.Close()
	} else {
		log.Println("No updates available.")
		server.Close()
	}

	cards := multiverse.FuzzyNameSearch("aetherling", 15)

	names := make([]string, len(cards))
	for i, card := range cards {
		names[i] = card.Name
		fmt.Println(card.Name)

		if math.IsNaN(float64(card.Toughness.Val)) {
			if card.IsCreature() {
				fmt.Println(card.Toughness.Original)
			}
		} else {
			fmt.Println(card.Toughness.Val)
		}
	}
	fmt.Println(names)
}
<commit_msg>Adding updated main.go so build can pass.<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"

	m "github.com/CasualSuperman/Diorite/multiverse"
)

var local = flag.Bool("local", false, "Connect to a server running on localhost.")

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(runtime.NumCPU() * 8)

	canSaveMultiverse := true
	multiverseLoaded := false

	err := os.MkdirAll(StorageDir, os.ModePerm|os.ModeDir)

	if err != nil {
		log.Println("Unable to create application storage directory. Multiverse will not be saved.")
		canSaveMultiverse = false
	}

	var multiverse m.Multiverse

	if canSaveMultiverse {
		multiverseFile, err := os.Open(MultiverseFileName)

		if err != nil {
			if os.IsNotExist(err) || os.IsPermission(err) {
				log.Println("No local database available. A local copy will be downloaded.")
			} else {
				log.Fatalln(err)
			}
		} else {
			log.Println("Loading local multiverse.")
			multiverse, err = m.Read(multiverseFile)
			multiverseFile.Close()

			if err != nil {
				log.Printf("Unable to load multiverse: %s\n", err)
			} else {
				log.Println("Multiverse loaded.")
				multiverseLoaded = true
			}
		}

	}

	if multiverseLoaded {
		log.Println("Checking for multiverse updates.")
	} else {
		log.Println("Downloading online multiverse.")
	}

	var server serverConnection

	if *local {
		server, err = connectToLocalServer()
	} else {
		server, err = connectToDefaultServer()
	}

	if err != nil {
		log.Println(err)
		if multiverseLoaded == false {
			log.Fatalln("No local multiverse available, and unable to download copy. Unable to continue.")
		}
		log.Println("Warning: Online database unavailable. Your card index may be out of date.")
	} else if server.Modified().After(multiverse.Modified) {
		var saveTo io.Writer

		if canSaveMultiverse {
			saveTo, err = os.Create(MultiverseFileName)
			if err != nil {
				log.Println("Unable to save update to multiverse. Continuing, but it will be redownloaded on next startup.")
				saveTo = nil
			}
		}

		log.Println("Multiverse update available! Downloading now.")
		newM, err := server.DownloadMultiverse(saveTo)

		if err != nil {
			log.Printf("Error downloading: %s\n", err)
			if !multiverseLoaded {
				log.Fatalln("Downloading multiverse failed and no local database available. Unable to continue.")
			}
			log.Println("Unable to download most recent multiverse. Continuing with an out-of-date version.")
		} else {
			log.Println("Multiverse downloaded!")
			log.Println("Cards in multiverse:", newM.Cards.Len())
			multiverse = newM
		}
		server.Close()
	} else {
		log.Println("No updates available.")
		server.Close()
	}

	searchbench, _ := os.Create("searchbench")
	pprof.StartCPUProfile(searchbench)
	for i := 0; i < 1000; i++ {
		multiverse.Search(m.Formats.Standard)
		multiverse.Search(
			m.And{
				m.ManaColors.Blue,
				m.Or{
					m.ManaColors.Green,
					m.ManaColors.Black,
				},
				m.Not{
					m.Or{
						m.ManaColors.White,
						m.ManaColors.Red,
					},
				},
			})
	}
	pprof.StopCPUProfile()

	printedIn := func(setName string) m.Filter {
		return m.Func(func(c *m.Card) bool {
			for _, printing := range c.Printings {
				if printing.Set.Name == setName {
					return true
				}
			}
			return false
		})
	}

	_ = printedIn

	hasText := func(text string) m.Filter {
		text = strings.ToLower(text)
		return m.Func(func(c *m.Card) bool {
			return strings.Contains(strings.ToLower(c.Text), text)
		})
	}

	cards, err := multiverse.Search(
		m.And{
			m.Formats.Standard,
			hasText("life"),
			printedIn("Theros"),
			m.Or{
				m.ManaColors.White,
				m.ManaColors.Green,
				m.ManaColors.Black,
			},
		})

	if err != nil {
		fmt.Printf("Error! %s\n", err.Error())
	} else {
		results := cards.Sort(m.Sorts.Cmc)
		fmt.Printf("%d Results\n", len(results))
		for _, card := range results {
			fmt.Printf("%s\t%s\n=====\n%s\n\n\n\n", card.Name, card.Cost, card.Text)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

var (
	flAddr          string
	flConnTimeout   time.Duration
	flRPCTimeout    time.Duration
	flTLS           bool
	flTLSNoVerify   bool
	flTLSCACert     string
	flTLSClientCert string
	flTLSClientKey  string
	flTLSServerName string
	flVerbose       bool
)

const (
	// StatusInvalidArguments indicates specified invalid arguments.
	StatusInvalidArguments = 1
	// StatusConnectionFailure indicates connection failed.
	StatusConnectionFailure = 2
	// StatusRPCFailure indicates rpc failed.
	StatusRPCFailure = 3
	// StatusUnhealthy indicates rpc succeeded but indicates unhealthy service.
	StatusUnhealthy = 4
)

func init() {
	log.SetFlags(0)
	flag.StringVar(&flAddr, "addr", "", "(required) tcp host:port to connect")
	// timeouts
	flag.DurationVar(&flConnTimeout, "connect-timeout", time.Second, "timeout for establishing connection")
	flag.DurationVar(&flRPCTimeout, "rpc-timeout", time.Second, "timeout for health check rpc")
	// tls settings
	flag.BoolVar(&flTLS, "tls", false, "use TLS (default: false, INSECURE plaintext transport)")
	flag.BoolVar(&flTLSNoVerify, "tls-no-verify", false, "(with -tls) don't verify the certificate (INSECURE) presented by the server (default: false)")
	flag.StringVar(&flTLSCACert, "tls-ca-cert", "", "(with -tls, optional) file containing trusted certificates for verifying server")
	flag.StringVar(&flTLSClientCert, "tls-client-cert", "", "(with -tls, optional) client certificate for authenticating to the server (requires -tls-client-key)")
	flag.StringVar(&flTLSClientKey, "tls-client-key", "", "(with -tls) client private key for authenticating to the server (requires -tls-client-cert)")
	flag.StringVar(&flTLSServerName, "tls-server-name", "", "(with -tls) override the hostname used to verify the server certificate")
	flag.BoolVar(&flVerbose, "v", false, "verbose logs")

	flag.Parse()

	argError := func(s string, v ...interface{}) {
		log.Printf("error: "+s, v...)
		os.Exit(StatusInvalidArguments)
	}

	if flAddr == "" {
		argError("-addr not specified")
	}
	if flConnTimeout <= 0 {
		argError("-connect-timeout must be greater than zero (specified: %v)", flConnTimeout)
	}
	if flRPCTimeout <= 0 {
		argError("-rpc-timeout must be greater than zero (specified: %v)", flRPCTimeout)
	}
	if !flTLS && flTLSNoVerify {
		argError("specified -tls-no-verify without specifying -tls")
	}
	if !flTLS && flTLSCACert != "" {
		argError("specified -tls-ca-cert without specifying -tls")
	}
	if !flTLS && flTLSClientCert != "" {
		argError("specified -tls-client-cert without specifying -tls")
	}
	if !flTLS && flTLSServerName != "" {
		argError("specified -tls-server-name without specifying -tls")
	}
	if flTLSClientCert != "" && flTLSClientKey == "" {
		argError("specified -tls-client-cert without specifying -tls-client-key")
	}
	if flTLSClientCert == "" && flTLSClientKey != "" {
		argError("specified -tls-client-key without specifying -tls-client-cert")
	}
	if flTLSNoVerify && flTLSCACert != "" {
		argError("cannot specify -tls-ca-cert with -tls-no-verify (CA cert would not be used)")
	}
	if flTLSNoVerify && flTLSServerName != "" {
		argError("cannot specify -tls-server-name with -tls-no-verify (server name would not be used)")
	}

	if flVerbose {
		log.Printf("parsed options:")
		log.Printf("> addr=%s conn_timeout=%v rpc_timeout=%v", flAddr, flConnTimeout, flRPCTimeout)
		log.Printf("> tls=%v", flTLS)
		if flTLS {
			log.Printf("  > no-verify=%v ", flTLSNoVerify)
			log.Printf("  > ca-cert=%s", flTLSCACert)
			log.Printf("  > client-cert=%s", flTLSClientCert)
			log.Printf("  > client-key=%s", flTLSClientKey)
			log.Printf("  > server-name=%s", flTLSServerName)
		}
	}
}

func buildCredentials(skipVerify bool, caCerts, clientCert, clientKey, serverName string) (credentials.TransportCredentials, error) {
	var cfg tls.Config

	if clientCert != "" && clientKey != "" {
		keyPair, err := tls.LoadX509KeyPair(clientCert, clientKey)
		if err != nil {
			return nil, fmt.Errorf("failed to load tls client cert/key pair. error=%v", err)
		}
		cfg.Certificates = []tls.Certificate{keyPair}
	}

	if skipVerify {
		cfg.InsecureSkipVerify = true
	} else if caCerts != "" {
		// override system roots
		rootCAs := x509.NewCertPool()
		pem, err := ioutil.ReadFile(caCerts)
		if err != nil {
			return nil, fmt.Errorf("failed to load root CA certificates from file (%s) error=%v", caCerts, err)
		}
		if !rootCAs.AppendCertsFromPEM(pem) {
			return nil, fmt.Errorf("no root CA certs parsed from file %s", caCerts)
		}
		cfg.RootCAs = rootCAs
	}
	if serverName != "" {
		cfg.ServerName = serverName
	}
	return credentials.NewTLS(&cfg), nil
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		sig := <-c
		if sig == os.Interrupt {
			log.Printf("cancellation received")
			cancel()
			return
		}
	}()
	if flVerbose {
		log.Printf("establishing connection")
	}

	opts := []grpc.DialOption{
		grpc.WithUserAgent("grpc_health_probe"),
		grpc.WithBlock(),
		grpc.WithTimeout(flConnTimeout)}
	if flTLS {
		creds, err := buildCredentials(flTLSNoVerify, flTLSCACert, flTLSClientCert, flTLSClientKey, flTLSServerName)
		if err != nil {
			log.Printf("failed to initialize tls credentials. error=%v", err)
			os.Exit(StatusInvalidArguments)
		}
		opts = append(opts, grpc.WithTransportCredentials(creds))
	} else {
		opts = append(opts, grpc.WithInsecure())
	}
	connStart := time.Now()
	conn, err := grpc.DialContext(ctx, flAddr, opts...)
	if err != nil {
		log.Printf("failed to connect service at %q: %+v", flAddr, err)
		os.Exit(StatusConnectionFailure)
	}
	connDuration := time.Since(connStart)
	defer conn.Close()

	rpcStart := time.Now()
	rpcCtx, rpcCancel := context.WithTimeout(ctx, flRPCTimeout)
	defer rpcCancel()
	resp, err := healthpb.NewHealthClient(conn).Check(rpcCtx, &healthpb.HealthCheckRequest{})
	if err != nil {
		if stat, ok := status.FromError(err); ok && stat.Code() == codes.Unimplemented {
			log.Printf("error: this server does not implement the grpc health protocol (grpc.health.v1.Health)")
		} else {
			log.Printf("error: health rpc failed: %+v", err)
		}
		os.Exit(StatusRPCFailure)
	}
	rpcDuration := time.Since(rpcStart)

	if resp.GetStatus() != healthpb.HealthCheckResponse_SERVING {
		log.Printf("service unhealthy (responded with %q)", resp.GetStatus().String())
		os.Exit(StatusUnhealthy)
	}
	if flVerbose {
		log.Printf("time elapsed: connect=%v rpc=%v", connDuration, rpcDuration)
	}
	log.Printf("status: %v", resp.GetStatus().String())
}
<commit_msg>import fix<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/status"
)

var (
	flAddr          string
	flConnTimeout   time.Duration
	flRPCTimeout    time.Duration
	flTLS           bool
	flTLSNoVerify   bool
	flTLSCACert     string
	flTLSClientCert string
	flTLSClientKey  string
	flTLSServerName string
	flVerbose       bool
)

const (
	// StatusInvalidArguments indicates specified invalid arguments.
	StatusInvalidArguments = 1
	// StatusConnectionFailure indicates connection failed.
	StatusConnectionFailure = 2
	// StatusRPCFailure indicates rpc failed.
	StatusRPCFailure = 3
	// StatusUnhealthy indicates rpc succeeded but indicates unhealthy service.
	StatusUnhealthy = 4
)

func init() {
	log.SetFlags(0)
	flag.StringVar(&flAddr, "addr", "", "(required) tcp host:port to connect")
	// timeouts
	flag.DurationVar(&flConnTimeout, "connect-timeout", time.Second, "timeout for establishing connection")
	flag.DurationVar(&flRPCTimeout, "rpc-timeout", time.Second, "timeout for health check rpc")
	// tls settings
	flag.BoolVar(&flTLS, "tls", false, "use TLS (default: false, INSECURE plaintext transport)")
	flag.BoolVar(&flTLSNoVerify, "tls-no-verify", false, "(with -tls) don't verify the certificate (INSECURE) presented by the server (default: false)")
	flag.StringVar(&flTLSCACert, "tls-ca-cert", "", "(with -tls, optional) file containing trusted certificates for verifying server")
	flag.StringVar(&flTLSClientCert, "tls-client-cert", "", "(with -tls, optional) client certificate for authenticating to the server (requires -tls-client-key)")
	flag.StringVar(&flTLSClientKey, "tls-client-key", "", "(with -tls) client private key for authenticating to the server (requires -tls-client-cert)")
	flag.StringVar(&flTLSServerName, "tls-server-name", "", "(with -tls) override the hostname used to verify the server certificate")
	flag.BoolVar(&flVerbose, "v", false, "verbose logs")

	flag.Parse()

	argError := func(s string, v ...interface{}) {
		log.Printf("error: "+s, v...)
		os.Exit(StatusInvalidArguments)
	}

	if flAddr == "" {
		argError("-addr not specified")
	}
	if flConnTimeout <= 0 {
		argError("-connect-timeout must be greater than zero (specified: %v)", flConnTimeout)
	}
	if flRPCTimeout <= 0 {
		argError("-rpc-timeout must be greater than zero (specified: %v)", flRPCTimeout)
	}
	if !flTLS && flTLSNoVerify {
		argError("specified -tls-no-verify without specifying -tls")
	}
	if !flTLS && flTLSCACert != "" {
		argError("specified -tls-ca-cert without specifying -tls")
	}
	if !flTLS && flTLSClientCert != "" {
		argError("specified -tls-client-cert without specifying -tls")
	}
	if !flTLS && flTLSServerName != "" {
		argError("specified -tls-server-name without specifying -tls")
	}
	if flTLSClientCert != "" && flTLSClientKey == "" {
		argError("specified -tls-client-cert without specifying -tls-client-key")
	}
	if flTLSClientCert == "" && flTLSClientKey != "" {
		argError("specified -tls-client-key without specifying -tls-client-cert")
	}
	if flTLSNoVerify && flTLSCACert != "" {
		argError("cannot specify -tls-ca-cert with -tls-no-verify (CA cert would not be used)")
	}
	if flTLSNoVerify && flTLSServerName != "" {
		argError("cannot specify -tls-server-name with -tls-no-verify (server name would not be used)")
	}

	if flVerbose {
		log.Printf("parsed options:")
		log.Printf("> addr=%s conn_timeout=%v rpc_timeout=%v", flAddr, flConnTimeout, flRPCTimeout)
		log.Printf("> tls=%v", flTLS)
		if flTLS {
			log.Printf("  > no-verify=%v ", flTLSNoVerify)
			log.Printf("  > ca-cert=%s", flTLSCACert)
			log.Printf("  > client-cert=%s", flTLSClientCert)
			log.Printf("  > client-key=%s", flTLSClientKey)
			log.Printf("  > server-name=%s", flTLSServerName)
		}
	}
}

func buildCredentials(skipVerify bool, caCerts, clientCert, clientKey, serverName string) (credentials.TransportCredentials, error) {
	var cfg tls.Config

	if clientCert != "" && clientKey != "" {
		keyPair, err := tls.LoadX509KeyPair(clientCert, clientKey)
		if err != nil {
			return nil, fmt.Errorf("failed to load tls client cert/key pair. error=%v", err)
		}
		cfg.Certificates = []tls.Certificate{keyPair}
	}

	if skipVerify {
		cfg.InsecureSkipVerify = true
	} else if caCerts != "" {
		// override system roots
		rootCAs := x509.NewCertPool()
		pem, err := ioutil.ReadFile(caCerts)
		if err != nil {
			return nil, fmt.Errorf("failed to load root CA certificates from file (%s) error=%v", caCerts, err)
		}
		if !rootCAs.AppendCertsFromPEM(pem) {
			return nil, fmt.Errorf("no root CA certs parsed from file %s", caCerts)
		}
		cfg.RootCAs = rootCAs
	}
	if serverName != "" {
		cfg.ServerName = serverName
	}
	return credentials.NewTLS(&cfg), nil
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		sig := <-c
		if sig == os.Interrupt {
			log.Printf("cancellation received")
			cancel()
			return
		}
	}()
	if flVerbose {
		log.Printf("establishing connection")
	}

	opts := []grpc.DialOption{
		grpc.WithUserAgent("grpc_health_probe"),
		grpc.WithBlock(),
		grpc.WithTimeout(flConnTimeout)}
	if flTLS {
		creds, err := buildCredentials(flTLSNoVerify, flTLSCACert, flTLSClientCert, flTLSClientKey, flTLSServerName)
		if err != nil {
			log.Printf("failed to initialize tls credentials. error=%v", err)
			os.Exit(StatusInvalidArguments)
		}
		opts = append(opts, grpc.WithTransportCredentials(creds))
	} else {
		opts = append(opts, grpc.WithInsecure())
	}
	connStart := time.Now()
	conn, err := grpc.DialContext(ctx, flAddr, opts...)
	if err != nil {
		log.Printf("failed to connect service at %q: %+v", flAddr, err)
		os.Exit(StatusConnectionFailure)
	}
	connDuration := time.Since(connStart)
	defer conn.Close()

	rpcStart := time.Now()
	rpcCtx, rpcCancel := context.WithTimeout(ctx, flRPCTimeout)
	defer rpcCancel()
	resp, err := healthpb.NewHealthClient(conn).Check(rpcCtx, &healthpb.HealthCheckRequest{})
	if err != nil {
		if stat, ok := status.FromError(err); ok && stat.Code() == codes.Unimplemented {
			log.Printf("error: this server does not implement the grpc health protocol (grpc.health.v1.Health)")
		} else {
			log.Printf("error: health rpc failed: %+v", err)
		}
		os.Exit(StatusRPCFailure)
	}
	rpcDuration := time.Since(rpcStart)

	if resp.GetStatus() != healthpb.HealthCheckResponse_SERVING {
		log.Printf("service unhealthy (responded with %q)", resp.GetStatus().String())
		os.Exit(StatusUnhealthy)
	}
	if flVerbose {
		log.Printf("time elapsed: connect=%v rpc=%v", connDuration, rpcDuration)
	}
	log.Printf("status: %v", resp.GetStatus().String())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/feeds"
	"github.com/joho/godotenv"
	"net/http"
	"os"
)

func RenderFeed(w http.ResponseWriter, feed *feeds.Feed) {
	atom, err := feed.ToAtom()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/atom+xml")
	fmt.Fprintln(w, atom)
}

func HandlePurolandNews(w http.ResponseWriter, r *http.Request) {
	feed, err := GetPurolandNews()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func HandlePurolandInfo(w http.ResponseWriter, r *http.Request) {
	feed, err := GetPurolandInfo()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func HandleCharacterShow(w http.ResponseWriter, r *http.Request) {
	feed, err := GetCharacterShow()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func HandleSanrioEvent(w http.ResponseWriter, r *http.Request) {
	feed, err := GetSanrioEvent()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func HandleKittychanInfo(w http.ResponseWriter, r *http.Request) {
	feed, err := GetKittychanInfo()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func HandleSanrioEventsCalendar(w http.ResponseWriter, r *http.Request) {
	feed, err := GetSanrioEventsCalendar()
	if err != nil {
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	RenderFeed(w, feed)
}

func main() {
	_ = godotenv.Load()

	http.HandleFunc("/puroland-info", HandlePurolandInfo)
	http.HandleFunc("/puroland-news", HandlePurolandNews)
	http.HandleFunc("/character-show", HandleCharacterShow)
	http.HandleFunc("/sanrio-event", HandleSanrioEvent)
	http.HandleFunc("/kittychan-info", HandleKittychanInfo)
	http.HandleFunc("/sanrio-events-calendar", HandleSanrioEventsCalendar)

	port := os.Getenv("PORT")
	if port == "" {
		port = "13000"
	}
	http.ListenAndServe(":"+port, nil)
}
<commit_msg>Refactor<commit_after>package main

import (
	"fmt"
	"github.com/gorilla/feeds"
	"github.com/joho/godotenv"
	"net/http"
	"os"
)

func renderFeed(w http.ResponseWriter, feed *feeds.Feed) {
	atom, err := feed.ToAtom()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/atom+xml")
	fmt.Fprintln(w, atom)
}

func feedHandler(fetcher func() (*feeds.Feed, error)) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		feed, err := fetcher()
		if err != nil {
			w.WriteHeader(http.StatusServiceUnavailable)
			return
		}
		renderFeed(w, feed)
	}
}

func main() {
	_ = godotenv.Load()

	http.HandleFunc("/puroland-info", feedHandler(GetPurolandInfo))
	http.HandleFunc("/puroland-news", feedHandler(GetPurolandNews))
	http.HandleFunc("/character-show", feedHandler(GetCharacterShow))
	http.HandleFunc("/sanrio-event", feedHandler(GetSanrioEvent))
	http.HandleFunc("/kittychan-info", feedHandler(GetKittychanInfo))
	http.HandleFunc("/sanrio-events-calendar", feedHandler(GetSanrioEventsCalendar))

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


<commit_before>package main

import (
	"github.com/armed/nver/cmd"
	"github.com/codegangsta/cli"
	"log"
	"os"
	"runtime"
)

func main() {
	if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
		log.Fatalf("Sorry, nver currently supports only Mac OS X and Linux")
	}

	app := cli.NewApp()
	app.Name = "nver"
	app.Version = "0.0.3"
	app.Usage = "Manage your Node.js versions"
	app.Commands = cmd.Commands
	app.Run(os.Args)
}
<commit_msg>edited usage help msg<commit_after>package main

import (
	"github.com/armed/nver/cmd"
	"github.com/codegangsta/cli"
	"log"
	"os"
	"runtime"
)

func main() {
	if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
		log.Fatalf("Sorry, nver currently supports only Mac OS X and Linux")
	}

	app := cli.NewApp()
	app.Name = "nver"
	app.Version = "0.0.3"
	app.Usage = "Manage your current Node.js version"
	app.Commands = cmd.Commands
	app.Run(os.Args)
}
<|endoftext|>