<commit_before>package lnwire

import (
	"bytes"
	"fmt"
	"io"

	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/wire"
)

// SingleFundingComplete is the message Alice sends to Bob once she is able to
// fully assemble the funding transaction, and both versions of the commitment
// transaction. The purpose of this message is to present Bob with the items
// required for him to generate a signature for Alice's version of the
// commitment transaction.
type SingleFundingComplete struct {
	// ChannelID serves to uniquely identify the future channel created by
	// the initiated single funder workflow.
	// TODO(roasbeef): change all to PendingChannelID, document schema
	ChannelID uint64

	// FundingOutPoint is the outpoint (txid:index) of the funding
	// transaction. With this value, Bob will be able to generate a
	// signature for Alice's version of the commitment transaction.
	FundingOutPoint wire.OutPoint

	// CommitSignature is Alice's signature for Bob's version of the
	// commitment transaction.
	CommitSignature *btcec.Signature

	// RevocationKey is the initial key to be used for the revocation
	// clause within the self-output of the initiators's commitment
	// transaction. Once an initial new state is created, the initiator
	// will send a preimage which will allow the initiator to sweep the
	// initiator's funds if the violate the contract.
	RevocationKey *btcec.PublicKey

	// StateHintObsfucator is the set of bytes used by the initiator to
	// obsfucate the state number encoded within the sequence number for
	// the commitment transaction's only input. The initiator generates
	// this value by hashing the 0th' state derived from the revocation PRF
	// an additional time.
	StateHintObsfucator [4]byte
}

// NewSingleFundingComplete creates, and returns a new empty
// SingleFundingResponse.
func NewSingleFundingComplete(chanID uint64, fundingPoint wire.OutPoint,
	commitSig *btcec.Signature, revokeKey *btcec.PublicKey,
	obsfucator [4]byte) *SingleFundingComplete {

	return &SingleFundingComplete{
		ChannelID:           chanID,
		FundingOutPoint:     fundingPoint,
		CommitSignature:     commitSig,
		RevocationKey:       revokeKey,
		StateHintObsfucator: obsfucator,
	}
}

// Decode deserializes the serialized SingleFundingComplete stored in the passed
// io.Reader into the target SingleFundingComplete using the deserialization
// rules defined by the passed protocol version.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Decode(r io.Reader, pver uint32) error {
	// ChannelID (8)
	// FundingOutPoint (36)
	// CommitmentSignature (73)
	// RevocationKey (33)
	err := readElements(r,
		&s.ChannelID,
		&s.FundingOutPoint,
		&s.CommitSignature,
		&s.RevocationKey,
		s.StateHintObsfucator[:])
	if err != nil {
		return err
	}

	return nil
}

// Encode serializes the target SingleFundingComplete into the passed io.Writer
// implementation. Serialization will observe the rules defined by the passed
// protocol version.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Encode(w io.Writer, pver uint32) error {
	// ChannelID (8)
	// FundingOutPoint (36)
	// Commitment Signature (73)
	// RevocationKey (33)
	err := writeElements(w,
		s.ChannelID,
		s.FundingOutPoint,
		s.CommitSignature,
		s.RevocationKey,
		s.StateHintObsfucator[:])
	if err != nil {
		return err
	}

	return nil
}

// Command returns the uint32 code which uniquely identifies this message as a
// SingleFundingRequest on the wire.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Command() uint32 {
	return CmdSingleFundingComplete
}

// MaxPayloadLength returns the maximum allowed payload length for a
// SingleFundingComplete. This is calculated by summing the max length of all
// the fields within a SingleFundingResponse. Therefore, the final breakdown
// is: 8 + 36 + 33 + 73 + 4 = 154
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) MaxPayloadLength(uint32) uint32 {
	return 154
}

// Validate examines each populated field within the SingleFundingComplete for
// field sanity.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Validate() error {
	var zeroHash [32]byte
	if bytes.Equal(zeroHash[:], s.FundingOutPoint.Hash[:]) {
		return fmt.Errorf("funding outpoint hash must be non-zero")
	}

	if s.CommitSignature == nil {
		return fmt.Errorf("commitment signature must be non-nil")
	}

	// TODO(roasbeef): fin validation

	// We're good!
	return nil
}
<commit_msg>lnwire: use [6]byte obsfucator<commit_after>package lnwire

import (
	"bytes"
	"fmt"
	"io"

	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/wire"
)

// SingleFundingComplete is the message Alice sends to Bob once she is able to
// fully assemble the funding transaction, and both versions of the commitment
// transaction. The purpose of this message is to present Bob with the items
// required for him to generate a signature for Alice's version of the
// commitment transaction.
type SingleFundingComplete struct {
	// ChannelID serves to uniquely identify the future channel created by
	// the initiated single funder workflow.
	// TODO(roasbeef): change all to PendingChannelID, document schema
	ChannelID uint64

	// FundingOutPoint is the outpoint (txid:index) of the funding
	// transaction. With this value, Bob will be able to generate a
	// signature for Alice's version of the commitment transaction.
	FundingOutPoint wire.OutPoint

	// CommitSignature is Alice's signature for Bob's version of the
	// commitment transaction.
	CommitSignature *btcec.Signature

	// RevocationKey is the initial key to be used for the revocation
	// clause within the self-output of the initiators's commitment
	// transaction. Once an initial new state is created, the initiator
	// will send a preimage which will allow the initiator to sweep the
	// initiator's funds if the violate the contract.
	RevocationKey *btcec.PublicKey

	// StateHintObsfucator is the set of bytes used by the initiator to
	// obsfucate the state number encoded within the sequence number for
	// the commitment transaction's only input. The initiator generates
	// this value by hashing the 0th' state derived from the revocation PRF
	// an additional time.
	StateHintObsfucator [6]byte
}

// NewSingleFundingComplete creates, and returns a new empty
// SingleFundingResponse.
func NewSingleFundingComplete(chanID uint64, fundingPoint wire.OutPoint,
	commitSig *btcec.Signature, revokeKey *btcec.PublicKey,
	obsfucator [6]byte) *SingleFundingComplete {

	return &SingleFundingComplete{
		ChannelID:           chanID,
		FundingOutPoint:     fundingPoint,
		CommitSignature:     commitSig,
		RevocationKey:       revokeKey,
		StateHintObsfucator: obsfucator,
	}
}

// Decode deserializes the serialized SingleFundingComplete stored in the passed
// io.Reader into the target SingleFundingComplete using the deserialization
// rules defined by the passed protocol version.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Decode(r io.Reader, pver uint32) error {
	// ChannelID (8)
	// FundingOutPoint (36)
	// CommitmentSignature (73)
	// RevocationKey (33)
	err := readElements(r,
		&s.ChannelID,
		&s.FundingOutPoint,
		&s.CommitSignature,
		&s.RevocationKey,
		s.StateHintObsfucator[:])
	if err != nil {
		return err
	}

	return nil
}

// Encode serializes the target SingleFundingComplete into the passed io.Writer
// implementation. Serialization will observe the rules defined by the passed
// protocol version.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Encode(w io.Writer, pver uint32) error {
	// ChannelID (8)
	// FundingOutPoint (36)
	// Commitment Signature (73)
	// RevocationKey (33)
	err := writeElements(w,
		s.ChannelID,
		s.FundingOutPoint,
		s.CommitSignature,
		s.RevocationKey,
		s.StateHintObsfucator[:])
	if err != nil {
		return err
	}

	return nil
}

// Command returns the uint32 code which uniquely identifies this message as a
// SingleFundingRequest on the wire.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Command() uint32 {
	return CmdSingleFundingComplete
}

// MaxPayloadLength returns the maximum allowed payload length for a
// SingleFundingComplete. This is calculated by summing the max length of all
// the fields within a SingleFundingResponse. Therefore, the final breakdown
// is: 8 + 36 + 33 + 73 + 4 = 154
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) MaxPayloadLength(uint32) uint32 {
	return 154
}

// Validate examines each populated field within the SingleFundingComplete for
// field sanity.
//
// This is part of the lnwire.Message interface.
func (s *SingleFundingComplete) Validate() error {
	var zeroHash [32]byte
	if bytes.Equal(zeroHash[:], s.FundingOutPoint.Hash[:]) {
		return fmt.Errorf("funding outpoint hash must be non-zero")
	}

	if s.CommitSignature == nil {
		return fmt.Errorf("commitment signature must be non-nil")
	}

	// TODO(roasbeef): fin validation

	// We're good!
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"

	"github.com/codegangsta/cli"
)

// os.Exit forcely kills process, so let me share this global variable to terminate at the last
var exitCode = 0

func main() {
	app := cli.NewApp()
	app.Name = "lltsv"
	app.Version = Version
	app.Usage = `List specified keys of LTSV (Labeled Tab Separated Values)

	Example1 $ echo "foo:aaa\tbar:bbb" | lltsv -k foo,bar
	foo:aaa   bar:bbb

	The output is colorized as default when you outputs to a terminal.
	The coloring is disabled if you pipe or redirect outputs.

	Example2 $ echo "foo:aaa\tbar:bbb" | lltsv -k foo,bar -K
	aaa       bbb

	Eliminate labels with "-K" option.

	Example3 $ lltsv -k foo,bar -K file*.log

	Specify input files as arguments.

	Example4 $ lltsv -k resptime,status,uri -f 'resptime > 6' access_log
	         $ lltsv -k resptime,status,uri -f 'resptime > 6' -f 'uri =~ ^/foo' access_log

	Filter output with "-f" option. Available comparing operators are:

	  >= > == < <= (arithmetic (float64))
	  =~ !~        (regular expression (string))

	You can specify multiple -f options (AND condition).

	Example5 $ lltsv -k resptime,upstream_resptime,diff -f 'diff = resptime - upstream_resptime' access_log

	Evaluate value with "-e" option. Available operators are:

	  + - * / (arithmetic (float64))

	Homepage: https://github.com/sonots/lltsv`
	app.Author = "sonots"
	app.Email = "sonots@gmail.com"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "key, k",
			Usage: "keys to output (multiple keys separated by ,)",
		},
		cli.BoolFlag{
			Name:  "no-key, K",
			Usage: "output without keys (and without color)",
		},
		cli.StringSliceFlag{
			Name:  "filter, f",
			Usage: "filter expression to output",
		},
		cli.StringSliceFlag{
			Name:  "expr, e",
			Usage: "evaluate value by expression to output",
		},
	}
	app.Action = doMain
	app.Run(os.Args)
	os.Exit(exitCode)
}

func doMain(c *cli.Context) {
	keys := make([]string, 0, 0) // slice with length 0
	if c.String("key") != "" {
		keys = strings.Split(c.String("key"), ",")
	}
	no_key := c.Bool("no-key")
	filters := c.StringSlice("filter")
	exprs := c.StringSlice("expr")

	lltsv := newLltsv(keys, no_key, filters, exprs)

	if len(c.Args()) > 0 {
		for _, filename := range c.Args() {
			file, err := os.Open(filename)
			if err != nil {
				os.Stderr.WriteString("failed to open and read `" + filename + "`.\n")
				exitCode = 1
				return
			}
			err = lltsv.scanAndWrite(file)
			file.Close()
			if err != nil {
				os.Stderr.WriteString("reading input errored\n")
				exitCode = 1
				return
			}
		}
	} else {
		file := os.Stdin
		err := lltsv.scanAndWrite(file)
		file.Close()
		if err != nil {
			os.Stderr.WriteString("reading input errored\n")
			exitCode = 1
			return
		}
	}
}
<commit_msg>Follow-up https://github.com/urfave/cli/blob/master/CHANGELOG.md#deprecated-cli-app-action-signature<commit_after>package main

import (
	"os"
	"strings"

	"github.com/codegangsta/cli"
)

// os.Exit forcely kills process, so let me share this global variable to terminate at the last
var exitCode = 0

func main() {
	app := cli.NewApp()
	app.Name = "lltsv"
	app.Version = Version
	app.Usage = `List specified keys of LTSV (Labeled Tab Separated Values)

	Example1 $ echo "foo:aaa\tbar:bbb" | lltsv -k foo,bar
	foo:aaa   bar:bbb

	The output is colorized as default when you outputs to a terminal.
	The coloring is disabled if you pipe or redirect outputs.

	Example2 $ echo "foo:aaa\tbar:bbb" | lltsv -k foo,bar -K
	aaa       bbb

	Eliminate labels with "-K" option.

	Example3 $ lltsv -k foo,bar -K file*.log

	Specify input files as arguments.

	Example4 $ lltsv -k resptime,status,uri -f 'resptime > 6' access_log
	         $ lltsv -k resptime,status,uri -f 'resptime > 6' -f 'uri =~ ^/foo' access_log

	Filter output with "-f" option. Available comparing operators are:

	  >= > == < <= (arithmetic (float64))
	  =~ !~        (regular expression (string))

	You can specify multiple -f options (AND condition).

	Example5 $ lltsv -k resptime,upstream_resptime,diff -f 'diff = resptime - upstream_resptime' access_log

	Evaluate value with "-e" option. Available operators are:

	  + - * / (arithmetic (float64))

	Homepage: https://github.com/sonots/lltsv`
	app.Author = "sonots"
	app.Email = "sonots@gmail.com"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "key, k",
			Usage: "keys to output (multiple keys separated by ,)",
		},
		cli.BoolFlag{
			Name:  "no-key, K",
			Usage: "output without keys (and without color)",
		},
		cli.StringSliceFlag{
			Name:  "filter, f",
			Usage: "filter expression to output",
		},
		cli.StringSliceFlag{
			Name:  "expr, e",
			Usage: "evaluate value by expression to output",
		},
	}
	app.Action = doMain
	app.Run(os.Args)
	os.Exit(exitCode)
}

func doMain(c *cli.Context) error {
	keys := make([]string, 0, 0) // slice with length 0
	if c.String("key") != "" {
		keys = strings.Split(c.String("key"), ",")
	}
	no_key := c.Bool("no-key")
	filters := c.StringSlice("filter")
	exprs := c.StringSlice("expr")

	lltsv := newLltsv(keys, no_key, filters, exprs)

	if len(c.Args()) > 0 {
		for _, filename := range c.Args() {
			file, err := os.Open(filename)
			if err != nil {
				os.Stderr.WriteString("failed to open and read `" + filename + "`.\n")
				exitCode = 1
				return err
			}
			err = lltsv.scanAndWrite(file)
			file.Close()
			if err != nil {
				os.Stderr.WriteString("reading input errored\n")
				exitCode = 1
				return err
			}
		}
	} else {
		file := os.Stdin
		err := lltsv.scanAndWrite(file)
		file.Close()
		if err != nil {
			os.Stderr.WriteString("reading input errored\n")
			exitCode = 1
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/http"
	"log"
	"io/ioutil"
	"encoding/json"
	"fmt"
	"bytes"
	"io"
	"gopkg.in/tylerb/graceful.v1"
	"time"
	"strings"
)

var (
	githubUsername = ""
	githubPassword = ""
	githubAddr     = ""
	Addr           = ""
)

type GitHubRateLimit struct {
	Resources struct {
			  Core    struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"core"`
			  Search  struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"search"`
			  Graphql struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"graphql"`
		  } `json:"resources"`
	Rate      struct {
			  Limit     int `json:"limit"`
			  Remaining int `json:"remaining"`
			  Reset     int `json:"reset"`
		  } `json:"rate"`
}

func (g *GitHubRateLimit) WriteTo(w io.Writer) {
	buf := &bytes.Buffer{}

	// GitHub Rate Limit: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_limit", "GitHub Rate Limit: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_limit", "gauge"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "core", g.Resources.Core.Limit))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "search", g.Resources.Search.Limit))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "graphql", g.Resources.Graphql.Limit))

	// GitHub Rate Remaining: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_remaining", "GitHub Rate Remaining: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_remaining", "gauge"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "core", g.Resources.Core.Remaining))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "search", g.Resources.Search.Remaining))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "graphql", g.Resources.Graphql.Remaining))

	// GitHub Rate Reset: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_remaining", "GitHub Rate Reset: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_remaining", "count"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "core", g.Resources.Core.Reset))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "search", g.Resources.Search.Reset))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "graphql", g.Resources.Graphql.Reset))

	// GitHub Rate Rate
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_limit", "GitHub Rate Limit"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_limit", "gauge"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_limit", g.Rate.Limit))

	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_remaining", "GitHub Rate Remaining"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_remaining", "gauge"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_remaining", g.Rate.Remaining))

	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_reset", "GitHub Rate Reset"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_reset", "count"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_reset", g.Rate.Reset))

	io.Copy(w, buf)
}

func main() {
	addr := flag.String("addr", "0.0.0.0:8080", "HTTP Server address")
	url := flag.String("url", "https://api.github.com", "Github API address")
	username := flag.String("username", "", "GitHub username")
	password := flag.String("password", "", "GitHub password")
	flag.Parse()

	Addr = *addr
	githubAddr = *url + "/rate_limit"
	githubUsername = *username
	githubPassword = *password

	log.Println("Starting GitHub exporter.")
	log.Println("Listening on:", "'" + Addr + "'",)
	log.Println("Scrapping:", "'" + githubAddr + "'", "with username", "'" + githubUsername + "'", "and password", "'" + strings.Repeat("*", len(githubPassword)) + "'", ".")

	server := &graceful.Server{
		Timeout: 10 * time.Second,
		Server: &http.Server{
			Addr:        Addr,
			ReadTimeout: time.Duration(5) * time.Second,
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				req, err := http.NewRequest("GET", githubAddr, nil)
				if err != nil {
					log.Println(err)
				}

				if (githubUsername != "") && (githubPassword != "") {
					req.SetBasicAuth(githubUsername, githubPassword)
				}

				transport := http.Transport{}
				resp, err := transport.RoundTrip(req)
				if err != nil {
					log.Println(err)
				}

				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					log.Println(err)
				}

				resp.Body.Close()

				res := GitHubRateLimit{}
				json.Unmarshal([]byte(body), &res)

				res.WriteTo(w)
			}),
		},
	}

	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>s/remaining/reset/g<commit_after>package main

import (
	"flag"
	"net/http"
	"log"
	"io/ioutil"
	"encoding/json"
	"fmt"
	"bytes"
	"io"
	"gopkg.in/tylerb/graceful.v1"
	"time"
	"strings"
)

var (
	githubUsername = ""
	githubPassword = ""
	githubAddr     = ""
	Addr           = ""
)

type GitHubRateLimit struct {
	Resources struct {
			  Core    struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"core"`
			  Search  struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"search"`
			  Graphql struct {
					  Limit     int `json:"limit"`
					  Remaining int `json:"remaining"`
					  Reset     int `json:"reset"`
				  } `json:"graphql"`
		  } `json:"resources"`
	Rate      struct {
			  Limit     int `json:"limit"`
			  Remaining int `json:"remaining"`
			  Reset     int `json:"reset"`
		  } `json:"rate"`
}

func (g *GitHubRateLimit) WriteTo(w io.Writer) {
	buf := &bytes.Buffer{}

	// GitHub Rate Limit: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_limit", "GitHub Rate Limit: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_limit", "gauge"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "core", g.Resources.Core.Limit))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "search", g.Resources.Search.Limit))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_limit", "graphql", g.Resources.Graphql.Limit))

	// GitHub Rate Remaining: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_remaining", "GitHub Rate Remaining: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_remaining", "gauge"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "core", g.Resources.Core.Remaining))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "search", g.Resources.Search.Remaining))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_remaining", "graphql", g.Resources.Graphql.Remaining))

	// GitHub Rate Reset: Resources
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_resources_reset", "GitHub Rate Reset: Resources"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_resources_reset", "count"))

	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "core", g.Resources.Core.Reset))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "search", g.Resources.Search.Reset))
	buf.WriteString(fmt.Sprintf("%s{type=\"%s\"} %d\n", "github_ratelimit_resources_reset", "graphql", g.Resources.Graphql.Reset))

	// GitHub Rate Rate
	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_limit", "GitHub Rate Limit"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_limit", "gauge"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_limit", g.Rate.Limit))

	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_remaining", "GitHub Rate Remaining"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_remaining", "gauge"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_remaining", g.Rate.Remaining))

	buf.WriteString(fmt.Sprintf("# HELP %s %s\n", "github_ratelimit_rate_reset", "GitHub Rate Reset"))
	buf.WriteString(fmt.Sprintf("# TYPE %s %s\n", "github_ratelimit_rate_reset", "count"))
	buf.WriteString(fmt.Sprintf("%s %d\n", "github_ratelimit_rate_reset", g.Rate.Reset))

	io.Copy(w, buf)
}

func main() {
	addr := flag.String("addr", "0.0.0.0:8080", "HTTP Server address")
	url := flag.String("url", "https://api.github.com", "Github API address")
	username := flag.String("username", "", "GitHub username")
	password := flag.String("password", "", "GitHub password")
	flag.Parse()

	Addr = *addr
	githubAddr = *url + "/rate_limit"
	githubUsername = *username
	githubPassword = *password

	log.Println("Starting GitHub exporter.")
	log.Println("Listening on:", "'" + Addr + "'",)
	log.Println("Scrapping:", "'" + githubAddr + "'", "with username", "'" + githubUsername + "'", "and password", "'" + strings.Repeat("*", len(githubPassword)) + "'", ".")

	server := &graceful.Server{
		Timeout: 10 * time.Second,
		Server: &http.Server{
			Addr:        Addr,
			ReadTimeout: time.Duration(5) * time.Second,
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				req, err := http.NewRequest("GET", githubAddr, nil)
				if err != nil {
					log.Println(err)
				}

				if (githubUsername != "") && (githubPassword != "") {
					req.SetBasicAuth(githubUsername, githubPassword)
				}

				transport := http.Transport{}
				resp, err := transport.RoundTrip(req)
				if err != nil {
					log.Println(err)
				}

				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					log.Println(err)
				}

				resp.Body.Close()

				res := GitHubRateLimit{}
				json.Unmarshal([]byte(body), &res)

				res.WriteTo(w)
			}),
		},
	}

	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

// 也可以以服务的方式启动nging
// 服务支持的操作有：
// nging service install  	-- 安装服务
// nging service uninstall  -- 卸载服务
// nging service start 		-- 启动服务
// nging service stop 		-- 停止服务
// nging service restart 	-- 重启服务
package main

//go:generate go get github.com/admpub/bindata/...
//go:generate go-bindata -fs -o bindata_assetfs.go -ignore "\\.(git|svn|DS_Store|less|scss)$" -minify "\\.(js|css)$" -tags bindata public/assets/... template/... config/i18n/...

import (
	//register

	"github.com/webx-top/echo"

	"github.com/admpub/log"
	_ "github.com/admpub/nging/application"
	"github.com/admpub/nging/application/cmd"
	_ "github.com/admpub/nging/application/initialize/manager"
	_ "github.com/admpub/nging/application/library/sqlite"
)

var (
	BUILD_TIME string
	CLOUD_GOX  string
	COMMIT     string
	LABEL      = `dev` //beta/alpha/stable
	VERSION    = `2.1.2`

	version   string
	schemaVer = 3.0 //数据表结构版本
)

func main() {
	defer log.Sync()
	echo.Set(`BUILD_TIME`, BUILD_TIME)
	echo.Set(`COMMIT`, COMMIT)
	echo.Set(`LABEL`, LABEL)
	echo.Set(`VERSION`, VERSION)
	echo.Set(`SCHEMA_VER`, schemaVer)
	exec()
}

func exec() {
	cmd.Execute()
}
<commit_msg>v2.2.0<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

// 也可以以服务的方式启动nging
// 服务支持的操作有：
// nging service install  	-- 安装服务
// nging service uninstall  -- 卸载服务
// nging service start 		-- 启动服务
// nging service stop 		-- 停止服务
// nging service restart 	-- 重启服务
package main

//go:generate go get github.com/admpub/bindata/...
//go:generate go-bindata -fs -o bindata_assetfs.go -ignore "\\.(git|svn|DS_Store|less|scss)$" -minify "\\.(js|css)$" -tags bindata public/assets/... template/... config/i18n/...

import (
	//register

	"github.com/webx-top/echo"

	"github.com/admpub/log"
	_ "github.com/admpub/nging/application"
	"github.com/admpub/nging/application/cmd"
	_ "github.com/admpub/nging/application/initialize/manager"
	_ "github.com/admpub/nging/application/library/sqlite"
)

var (
	BUILD_TIME string
	CLOUD_GOX  string
	COMMIT     string
	LABEL      = `dev` //beta/alpha/stable
	VERSION    = `2.2.0`

	version   string
	schemaVer = 3.0 //数据表结构版本
)

func main() {
	defer log.Sync()
	echo.Set(`BUILD_TIME`, BUILD_TIME)
	echo.Set(`COMMIT`, COMMIT)
	echo.Set(`LABEL`, LABEL)
	echo.Set(`VERSION`, VERSION)
	echo.Set(`SCHEMA_VER`, schemaVer)
	exec()
}

func exec() {
	cmd.Execute()
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

type record struct {
	name  string
	count int
	msg   string
	index int
}

type collector struct {
	w         io.Writer
	buf       *bytes.Buffer
	testName  string
	anyFailed bool
	records   map[string]record
	scanner   *bufio.Scanner
	curIndex  int
}

type recordList []record

func (rl recordList) Len() int      { return len(rl) }
func (rl recordList) Swap(i, j int) { rl[i], rl[j] = rl[j], rl[i] }
func (rl recordList) Less(i, j int) bool {
	if rl[i].count == rl[j].count {
		return rl[i].index < rl[j].index
	}
	return rl[i].count > rl[j].count
}

func newCollector(w io.Writer) *collector {
	return &collector{
		w:       w,
		buf:     new(bytes.Buffer),
		records: make(map[string]record, 0),
	}
}

func (c *collector) run(r io.Reader) {
	c.scanner = bufio.NewScanner(r)
	for c.scanner.Scan() {
		line := c.scanner.Text()
		c.parseLine(line)
	}
}

func (c *collector) parseLine(line string) {
	switch {
	case line == "FAIL" || line == "PASS":
	case strings.HasPrefix(line, "exit status"):
	case strings.HasPrefix(line, "=== RUN"):
		c.finishRecord()
	case strings.HasPrefix(line, "?") || strings.HasPrefix(line, "ok"):
		// These report the overall progress, showing
		// what packages were ok or had no tests.
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "FAIL"):
		// Package failure. Show results.
		c.finishRecord()
		for _, r := range c.sortedRecords() {
			fmt.Fprintf(c.w, "--- FAIL: %s (%d times)\n", r.name, r.count)
			fmt.Fprint(c.w, r.msg)
		}
		c.records = make(map[string]record, 0)
		fmt.Fprintln(c.w, "FAIL")
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "--- FAIL"):
		// Single test failure.
		c.finishRecord()
		c.testName = "Unknown"
		if sp := strings.Split(line, " "); len(sp) > 2 {
			c.testName = sp[2]
		}
		fmt.Fprintln(c.buf, c.testName)
	case c.testName != "":
		// Part of the current test error output
		fmt.Fprintln(c.buf, line)
	}
}

func (c *collector) finishRecord() {
	if c.testName == "" {
		return
	}
	c.anyFailed = true
	s := c.buf.String()
	if r, e := c.records[s]; e {
		r.count++
		c.records[s] = r
	} else {
		c.records[s] = record{
			name:  c.testName,
			count: 1,
			index: c.curIndex,
		}
		c.curIndex++
	}
	c.buf.Reset()
	c.testName = ""
}

func (c *collector) sortedRecords() []record {
	list := make(recordList, 0, len(c.records))
	for s, r := range c.records {
		if i := strings.Index(s, "\n"); i > 0 {
			s = s[i+1:]
		}
		r.msg = s
		list = append(list, r)
	}
	sort.Sort(list)
	return list
}

func main() {
	c := newCollector(os.Stdout)
	c.run(os.Stdin)
	if c.anyFailed {
		os.Exit(1)
	}
}
<commit_msg>Keep recordList close to its sort usage<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

type record struct {
	name  string
	count int
	msg   string
	index int
}

type collector struct {
	w         io.Writer
	buf       *bytes.Buffer
	testName  string
	anyFailed bool
	records   map[string]record
	scanner   *bufio.Scanner
	curIndex  int
}

func newCollector(w io.Writer) *collector {
	return &collector{
		w:       w,
		buf:     new(bytes.Buffer),
		records: make(map[string]record, 0),
	}
}

func (c *collector) run(r io.Reader) {
	c.scanner = bufio.NewScanner(r)
	for c.scanner.Scan() {
		line := c.scanner.Text()
		c.parseLine(line)
	}
}

func (c *collector) parseLine(line string) {
	switch {
	case line == "FAIL" || line == "PASS":
	case strings.HasPrefix(line, "exit status"):
	case strings.HasPrefix(line, "=== RUN"):
		c.finishRecord()
	case strings.HasPrefix(line, "?") || strings.HasPrefix(line, "ok"):
		// These report the overall progress, showing
		// what packages were ok or had no tests.
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "FAIL"):
		// Package failure. Show results.
		c.finishRecord()
		for _, r := range c.sortedRecords() {
			fmt.Fprintf(c.w, "--- FAIL: %s (%d times)\n", r.name, r.count)
			fmt.Fprint(c.w, r.msg)
		}
		c.records = make(map[string]record, 0)
		fmt.Fprintln(c.w, "FAIL")
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "--- FAIL"):
		// Single test failure.
		c.finishRecord()
		c.testName = "Unknown"
		if sp := strings.Split(line, " "); len(sp) > 2 {
			c.testName = sp[2]
		}
		fmt.Fprintln(c.buf, c.testName)
	case c.testName != "":
		// Part of the current test error output
		fmt.Fprintln(c.buf, line)
	}
}

func (c *collector) finishRecord() {
	if c.testName == "" {
		return
	}
	c.anyFailed = true
	s := c.buf.String()
	if r, e := c.records[s]; e {
		r.count++
		c.records[s] = r
	} else {
		c.records[s] = record{
			name:  c.testName,
			count: 1,
			index: c.curIndex,
		}
		c.curIndex++
	}
	c.buf.Reset()
	c.testName = ""
}

type recordList []record

func (rl recordList) Len() int      { return len(rl) }
func (rl recordList) Swap(i, j int) { rl[i], rl[j] = rl[j], rl[i] }
func (rl recordList) Less(i, j int) bool {
	if rl[i].count == rl[j].count {
		return rl[i].index < rl[j].index
	}
	return rl[i].count > rl[j].count
}

func (c *collector) sortedRecords() []record {
	list := make(recordList, 0, len(c.records))
	for s, r := range c.records {
		if i := strings.Index(s, "\n"); i > 0 {
			s = s[i+1:]
		}
		r.msg = s
		list = append(list, r)
	}
	sort.Sort(list)
	return list
}

func main() {
	c := newCollector(os.Stdout)
	c.run(os.Stdin)
	if c.anyFailed {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/voxelbrain/goptions"
	"github.com/voxelbrain/sabercat"
	"labix.org/v2/mgo"
)

var (
	consistencyDefault = MgoConsistencyMode(mgo.Eventual)
	options            = struct {
		MongoURL         *url.URL            `goptions:"-m, --mongodb, description='MongoDB URL to connect to (example: mongodb://localhost/db)', obligatory"`
		CollectionPrefix string              `goptions:"-c, --collection, description='Prefix of GridFS collection name'"`
		CacheTime        time.Duration       `goptions:"-t, --cache-time, description='Duration to keep files in cache'"`
		GridfsPrefix     string              `goptions:"-g, --gridfs-prefix, description='Prefix applied before requesting GridFS'"`
		HttpPrefix       string              `goptions:"-p, --http-prefix, description='Prefix under which GridFS is served'"`
		StripSlash       bool                `goptions:"-s, --strip-slash, description='Strip leading slash before requesting GridFS'"`
		ConsistencyMode  *MgoConsistencyMode `goptions:"--consistency, description='Mgo consistency mode (STRONG, MONOTONIC, EVENTUAL)'"`
		Address          *net.TCPAddr        `goptions:"-a, --address, description='Address to bind webserver to'"`
		Help             goptions.Help       `goptions:"-h, --help, description='Show this help'"`
	}{
		CollectionPrefix: "fs",
		HttpPrefix:       "/",
		Address: &net.TCPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: 8080,
		},
		ConsistencyMode: &consistencyDefault,
	}
)

func AddPrefix(prefix string, handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.URL.Path = prefix + r.URL.Path
		handler.ServeHTTP(w, r)
	})
}

func main() {
	goptions.ParseAndFail(&options)

	session, err := mgo.Dial(options.MongoURL.String())
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}
	options.ConsistencyMode.Apply(session)

	gfs := session.DB("").GridFS(options.CollectionPrefix)

	log.Printf("Starting server...")
	http.Handle("/",
		NewCache(options.CacheTime,
			http.StripPrefix(options.HttpPrefix,
				AddPrefix(options.GridfsPrefix,
					http.FileServer(sabercat.GridDir{
						GridFS:     gfs,
						StripSlash: options.StripSlash,
					})))))
	log.Fatalf("ListenAndServe: %s", http.ListenAndServe(options.Address.String(), nil))
}
<commit_msg>Use kartoffelsack<commit_after>package main

import (
	"log"
	"net"
	"net/http"
	"net/url"
	"time"

	"github.com/voxelbrain/goptions"
	"github.com/voxelbrain/kartoffelsack"
	"labix.org/v2/mgo"
)

var (
	consistencyDefault = MgoConsistencyMode(mgo.Eventual)
	options            = struct {
		MongoURL         *url.URL            `goptions:"-m, --mongodb, description='MongoDB URL to connect to (example: mongodb://localhost/db)', obligatory"`
		CollectionPrefix string              `goptions:"-c, --collection, description='Prefix of GridFS collection name'"`
		CacheTime        time.Duration       `goptions:"-t, --cache-time, description='Duration to keep files in cache'"`
		GridfsPrefix     string              `goptions:"-g, --gridfs-prefix, description='Prefix applied before requesting GridFS'"`
		HttpPrefix       string              `goptions:"-p, --http-prefix, description='Prefix under which GridFS is served'"`
		StripSlash       bool                `goptions:"-s, --strip-slash, description='Strip leading slash before requesting GridFS'"`
		ConsistencyMode  *MgoConsistencyMode `goptions:"--consistency, description='Mgo consistency mode (STRONG, MONOTONIC, EVENTUAL)'"`
		Address          *net.TCPAddr        `goptions:"-a, --address, description='Address to bind webserver to'"`
		Help             goptions.Help       `goptions:"-h, --help, description='Show this help'"`
	}{
		CollectionPrefix: "fs",
		HttpPrefix:       "/",
		Address: &net.TCPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: 8080,
		},
		ConsistencyMode: &consistencyDefault,
	}
)

func AddPrefix(prefix string, handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.URL.Path = prefix + r.URL.Path
		handler.ServeHTTP(w, r)
	})
}

func main() {
	goptions.ParseAndFail(&options)

	session, err := mgo.Dial(options.MongoURL.String())
	if err != nil {
		log.Fatalf("Could not connect to mongodb: %s", err)
	}
	options.ConsistencyMode.Apply(session)

	gfs := session.DB("").GridFS(options.CollectionPrefix)

	log.Printf("Starting server...")
	http.Handle("/",
		kartoffelsack.NewCache(options.CacheTime,
			http.StripPrefix(options.HttpPrefix,
				AddPrefix(options.GridfsPrefix,
					http.FileServer(kartoffelsack.GridDir{
						GridFS:     gfs,
						StripSlash: options.StripSlash,
					})))))
	log.Fatalf("ListenAndServe: %s", http.ListenAndServe(options.Address.String(), nil))
}
<|endoftext|>


<commit_before>package server

import (
	"bufio"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"path"
	"runtime"
	"strings"
	"time"

	"github.com/inconshreveable/go-update"
	"github.com/sirupsen/logrus"
)

const releaseServer = "http://dist-test.dividat.ch.s3.amazonaws.com/releases/driver/"

const updateInterval = 60 * time.Second

// LatestRelease metadata
type LatestRelease struct {
	Version string
	Commit  string
}

// Update diver: watch for a new version, then download and swap binary
func startUpdateLoop(log *logrus.Entry, channel string, version string) {
	updateTicker := time.NewTicker(updateInterval)
	for {
		select {
		case <-updateTicker.C:
			downloadAndApply(log.WithField("package", "server"), channel, version)
		}
	}
}

func downloadAndApply(log *logrus.Entry, channel string, version string) {
	log.Info("Checking if udpate is needed...")

	var latestURL = releaseServer + channel + "/latest.json"
	log.Debug("Downloading latest info from " + latestURL)
	latestResp, err := http.Get(latestURL)
	if err != nil {
		log.Error(err)
		return
	}

	log.Debug("Unmarshalling latest release data")
	latestRelease := new(LatestRelease)
	latestReleasePayload, _ := ioutil.ReadAll(latestResp.Body)
	if err = json.Unmarshal(latestReleasePayload, &latestRelease); err != nil {
		log.Error(err)
		return
	}

	if latestRelease.Version != version {
		log.Info("Current version (" + version + ") differs from latest version (" + latestRelease.Version + "), downloading update.")

		var filename = "dividat-driver-" + runtime.GOOS + "-" + runtime.GOARCH + "-" + latestRelease.Version
		var versionURL = releaseServer + path.Join(channel, latestRelease.Version, runtime.GOOS, filename)
		var shaURL = versionURL + ".sha256"

		log.Debug("Downloading new release from " + versionURL)
		var binResp *http.Response
		if binResp, err = http.Get(versionURL); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Downloading checksum file from " + shaURL)
		var shaResp *http.Response
		if shaResp, err = http.Get(shaURL); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Reading expected checksum")
		var expectedChecksum []byte
		if expectedChecksum, err = readExpectedChecksum(shaResp, filename); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Applying downloaded update")
		err = update.Apply(binResp.Body, update.Options{
			Checksum: expectedChecksum,
		})
		if err != nil {
			log.Error(err)
			return
		}

		log.Info("Update done.")
	} else {
		log.Info("Current version (" + version + ") is latest.")
	}
}

func readExpectedChecksum(shaResp *http.Response, filename string) ([]byte, error) {
	scanner := bufio.NewScanner(shaResp.Body)
	for scanner.Scan() {
		parts := strings.Split(scanner.Text(), "  ")
		if len(parts) == 2 && parts[1] == filename {
			return hex.DecodeString(parts[0])
		}
	}
	return nil, errors.New("Checksum not found for file " + filename)
}
<commit_msg>fix logging field, was wrongly overwritter<commit_after>package server

import (
	"bufio"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"path"
	"runtime"
	"strings"
	"time"

	"github.com/inconshreveable/go-update"
	"github.com/sirupsen/logrus"
)

const releaseServer = "http://dist-test.dividat.ch.s3.amazonaws.com/releases/driver/"

const updateInterval = 60 * time.Second

// LatestRelease metadata
type LatestRelease struct {
	Version string
	Commit  string
}

// Update diver: watch for a new version, then download and swap binary
func startUpdateLoop(log *logrus.Entry, channel string, version string) {
	updateTicker := time.NewTicker(updateInterval)
	for {
		select {
		case <-updateTicker.C:
			downloadAndApply(log, channel, version)
		}
	}
}

func downloadAndApply(log *logrus.Entry, channel string, version string) {
	log.Info("Checking if udpate is needed...")

	var latestURL = releaseServer + channel + "/latest.json"
	log.Debug("Downloading latest info from " + latestURL)
	latestResp, err := http.Get(latestURL)
	if err != nil {
		log.Error(err)
		return
	}

	log.Debug("Unmarshalling latest release data")
	latestRelease := new(LatestRelease)
	latestReleasePayload, _ := ioutil.ReadAll(latestResp.Body)
	if err = json.Unmarshal(latestReleasePayload, &latestRelease); err != nil {
		log.Error(err)
		return
	}

	if latestRelease.Version != version {
		log.Info("Current version (" + version + ") differs from latest version (" + latestRelease.Version + "), downloading update.")

		var filename = "dividat-driver-" + runtime.GOOS + "-" + runtime.GOARCH + "-" + latestRelease.Version
		var versionURL = releaseServer + path.Join(channel, latestRelease.Version, runtime.GOOS, filename)
		var shaURL = versionURL + ".sha256"

		log.Debug("Downloading new release from " + versionURL)
		var binResp *http.Response
		if binResp, err = http.Get(versionURL); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Downloading checksum file from " + shaURL)
		var shaResp *http.Response
		if shaResp, err = http.Get(shaURL); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Reading expected checksum")
		var expectedChecksum []byte
		if expectedChecksum, err = readExpectedChecksum(shaResp, filename); err != nil {
			log.Error(err)
			return
		}

		log.Debug("Applying downloaded update")
		err = update.Apply(binResp.Body, update.Options{
			Checksum: expectedChecksum,
		})
		if err != nil {
			log.Error(err)
			return
		}

		log.Info("Update done.")
	} else {
		log.Info("Current version (" + version + ") is latest.")
	}
}

func readExpectedChecksum(shaResp *http.Response, filename string) ([]byte, error) {
	scanner := bufio.NewScanner(shaResp.Body)
	for scanner.Scan() {
		parts := strings.Split(scanner.Text(), "  ")
		if len(parts) == 2 && parts[1] == filename {
			return hex.DecodeString(parts[0])
		}
	}
	return nil, errors.New("Checksum not found for file " + filename)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/vampirewalk/slackbot/Godeps/_workspace/src/github.com/nlopes/slack"
	"log"
	"net/url"
	"os"
	"strings"
)

func main() {
	token := os.Getenv("SLACK_TOKEN")
	if token == "" {
		log.Fatal("SLACK_TOKEN is required")
	}

	api := slack.New(token)
	channels, err := api.GetChannels(true)
	if err != nil {
		log.Fatal("Failed to get channels")
	}
	for _, channel := range channels {
		if !channel.IsMember {
			api.JoinChannel(channel.ID)
		}
	}
	bot := Bot{}

	rtm := api.NewRTM()
	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.ConnectedEvent:
				bot.SetMe(ev.Info.User)

			case *slack.MessageEvent:
				// if msg contains github url
				repoURL := bot.ExtractGithubRepoURL(ev.Msg.Text)
				log.Printf(repoURL)
				if repoURL != "" && !bot.IsMe(ev.Msg.User) {
					log.Printf("Received message \"%s\" from %s", ev.Msg.Text, ev.Msg.User)
					u, err := url.Parse(repoURL)
					if err != nil {
						log.Printf("URL error")
						rtm.SendMessage(rtm.NewOutgoingMessage("URL error", ev.Channel))
					}
					results := strings.Split(u.Path, "/")
					state, err := bot.GetRepoState(results[1], results[2])
					if err != nil {
						log.Printf("Parse error")
						rtm.SendMessage(rtm.NewOutgoingMessage("Parse error", ev.Channel))
					}
					report := bot.ReportRepoState(state)
					log.Printf(report)
					rtm.SendMessage(rtm.NewOutgoingMessage(report, ev.Channel))
				}

			case *slack.RTMError:
				log.Printf("Error: %s\n", ev.Error())

			case *slack.InvalidAuthEvent:
				log.Fatal("Invalid credentials")
				break Loop
			}
		}
	}
}
<commit_msg>don't fatal error<commit_after>package main

import (
	"github.com/vampirewalk/slackbot/Godeps/_workspace/src/github.com/nlopes/slack"
	"log"
	"net/url"
	"os"
	"strings"
)

func main() {
	token := os.Getenv("SLACK_TOKEN")
	if token == "" {
		log.Fatal("SLACK_TOKEN is required")
	}

	api := slack.New(token)
	channels, err := api.GetChannels(true)
	if err != nil {
		log.Print("Failed to get channels")
	}
	for _, channel := range channels {
		if !channel.IsMember {
			api.JoinChannel(channel.ID)
		}
	}
	bot := Bot{}

	rtm := api.NewRTM()
	go rtm.ManageConnection()

Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch ev := msg.Data.(type) {
			case *slack.ConnectedEvent:
				bot.SetMe(ev.Info.User)

			case *slack.MessageEvent:
				// if msg contains github url
				repoURL := bot.ExtractGithubRepoURL(ev.Msg.Text)
				log.Printf(repoURL)
				if repoURL != "" && !bot.IsMe(ev.Msg.User) {
					log.Printf("Received message \"%s\" from %s", ev.Msg.Text, ev.Msg.User)
					u, err := url.Parse(repoURL)
					if err != nil {
						log.Printf("URL error")
						rtm.SendMessage(rtm.NewOutgoingMessage("URL error", ev.Channel))
					}
					results := strings.Split(u.Path, "/")
					state, err := bot.GetRepoState(results[1], results[2])
					if err != nil {
						log.Printf("Parse error")
						rtm.SendMessage(rtm.NewOutgoingMessage("Parse error", ev.Channel))
					}
					report := bot.ReportRepoState(state)
					log.Printf(report)
					rtm.SendMessage(rtm.NewOutgoingMessage(report, ev.Channel))
				}

			case *slack.RTMError:
				log.Printf("Error: %s\n", ev.Error())

			case *slack.InvalidAuthEvent:
				log.Fatal("Invalid credentials")
				break Loop
			}
		}
	}
}
<|endoftext|>


<commit_before>// websocketd: See README
// -Joe Walnes

package websocketd

import (
	"io"
	"log"
	"net/http"
	"os/exec"
	"strings"

	"code.google.com/p/go.net/websocket"
)

func main() {
	config := parseCommandLine()

	http.Handle(config.BasePath, websocket.Handler(func(ws *websocket.Conn) {
		acceptWebSocket(ws, &config)
	}))

	if config.Verbose {
		log.Print("Listening on ws://", config.Addr, config.BasePath, " -> ", config.CommandName, " ", strings.Join(config.CommandArgs, " "))
	}
	err := http.ListenAndServe(config.Addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func acceptWebSocket(ws *websocket.Conn, config *Config) {
	defer ws.Close()

	if config.Verbose {
		log.Print("websocket: CONNECT")
		defer log.Print("websocket: DISCONNECT")
	}

	_, stdin, stdout, err := execCmd(config.CommandName, config.CommandArgs)
	if err != nil {
		if config.Verbose {
			log.Print("process: Failed to start: ", err)
		}
		return
	}

	done := make(chan bool)

	outbound := make(chan string, 256)
	go readProcess(stdout, outbound, done, config)
	go writeWebSocket(ws, outbound, done, config)

	inbound := make(chan string, 256)
	go readWebSocket(ws, inbound, done, config)
	go writeProcess(stdin, inbound, done, config)

	<-done
}

func execCmd(commandName string, commandArgs []string) (*exec.Cmd, io.WriteCloser, io.ReadCloser, error) {
	cmd := exec.Command(commandName, commandArgs...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return cmd, nil, nil, err
	}

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return cmd, nil, nil, err
	}

	err = cmd.Start()
	if err != nil {
		return cmd, nil, nil, err
	}

	return cmd, stdin, stdout, err
}
<commit_msg>Removed pointless buffers.<commit_after>// websocketd: See README
// -Joe Walnes

package websocketd

import (
	"io"
	"log"
	"net/http"
	"os/exec"
	"strings"

	"code.google.com/p/go.net/websocket"
)

func main() {
	config := parseCommandLine()

	http.Handle(config.BasePath, websocket.Handler(func(ws *websocket.Conn) {
		acceptWebSocket(ws, &config)
	}))

	if config.Verbose {
		log.Print("Listening on ws://", config.Addr, config.BasePath, " -> ", config.CommandName, " ", strings.Join(config.CommandArgs, " "))
	}
	err := http.ListenAndServe(config.Addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func acceptWebSocket(ws *websocket.Conn, config *Config) {
	defer ws.Close()

	if config.Verbose {
		log.Print("websocket: CONNECT")
		defer log.Print("websocket: DISCONNECT")
	}

	_, stdin, stdout, err := execCmd(config.CommandName, config.CommandArgs)
	if err != nil {
		if config.Verbose {
			log.Print("process: Failed to start: ", err)
		}
		return
	}

	done := make(chan bool)

	outbound := make(chan string)
	go readProcess(stdout, outbound, done, config)
	go writeWebSocket(ws, outbound, done, config)

	inbound := make(chan string)
	go readWebSocket(ws, inbound, done, config)
	go writeProcess(stdin, inbound, done, config)

	<-done
}

func execCmd(commandName string, commandArgs []string) (*exec.Cmd, io.WriteCloser, io.ReadCloser, error) {
	cmd := exec.Command(commandName, commandArgs...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return cmd, nil, nil, err
	}

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return cmd, nil, nil, err
	}

	err = cmd.Start()
	if err != nil {
		return cmd, nil, nil, err
	}

	return cmd, stdin, stdout, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"bytes"
	"os/exec"
)

//  only modeling the parts of the responses as I need them
type kubectlItem struct {
	Metadata	struct {
		Name 		string	`json:"name"`
		Uid		string	`json:"uid"`
	} 				`json:"metadata"`
	Spec	interface{}	`json:"spec"`
	Status	 struct {
		Replicas	int	`json:"replicas"`
	}				`json:"status"`
}

type kubectlService struct {
	Status		struct {
		LoadBalancer	struct {
			Ingress	[]struct {
				IP	string 	`json:"ip"`
			} 			`json:"ingress"`
		}				`json:"loadBalancer"`
	} 					`json:"status"`
}

func addExtraArgs(run_args []string, optional_args, env_args map[string]string) ([]string) {
	for k, v := range optional_args {
		run_args = append(run_args, "--" + k + "=" +v)
	}
	for k, v := range env_args {
		run_args = append(run_args, "--env=" + k + "=" + v)
	}

	return run_args
}

func CreateKubeRC(name, dockerImage, external_port string, optional_args, env_args map[string]string) (string, error) {
	kubectl_cmd := "kubectl"
	kubectl_run_args :=[]string{"run", name, "--image=" + dockerImage, "--output=json"}
	kubectl_run_args = addExtraArgs(kubectl_run_args, optional_args, env_args)
	run_replicacontroler := exec.Command(kubectl_cmd, kubectl_run_args...)
	var stdout, stderr bytes.Buffer
	run_replicacontroler.Stdout = &stdout
	run_replicacontroler.Stderr = &stderr
	err := run_replicacontroler.Run()
	if err != nil {
		return "", fmt.Errorf("Error creating replicacontroler named %q with error %q and stdout: %q", name, stderr.String(), stdout.String())
	}

	var runReturn kubectlItem
	err = parseJSON(&runReturn, stdout.String())
	if err != nil {
		return "", err
	}
	uid := runReturn.Metadata.Uid

	var ex_err error
	if external_port != "" {
		ex_err = expose_rc_externally(name, external_port)
	}

	return uid,ex_err
}

func expose_rc_externally(name, external_port string) (error) {
	expose_rc := exec.Command("kubectl", "expose", "deployments", name, "--port=" + external_port, "--type=LoadBalancer", "--output=json")
	var stdout, stderr bytes.Buffer
	expose_rc.Stdout = &stdout
	expose_rc.Stderr = &stderr
	err := expose_rc.Run()
	if err != nil {
		return fmt.Errorf("Error creating external load balancer on a specific port: %q, with stdout: %q", stderr.String(), stdout.String())
	}

	// wait at most 10 minutes for external ip to be set
	exip_set := false
	for i := 0; i < (10 * 6) && !exip_set; i++ {
		time.Sleep(10 * time.Second)
		exip, err := fetchExternalIp(name)
		if err != nil {
			return err
		}

		if exip != "" {
			exip_set = true
		}
	}

	return nil
}

//  calling function needs to handle if the read is successful but the rc is dead or has no replicas
func ReadKubeRC(name, external_port string) (int, string, error) {
	get_replicacontrolers := exec.Command("kubectl", "get", "deployments", name, "--output=json")
	var stdout, stderr bytes.Buffer
	get_replicacontrolers.Stdout = &stdout
	get_replicacontrolers.Stderr = &stderr
	err := get_replicacontrolers.Run()
	if err != nil {
		return -1, "", fmt.Errorf("Error listing replica controlers: %q with stdout: %q", stderr.String(), stdout.String())
	}

	var getReturn kubectlItem
	err = parseJSON(&getReturn, stdout.String())
	if err != nil {
		return -1, "", err
	}

	var ex_err error
	var external_ip string
	if external_port != "" {
		external_ip, ex_err = fetchExternalIp(name)
	}
	return getReturn.Status.Replicas, external_ip, ex_err
}

func fetchExternalIp(name string) (string, error) {
	get_services := exec.Command("kubectl", "get", "services", name, "--output=json")
	var stdout, stderr bytes.Buffer
	get_services.Stdout = &stdout
	get_services.Stderr = &stderr
	err := get_services.Run()
	if err != nil {
		return "", fmt.Errorf("Error fetching services information for this cluster: %q and stdout: %q", stderr.String(), stdout.String())
	}

	var getReturn kubectlService
	err = parseJSON(&getReturn, stdout.String())
	if err != nil {
		return "", err
	}

	var ex_ip string
	if len(getReturn.Status.LoadBalancer.Ingress) != 0 {
		ex_ip = getReturn.Status.LoadBalancer.Ingress[0].IP
	}

	return ex_ip, nil
}

func DeleteKubeRC(name, external_port string) (error) {
	if external_port != "" {
		err := deleteLoadBalanacerService(name)
		if err != nil {
			return err
		}
	}
	delete_replicacontrolers := exec.Command("kubectl", "delete", "deployments", name)
	var stdout, stderr bytes.Buffer
	delete_replicacontrolers.Stdout = &stdout
	delete_replicacontrolers.Stderr = &stderr
	err := delete_replicacontrolers.Run()
	if err != nil {
		return  fmt.Errorf("Error deleting replica controler: %q and stdout: %q", stderr.String(), stdout.String())
	}

	return nil
}

func deleteLoadBalanacerService(name string) (error) {
	delete_loadbalancer_service := exec.Command("kubectl", "delete", "svc", name)
	var stdout, stderr bytes.Buffer
	delete_loadbalancer_service.Stdout = &stdout
	delete_loadbalancer_service.Stderr = &stderr
	err := delete_loadbalancer_service.Run()
	if err != nil {
		return  fmt.Errorf("Error deleting service: %q with stdout: %q", stderr.String(), stdout.String())
	}

	return nil
}
<commit_msg>remove return from kuberc and just have a print statement<commit_after>package main

import (
	"fmt"
	"time"
	"bytes"
	"os/exec"
)

//  only modeling the parts of the responses as I need them
type kubectlItem struct {
	Metadata	struct {
		Name 		string	`json:"name"`
		Uid		string	`json:"uid"`
	} 				`json:"metadata"`
	Spec	interface{}	`json:"spec"`
	Status	 struct {
		Replicas	int	`json:"replicas"`
	}				`json:"status"`
}

type kubectlService struct {
	Status		struct {
		LoadBalancer	struct {
			Ingress	[]struct {
				IP	string 	`json:"ip"`
			} 			`json:"ingress"`
		}				`json:"loadBalancer"`
	} 					`json:"status"`
}

func addExtraArgs(run_args []string, optional_args, env_args map[string]string) ([]string) {
	for k, v := range optional_args {
		run_args = append(run_args, "--" + k + "=" +v)
	}
	for k, v := range env_args {
		run_args = append(run_args, "--env=" + k + "=" + v)
	}

	return run_args
}

func CreateKubeRC(name, dockerImage, external_port string, optional_args, env_args map[string]string) (string, error) {
	kubectl_cmd := "kubectl"
	kubectl_run_args :=[]string{"run", name, "--image=" + dockerImage, "--output=json"}
	kubectl_run_args = addExtraArgs(kubectl_run_args, optional_args, env_args)
	run_replicacontroler := exec.Command(kubectl_cmd, kubectl_run_args...)
	var stdout, stderr bytes.Buffer
	run_replicacontroler.Stdout = &stdout
	run_replicacontroler.Stderr = &stderr
	err := run_replicacontroler.Run()
	if err != nil {
		fmt.Printf("Error creating replicacontroler named %q with error %q and stdout: %q", name, stderr.String(), stdout.String())
	}

	var runReturn kubectlItem
	err = parseJSON(&runReturn, stdout.String())
	if err != nil {
		return "", err
	}
	uid := runReturn.Metadata.Uid

	var ex_err error
	if external_port != "" {
		ex_err = expose_rc_externally(name, external_port)
	}

	return uid,ex_err
}

func expose_rc_externally(name, external_port string) (error) {
	expose_rc := exec.Command("kubectl", "expose", "deployments", name, "--port=" + external_port, "--type=LoadBalancer", "--output=json")
	var stdout, stderr bytes.Buffer
	expose_rc.Stdout = &stdout
	expose_rc.Stderr = &stderr
	err := expose_rc.Run()
	if err != nil {
		fmt.Printf("Error creating external load balancer on a specific port: %q, with stdout: %q", stderr.String(), stdout.String())
	}

	// wait at most 10 minutes for external ip to be set
	exip_set := false
	for i := 0; i < (10 * 6) && !exip_set; i++ {
		time.Sleep(10 * time.Second)
		exip, err := fetchExternalIp(name)
		if err != nil {
			return err
		}

		if exip != "" {
			exip_set = true
		}
	}

	return nil
}

//  calling function needs to handle if the read is successful but the rc is dead or has no replicas
func ReadKubeRC(name, external_port string) (int, string, error) {
	get_replicacontrolers := exec.Command("kubectl", "get", "deployments", name, "--output=json")
	var stdout, stderr bytes.Buffer
	get_replicacontrolers.Stdout = &stdout
	get_replicacontrolers.Stderr = &stderr
	err := get_replicacontrolers.Run()
	if err != nil {
		fmt.Printf("Error listing replica controlers: %q with stdout: %q", stderr.String(), stdout.String())
	}

	var getReturn kubectlItem
	err = parseJSON(&getReturn, stdout.String())
	if err != nil {
		return -1, "", err
	}

	var ex_err error
	var external_ip string
	if external_port != "" {
		external_ip, ex_err = fetchExternalIp(name)
	}
	return getReturn.Status.Replicas, external_ip, ex_err
}

func fetchExternalIp(name string) (string, error) {
	get_services := exec.Command("kubectl", "get", "services", name, "--output=json")
	var stdout, stderr bytes.Buffer
	get_services.Stdout = &stdout
	get_services.Stderr = &stderr
	err := get_services.Run()
	if err != nil {
		fmt.Errorf("Error fetching services information for this cluster: %q and stdout: %q", stderr.String(), stdout.String())
	}

	var getReturn kubectlService
	err = parseJSON(&getReturn, stdout.String())
	if err != nil {
		return "", err
	}

	var ex_ip string
	if len(getReturn.Status.LoadBalancer.Ingress) != 0 {
		ex_ip = getReturn.Status.LoadBalancer.Ingress[0].IP
	}

	return ex_ip, nil
}

func DeleteKubeRC(name, external_port string) (error) {
	if external_port != "" {
		err := deleteLoadBalanacerService(name)
		if err != nil {
			return err
		}
	}
	delete_replicacontrolers := exec.Command("kubectl", "delete", "deployments", name)
	var stdout, stderr bytes.Buffer
	delete_replicacontrolers.Stdout = &stdout
	delete_replicacontrolers.Stderr = &stderr
	err := delete_replicacontrolers.Run()
	if err != nil {
		fmt.Printf("Error deleting replica controler: %q and stdout: %q", stderr.String(), stdout.String())
	}

	return nil
}

func deleteLoadBalanacerService(name string) (error) {
	delete_loadbalancer_service := exec.Command("kubectl", "delete", "svc", name)
	var stdout, stderr bytes.Buffer
	delete_loadbalancer_service.Stdout = &stdout
	delete_loadbalancer_service.Stderr = &stderr
	err := delete_loadbalancer_service.Run()
	if err != nil {
		return  fmt.Errorf("Error deleting service: %q with stdout: %q", stderr.String(), stdout.String())
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/dgraph-io/badger"
	"github.com/gorilla/mux"
	gonanoid "github.com/matoous/go-nanoid"
	"github.com/rs/xid"
)

var port = 8080
var addr = fmt.Sprintf(":%d", port)
var db badger.DB

func main() {
	// db
	opts := badger.DefaultOptions
	opts.Dir = "./db"
	opts.ValueDir = "./db"
	opts.NumVersionsToKeep = math.MaxInt32

	db, err := badger.Open(opts)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// create router
	router := mux.NewRouter().StrictSlash(true)

	// api
	api := router.PathPrefix("/api").Subrouter()
	api.HandleFunc("/health", health).Methods("GET")
	api.HandleFunc("/rp", createRp()).Methods("POST")
	api.HandleFunc("/rp/import", todo).Methods("POST")
	api.HandleFunc("/rp/import/{id:[-0-9a-zA-Z]+}", todo).Methods("POST")
	api.HandleFunc("/user", todo).Methods("POST")
	api.HandleFunc("/user/verify", verifyUser).Methods("GET")
	roomAPI := api.PathPrefix("/rp/{id:[-0-9a-zA-Z]+}").Subrouter()
	roomAPI.HandleFunc("/", rpChat).Methods("GET")
	roomAPI.HandleFunc("/updates", rpChatUpdates).Methods("GET").Queries("since", "{since:[1-9][0-9]*}")
	roomAPI.HandleFunc("/pages", todo).Methods("GET")
	roomAPI.HandleFunc("/pages/{pageNum:[1-9][0-9]*}", todo).Methods("GET")
	roomAPI.HandleFunc("/download.txt", todo).Methods("GET")
	roomAPI.HandleFunc("/export", todo).Methods("GET")
	roomAPI.HandleFunc("/{collections:[a-z]+}", todo).Methods("POST")
	roomAPI.HandleFunc("/{collections:[a-z]+}/{docId:[0-9a-z]+}", todo).Methods("PUT")
	roomAPI.HandleFunc("/{collections:[a-z]+}/history", todo).Methods("GET")
	api.PathPrefix("/").HandlerFunc(apiMalformed)

	// routes
	router.HandleFunc("/", indexHTML).Methods("GET")
	router.HandleFunc("/terms", indexHTML).Methods("GET")
	router.HandleFunc("/format", indexHTML).Methods("GET")
	router.HandleFunc("/rp/{rpCode}", indexHTML).Methods("GET")
	router.HandleFunc("/read/{rpCode}", indexHTML).Methods("GET")
	router.HandleFunc("/read/{rpCode}/page/{page}", indexHTML).Methods("GET")

	// assets
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("views/dist")))

	// listen
	fmt.Printf("Listening on %s\n", addr)
	log.Fatal(http.ListenAndServe(addr, router))
}

func health(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, `{"rpnow":"ok"}`)
}

func createRp() http.HandlerFunc {
	type request struct {
		Title string `json:"title"`
	}
	return func(w http.ResponseWriter, r *http.Request) {
		var fields request
		if err := json.NewDecoder(r.Body).Decode(&fields); err != nil {
			panic(err)
		}
		fmt.Println(fields)
		url, err := gonanoid.Nanoid()
		if err != nil {
			panic(err)
		}
		rpid := xid.New()
		// err = db.Update(func(tx *bolt.Tx) error {
		// 	rp, err := tx.CreateBucket(rpid.Bytes())
		// 	if err != nil {
		// 		return err
		// 	}
		// 	_ = rp // TODO put field meta in rp bucket

		// 	urls := tx.Bucket([]byte("urls"))
		// 	err = urls.Put([]byte(url), rpid.Bytes())
		// 	if err != nil {
		// 		return err
		// 	}
		// 	return nil
		// })
		// if err != nil {
		// 	panic(err)
		// }
		_, _ = url, rpid
		json.NewEncoder(w).Encode(map[string]string{"rpCode": "abc"})
	}
}

func rpChat(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	fmt.Println(params)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"title":       "Test API",
		"msgs":        []interface{}{},
		"charas":      []interface{}{},
		"lastEventId": 2,
		"readCode":    "abc-read",
	})
}

func rpChatUpdates(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	fmt.Println(params)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"lastEventId": params["since"],
		"updates":     []interface{}{},
	})
}

func verifyUser(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
}

func indexHTML(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "views/dist/index.html")
}

func apiMalformed(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "{\"error\":\"Malformed request\"}")
}

func todo(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotImplemented)
	fmt.Fprintln(w, "TODO")
}
<commit_msg>Gracefully shut down http server<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/dgraph-io/badger"
	"github.com/gorilla/mux"
	gonanoid "github.com/matoous/go-nanoid"
	"github.com/rs/xid"
)

var port = 8080
var addr = fmt.Sprintf(":%d", port)
var db badger.DB

func main() {
	// Print "Goodbye" after all defer statements are done
	defer log.Println("Goodbye!")

	// db
	opts := badger.DefaultOptions
	opts.Dir = "./db"
	opts.ValueDir = "./db"
	opts.NumVersionsToKeep = math.MaxInt32

	db, err := badger.Open(opts)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// create router
	router := mux.NewRouter().StrictSlash(true)

	// api
	api := router.PathPrefix("/api").Subrouter()
	api.HandleFunc("/health", health).Methods("GET")
	api.HandleFunc("/rp", createRp()).Methods("POST")
	api.HandleFunc("/rp/import", todo).Methods("POST")
	api.HandleFunc("/rp/import/{id:[-0-9a-zA-Z]+}", todo).Methods("POST")
	api.HandleFunc("/user", todo).Methods("POST")
	api.HandleFunc("/user/verify", verifyUser).Methods("GET")
	roomAPI := api.PathPrefix("/rp/{id:[-0-9a-zA-Z]+}").Subrouter()
	roomAPI.HandleFunc("/", rpChat).Methods("GET")
	roomAPI.HandleFunc("/updates", rpChatUpdates).Methods("GET").Queries("since", "{since:[1-9][0-9]*}")
	roomAPI.HandleFunc("/pages", todo).Methods("GET")
	roomAPI.HandleFunc("/pages/{pageNum:[1-9][0-9]*}", todo).Methods("GET")
	roomAPI.HandleFunc("/download.txt", todo).Methods("GET")
	roomAPI.HandleFunc("/export", todo).Methods("GET")
	roomAPI.HandleFunc("/{collections:[a-z]+}", todo).Methods("POST")
	roomAPI.HandleFunc("/{collections:[a-z]+}/{docId:[0-9a-z]+}", todo).Methods("PUT")
	roomAPI.HandleFunc("/{collections:[a-z]+}/history", todo).Methods("GET")
	api.PathPrefix("/").HandlerFunc(apiMalformed)

	// routes
	router.HandleFunc("/", indexHTML).Methods("GET")
	router.HandleFunc("/terms", indexHTML).Methods("GET")
	router.HandleFunc("/format", indexHTML).Methods("GET")
	router.HandleFunc("/rp/{rpCode}", indexHTML).Methods("GET")
	router.HandleFunc("/read/{rpCode}", indexHTML).Methods("GET")
	router.HandleFunc("/read/{rpCode}/page/{page}", indexHTML).Methods("GET")

	// assets
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("views/dist")))

	// listen
	srv := &http.Server{
		Addr: addr,
		// Good practice to set timeouts to avoid Slowloris attacks.
		WriteTimeout: time.Second * 15,
		ReadTimeout:  time.Second * 15,
		IdleTimeout:  time.Second * 60,
		Handler:      router, // Pass our instance of gorilla/mux in.
	}
	go func() {
		if err := srv.ListenAndServe(); err != http.ErrServerClosed {
			log.Fatalf("listen and serve: %s", err)
		}
	}()

	log.Printf("Listening on %s\n", addr)

	// await kill signal
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	<-c

	// gracefully end http server
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		log.Fatalf("http shutdown: %s", err)
	}
	log.Println("Http server stopped")
}

func health(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, `{"rpnow":"ok"}`)
}

func createRp() http.HandlerFunc {
	type request struct {
		Title string `json:"title"`
	}
	return func(w http.ResponseWriter, r *http.Request) {
		var fields request
		if err := json.NewDecoder(r.Body).Decode(&fields); err != nil {
			panic(err)
		}
		log.Println(fields)
		url, err := gonanoid.Nanoid()
		if err != nil {
			panic(err)
		}
		rpid := xid.New()
		// err = db.Update(func(tx *bolt.Tx) error {
		// 	rp, err := tx.CreateBucket(rpid.Bytes())
		// 	if err != nil {
		// 		return err
		// 	}
		// 	_ = rp // TODO put field meta in rp bucket

		// 	urls := tx.Bucket([]byte("urls"))
		// 	err = urls.Put([]byte(url), rpid.Bytes())
		// 	if err != nil {
		// 		return err
		// 	}
		// 	return nil
		// })
		// if err != nil {
		// 	panic(err)
		// }
		_, _ = url, rpid
		json.NewEncoder(w).Encode(map[string]string{"rpCode": "abc"})
	}
}

func rpChat(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	log.Println(params)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"title":       "Test API",
		"msgs":        []interface{}{},
		"charas":      []interface{}{},
		"lastEventId": 2,
		"readCode":    "abc-read",
	})
}

func rpChatUpdates(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	log.Println(params)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"lastEventId": params["since"],
		"updates":     []interface{}{},
	})
}

func verifyUser(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
}

func indexHTML(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "views/dist/index.html")
}

func apiMalformed(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, "{\"error\":\"Malformed request\"}")
}

func todo(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotImplemented)
	fmt.Fprintln(w, "TODO")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
)

const ()

func query(word string) {
	var url string
	isChinese := IsChinese(word)

	if isChinese {
		url = "http://dict.youdao.com/w/eng/%s"
	} else {
		url = "http://dict.youdao.com/w/%s"
	}

	doc, err := goquery.NewDocument(fmt.Sprintf(url, word))
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	if isChinese {
		// Find the result
		fmt.Println()
		doc.Find(".trans-container > ul > p > span.contentTitle").Each(func(i int, s *goquery.Selection) {
			color.Yellow("    %s", s.Find(".search-js").Text())
		})
	} else {
		// Find the result
		result := doc.Find("div#phrsListTab > div.trans-container > ul").Text()
		color.Green(result)
	}

	// Show examples
	sentences := getSentences(doc, isChinese)
	if len(sentences) > 0 {
		fmt.Println()
		for _, sentence := range sentences {
			color.Green("    %s", sentence[0])
			color.Magenta("    %s", sentence[1])
		}
		fmt.Println()
	}
}

func getSentences(doc *goquery.Document, isChinese bool) [][]string {
	result := [][]string{}
	doc.Find("#bilingual ul li").Each(func(_ int, s *goquery.Selection) {
		r := []string{}
		s.Children().Each(func(ii int, ss *goquery.Selection) {
			// Ignore source
			if ii == 2 {
				return
			}
			var sentence string
			ss.Children().Each(func(iii int, sss *goquery.Selection) {
				if text := strings.TrimSpace(sss.Text()); text != "" {
					addSpace := (ii == 1 && isChinese) || (ii == 0 && !isChinese)
					if addSpace && iii != 0 && text != "." {
						text = " " + text
					}
					sentence += text
				}
			})
			r = append(r, sentence)
		})
		if len(r) == 2 {
			result = append(result, r)
		}
	})
	return result
}

func main() {
	if len(os.Args) == 1 {
		displayUsage()
		os.Exit(0)
	}

	words := strings.Join(os.Args[1:], " ")
	query(words)
}
<commit_msg>adjust output color<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
)

const ()

func query(word string) {
	var url string
	isChinese := IsChinese(word)

	if isChinese {
		url = "http://dict.youdao.com/w/eng/%s"
	} else {
		url = "http://dict.youdao.com/w/%s"
	}

	doc, err := goquery.NewDocument(fmt.Sprintf(url, word))
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	if isChinese {
		// Find the result
		fmt.Println()
		doc.Find(".trans-container > ul > p > span.contentTitle").Each(func(i int, s *goquery.Selection) {
			color.Green("    %s", s.Find(".search-js").Text())
		})
	} else {
		// Find the result
		result := doc.Find("div#phrsListTab > div.trans-container > ul").Text()
		color.Green(result)
	}

	// Show examples
	sentences := getSentences(doc, isChinese)
	if len(sentences) > 0 {
		fmt.Println()
		for _, sentence := range sentences {
			color.Green("    %s", sentence[0])
			color.Magenta("    %s", sentence[1])
		}
		fmt.Println()
	}
}

func getSentences(doc *goquery.Document, isChinese bool) [][]string {
	result := [][]string{}
	doc.Find("#bilingual ul li").Each(func(_ int, s *goquery.Selection) {
		r := []string{}
		s.Children().Each(func(ii int, ss *goquery.Selection) {
			// Ignore source
			if ii == 2 {
				return
			}
			var sentence string
			ss.Children().Each(func(iii int, sss *goquery.Selection) {
				if text := strings.TrimSpace(sss.Text()); text != "" {
					addSpace := (ii == 1 && isChinese) || (ii == 0 && !isChinese)
					if addSpace && iii != 0 && text != "." {
						text = " " + text
					}
					sentence += text
				}
			})
			r = append(r, sentence)
		})
		if len(r) == 2 {
			result = append(result, r)
		}
	})
	return result
}

func main() {
	if len(os.Args) == 1 {
		displayUsage()
		os.Exit(0)
	}

	words := strings.Join(os.Args[1:], " ")
	query(words)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"time"
	"net/http"
	"encoding/json"
	"github.com/rancher/go-rancher/client"
	"os"
	"github.com/ahaynssen/slack-go-webhook"
)

type Rancher struct {
	Url        string `json:"url"`
	AccessKey  string `json:"access_key"`
	SecretKey  string `json:"secret_key"`
	Service    string `json:"service"`
	Image      string `json:"docker_image"`
	StartFirst bool   `json:"start_first"`
	Confirm    bool   `json:"confirm"`
	Timeout    int    `json:"timeout"`
}

func main() {
	fmt.Println("Started upgrade server")
	http.HandleFunc("/upgrade/", requestSuccess)
	http.ListenAndServe(":8080", nil)
}

func requestSuccess(w http.ResponseWriter, r *http.Request){
	vargs := Rancher{
		StartFirst: false,
		Timeout:    30,
	}

	err := json.NewDecoder(r.Body).Decode(&vargs)
	if err != nil {
		fmt.Printf(err.Error())
		Error(w, err.Error(), 400)
		return
	} else {
		if len(vargs.Url) == 0 || len(vargs.AccessKey) == 0 || len(vargs.SecretKey) == 0 {
			Error(w, "Rancher credentials not set", 400)
			return
		}
		go upgradeRancher(vargs)
		w.WriteHeader(200)
		return
	}
}

func upgradeRancher(vargs Rancher) {
	var wantedImage, wantedVer string
	if !strings.HasPrefix(vargs.Image, "docker:") {
		vargs.Image = fmt.Sprintf("docker:%s", vargs.Image)
		parts := strings.Split(vargs.Image, ":")
		wantedImage = parts[1]
		wantedVer = parts[2]
	}
	parts := strings.Split(wantedImage, "/")
	vargs.Service = parts[1]

	rancher, err := client.NewRancherClient(&client.ClientOpts{
		Url:       vargs.Url,
		AccessKey: vargs.AccessKey,
		SecretKey: vargs.SecretKey,
	})

	if err != nil {
		fmt.Printf("Failed to create rancher client: %s\n", err)
		return
	}

	services, err := rancher.Service.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to list rancher services: %s\n", err)
		return
	}

	var upgradeLabel = os.Getenv("UPGRADE_LABEL")

	var foundImage, foundVer string
	for services != nil {
		for _, svc := range services.Data {
			if svc.LaunchConfig != nil {
				if _, ok := svc.LaunchConfig.Labels[upgradeLabel]; ok {
					parts := strings.Split(svc.LaunchConfig.ImageUuid, ":")
					foundImage = parts[1]
					foundVer = parts[2]
					if foundImage == wantedImage && ((foundVer < wantedVer) || (wantedVer == "latest")) {
						fmt.Println("Trying to upgrade...")
						err := doUpgrade(vargs, svc, rancher)
						if err != nil {
							fmt.Println(err.Error())
						} else {
							if (vargs.Confirm) {
								fmt.Println("Trying to confirm...")
								err := confirmUpgrade(vargs, svc, rancher)
								url := fmt.Sprintf("https://rancher.connectedfleet.io/env/%s/apps/stacks/%s", svc.AccountId, svc.EnvironmentId)
								if err != nil {
									fmt.Println("Unable to upgrade service %s: %s\n", vargs.Service, err.Error())
									message := fmt.Sprintf("Unable to confirm upgrade to `%s`.\nCheck status at <%[2]s|%[1]s>", vargs.Service, url)
									slackMessage("danger", message)
								} else {
									fmt.Printf("Upgraded %s to %s\n", svc.Name, vargs.Image)
									message := fmt.Sprintf("`%[1]s` has been successfully upgraded to `%[2]s` "+
											       "in Dev\n View in Rancher here: <%[3]s|%[1]s>", vargs.Service, wantedVer, url)
									slackMessage("good", message)

								}
							}
						}
						continue
					}
				}
			}
		}
		services, err = services.Next()
	}
}

func doUpgrade(vargs Rancher, service client.Service, rancher *client.RancherClient) (error) {
	service.LaunchConfig.ImageUuid = vargs.Image
	upgrade := &client.ServiceUpgrade{}
	upgrade.InServiceStrategy = &client.InServiceUpgradeStrategy{
		LaunchConfig:           service.LaunchConfig,
		SecondaryLaunchConfigs: service.SecondaryLaunchConfigs,
		StartFirst:             vargs.StartFirst,
	}
	upgrade.ToServiceStrategy = &client.ToServiceUpgradeStrategy{}
	_, err := rancher.Service.ActionUpgrade(&service, upgrade)
	return err
}

func confirmUpgrade(vargs Rancher, service client.Service, rancher *client.RancherClient) (error) {
	srv, err := retry(func() (interface{}, error) {
		s, e := rancher.Service.ById(service.Id)
		if e != nil {
			return nil, e
		}
		if s.State != "upgraded" {
			return nil, fmt.Errorf("Service not upgraded: %s\n", s.State)
		}
		return s, nil
	}, time.Duration(vargs.Timeout)*time.Second, 3*time.Second)
	if err != nil {
		return err
	}

	_, err = rancher.Service.ActionFinishupgrade(srv.(*client.Service))
	if err != nil {
		return err
	}
	fmt.Printf("Finished upgrade %s\n", vargs.Service)
	return err
}

type retryFunc func() (interface{}, error)

func retry(f retryFunc, timeout time.Duration, interval time.Duration) (interface{}, error) {
	finish := time.After(timeout)
	for {
		result, err := f()
		if err == nil {
			return result, nil
		}
		select {
		case <-finish:
			return nil, err
		case <-time.After(interval):
		}
	}
}

func Error(w http.ResponseWriter, error string, code int) {
	w.Header().Set("Content Type,", "text/plain; charset=UTF-8")
	w.WriteHeader(code)
	fmt.Fprint(w, error)
}

func slackMessage(status string, message string) {
	var webhookUrl = os.Getenv("SLACK_WEBHOOK")

	attachment := slack.Attachment {Color: &status, Text: &message}
	mrkdwn := "text"
	attachment.AddMrkdwn(&mrkdwn)
	payload := slack.Payload {
		Username: "rancher-updater-service",
		Attachments: []slack.Attachment{attachment},
	}
	printable, _ := json.Marshal(payload)
	fmt.Println(string(printable))
	err := slack.Send(webhookUrl, "", payload)
	if len(err) > 0 {
		fmt.Printf("error: %s\n", err)
	}
}<commit_msg>add filter for *dev* environments<commit_after>package main

import (
	"fmt"
	"strings"
	"time"
	"net/http"
	"encoding/json"
	"github.com/rancher/go-rancher/client"
	"os"
	"github.com/ahaynssen/slack-go-webhook"
)

type Rancher struct {
	Url        string `json:"url"`
	AccessKey  string `json:"access_key"`
	SecretKey  string `json:"secret_key"`
	Service    string `json:"service"`
	Image      string `json:"docker_image"`
	StartFirst bool   `json:"start_first"`
	Confirm    bool   `json:"confirm"`
	Timeout    int    `json:"timeout"`
}

func main() {
	fmt.Println("Started upgrade server")
	http.HandleFunc("/upgrade/", requestSuccess)
	http.ListenAndServe(":8080", nil)
}

func requestSuccess(w http.ResponseWriter, r *http.Request){
	vargs := Rancher{
		StartFirst: false,
		Timeout:    30,
	}

	err := json.NewDecoder(r.Body).Decode(&vargs)
	if err != nil {
		fmt.Printf(err.Error())
		Error(w, err.Error(), 400)
		return
	} else {
		if len(vargs.Url) == 0 || len(vargs.AccessKey) == 0 || len(vargs.SecretKey) == 0 {
			Error(w, "Rancher credentials not set", 400)
			return
		}
		go upgradeRancher(vargs)
		w.WriteHeader(200)
		return
	}
}

func upgradeRancher(vargs Rancher) {
	var wantedImage, wantedVer string
	if !strings.HasPrefix(vargs.Image, "docker:") {
		vargs.Image = fmt.Sprintf("docker:%s", vargs.Image)
		parts := strings.Split(vargs.Image, ":")
		wantedImage = parts[1]
		wantedVer = parts[2]
	}
	parts := strings.Split(wantedImage, "/")
	vargs.Service = parts[1]

	rancher, err := client.NewRancherClient(&client.ClientOpts{
		Url:       vargs.Url,
		AccessKey: vargs.AccessKey,
		SecretKey: vargs.SecretKey,
	})

	if err != nil {
		fmt.Printf("Failed to create rancher client: %s\n", err)
		return
	}

	services, err := rancher.Service.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to list rancher services: %s\n", err)
		return
	}

	environments, err := rancher.Account.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to get environments: %s\n", err)
	}
	envs := make(map[string]string)
	for environments != nil {
		for _, env := range environments.Data {
			envs[env.Id] = env.Name
		}
		environments, err = environments.Next()
		if err != nil {
			fmt.Printf("Failed: %s\n", err)
		}
	}

	var upgradeLabel = os.Getenv("UPGRADE_LABEL")

	var foundImage, foundVer string
	for services != nil {
		for _, svc := range services.Data {
			if svc.LaunchConfig != nil {
				if _, ok := svc.LaunchConfig.Labels[upgradeLabel]; ok {
					parts := strings.Split(svc.LaunchConfig.ImageUuid, ":")
					foundImage = parts[1]
					foundVer = parts[2]
					if strings.Contains(strings.ToLower(envs[svc.AccountId]), "dev") {
						if foundImage == wantedImage && ((foundVer < wantedVer) || (wantedVer == "latest")) {
							fmt.Println("Trying to upgrade...")
							err := doUpgrade(vargs, svc, rancher)
							if err != nil {
								fmt.Println(err.Error())
							} else {
								if (vargs.Confirm) {
									fmt.Println("Trying to confirm...")
									err := confirmUpgrade(vargs, svc, rancher)
									url := fmt.Sprintf("https://rancher.connectedfleet.io/env/%s/apps/stacks/%s", svc.AccountId, svc.EnvironmentId)
									if err != nil {
										fmt.Println("Unable to upgrade service %s: %s\n", vargs.Service, err.Error())
										message := fmt.Sprintf("Unable to confirm upgrade to `%s`.\nCheck status at <%[2]s|%[1]s>", vargs.Service, url)
										slackMessage("danger", message)
									} else {
										fmt.Printf("Upgraded %s to %s\n", svc.Name, vargs.Image)
										message := fmt.Sprintf("`%[1]s` has been successfully upgraded to `%[2]s` " +
											"in %[4]s\n View in Rancher here: <%[3]s|%[1]s>", vargs.Service, wantedVer, url, envs[svc.AccountId])
										slackMessage("good", message)

									}
								}
							}
							continue
						}
					}
				}
			}
		}
		services, err = services.Next()
	}
}

func doUpgrade(vargs Rancher, service client.Service, rancher *client.RancherClient) (error) {
	service.LaunchConfig.ImageUuid = vargs.Image
	upgrade := &client.ServiceUpgrade{}
	upgrade.InServiceStrategy = &client.InServiceUpgradeStrategy{
		LaunchConfig:           service.LaunchConfig,
		SecondaryLaunchConfigs: service.SecondaryLaunchConfigs,
		StartFirst:             vargs.StartFirst,
	}
	upgrade.ToServiceStrategy = &client.ToServiceUpgradeStrategy{}
	_, err := rancher.Service.ActionUpgrade(&service, upgrade)
	return err
}

func confirmUpgrade(vargs Rancher, service client.Service, rancher *client.RancherClient) (error) {
	srv, err := retry(func() (interface{}, error) {
		s, e := rancher.Service.ById(service.Id)
		if e != nil {
			return nil, e
		}
		if s.State != "upgraded" {
			return nil, fmt.Errorf("Service not upgraded: %s\n", s.State)
		}
		return s, nil
	}, time.Duration(vargs.Timeout)*time.Second, 3*time.Second)
	if err != nil {
		return err
	}

	_, err = rancher.Service.ActionFinishupgrade(srv.(*client.Service))
	if err != nil {
		return err
	}
	fmt.Printf("Finished upgrade %s\n", vargs.Service)
	return err
}

type retryFunc func() (interface{}, error)

func retry(f retryFunc, timeout time.Duration, interval time.Duration) (interface{}, error) {
	finish := time.After(timeout)
	for {
		result, err := f()
		if err == nil {
			return result, nil
		}
		select {
		case <-finish:
			return nil, err
		case <-time.After(interval):
		}
	}
}

func Error(w http.ResponseWriter, error string, code int) {
	w.Header().Set("Content Type,", "text/plain; charset=UTF-8")
	w.WriteHeader(code)
	fmt.Fprint(w, error)
}

func slackMessage(status string, message string) {
	var webhookUrl = os.Getenv("SLACK_WEBHOOK")

	attachment := slack.Attachment {Color: &status, Text: &message}
	mrkdwn := "text"
	attachment.AddMrkdwn(&mrkdwn)
	payload := slack.Payload {
		Username: "rancher-updater-service",
		Attachments: []slack.Attachment{attachment},
	}
	printable, _ := json.Marshal(payload)
	fmt.Println(string(printable))
	err := slack.Send(webhookUrl, "", payload)
	if len(err) > 0 {
		fmt.Printf("error: %s\n", err)
	}
}<|endoftext|>