<commit_before>/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package signer

import (
	"bytes"
	"crypto"
	"fmt"
	"sync/atomic"

	"k8s.io/apiserver/pkg/server/dynamiccertificates"
	"k8s.io/client-go/util/cert"
	"k8s.io/client-go/util/keyutil"
	"k8s.io/kubernetes/pkg/controller/certificates/authority"
)

func newCAProvider(caFile, caKeyFile string) (*caProvider, error) {
	caLoader, err := dynamiccertificates.NewDynamicServingContentFromFiles("csr-controller", caFile, caKeyFile)
	if err != nil {
		return nil, fmt.Errorf("error reading CA cert file %q: %v", caFile, err)
	}

	ret := &caProvider{
		caLoader: caLoader,
	}
	if err := ret.setCA(); err != nil {
		return nil, err
	}

	return ret, nil
}

type caProvider struct {
	caValue  atomic.Value
	caLoader *dynamiccertificates.DynamicCertKeyPairContent
}

// setCA unconditionally stores the current cert/key content
func (p *caProvider) setCA() error {
	certPEM, keyPEM := p.caLoader.CurrentCertKeyContent()

	certs, err := cert.ParseCertsPEM(certPEM)
	if err != nil {
		return fmt.Errorf("error reading CA cert file %q: %v", p.caLoader.Name(), err)
	}
	if len(certs) != 1 {
		return fmt.Errorf("error reading CA cert file %q: expected 1 certificate, found %d", p.caLoader.Name(), len(certs))
	}

	key, err := keyutil.ParsePrivateKeyPEM(keyPEM)
	if err != nil {
		return fmt.Errorf("error reading CA key file %q: %v", p.caLoader.Name(), err)
	}
	priv, ok := key.(crypto.Signer)
	if !ok {
		return fmt.Errorf("error reading CA key file %q: key did not implement crypto.Signer", p.caLoader.Name())
	}

	ca := &authority.CertificateAuthority{
		RawCert: certPEM,
		RawKey:  keyPEM,

		Certificate: certs[0],
		PrivateKey:  priv,
	}
	p.caValue.Store(ca)

	return nil
}

// currentCA provides the curent value of the CA.
// It always check for a stale value.  This is cheap because it's all an in memory cache of small slices.
func (p *caProvider) currentCA() (*authority.CertificateAuthority, error) {
	certPEM, keyPEM := p.caLoader.CurrentCertKeyContent()
	currCA := p.caValue.Load().(*authority.CertificateAuthority)
	if bytes.Equal(currCA.RawCert, certPEM) && bytes.Equal(currCA.RawKey, keyPEM) {
		return currCA, nil
	}

	// the bytes weren't equal, so we have to set and then load
	if err := p.setCA(); err != nil {
		return currCA, err
	}
	return p.caValue.Load().(*authority.CertificateAuthority), nil
}
<commit_msg>fix curent to current<commit_after>/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package signer

import (
	"bytes"
	"crypto"
	"fmt"
	"sync/atomic"

	"k8s.io/apiserver/pkg/server/dynamiccertificates"
	"k8s.io/client-go/util/cert"
	"k8s.io/client-go/util/keyutil"
	"k8s.io/kubernetes/pkg/controller/certificates/authority"
)

func newCAProvider(caFile, caKeyFile string) (*caProvider, error) {
	caLoader, err := dynamiccertificates.NewDynamicServingContentFromFiles("csr-controller", caFile, caKeyFile)
	if err != nil {
		return nil, fmt.Errorf("error reading CA cert file %q: %v", caFile, err)
	}

	ret := &caProvider{
		caLoader: caLoader,
	}
	if err := ret.setCA(); err != nil {
		return nil, err
	}

	return ret, nil
}

type caProvider struct {
	caValue  atomic.Value
	caLoader *dynamiccertificates.DynamicCertKeyPairContent
}

// setCA unconditionally stores the current cert/key content
func (p *caProvider) setCA() error {
	certPEM, keyPEM := p.caLoader.CurrentCertKeyContent()

	certs, err := cert.ParseCertsPEM(certPEM)
	if err != nil {
		return fmt.Errorf("error reading CA cert file %q: %v", p.caLoader.Name(), err)
	}
	if len(certs) != 1 {
		return fmt.Errorf("error reading CA cert file %q: expected 1 certificate, found %d", p.caLoader.Name(), len(certs))
	}

	key, err := keyutil.ParsePrivateKeyPEM(keyPEM)
	if err != nil {
		return fmt.Errorf("error reading CA key file %q: %v", p.caLoader.Name(), err)
	}
	priv, ok := key.(crypto.Signer)
	if !ok {
		return fmt.Errorf("error reading CA key file %q: key did not implement crypto.Signer", p.caLoader.Name())
	}

	ca := &authority.CertificateAuthority{
		RawCert: certPEM,
		RawKey:  keyPEM,

		Certificate: certs[0],
		PrivateKey:  priv,
	}
	p.caValue.Store(ca)

	return nil
}

// currentCA provides the current value of the CA.
// It always check for a stale value.  This is cheap because it's all an in memory cache of small slices.
func (p *caProvider) currentCA() (*authority.CertificateAuthority, error) {
	certPEM, keyPEM := p.caLoader.CurrentCertKeyContent()
	currCA := p.caValue.Load().(*authority.CertificateAuthority)
	if bytes.Equal(currCA.RawCert, certPEM) && bytes.Equal(currCA.RawKey, keyPEM) {
		return currCA, nil
	}

	// the bytes weren't equal, so we have to set and then load
	if err := p.setCA(); err != nil {
		return currCA, err
	}
	return p.caValue.Load().(*authority.CertificateAuthority), nil
}
<|endoftext|>


<commit_before>package slackbot

import (
	"encoding/json"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/justinian/dice"
)

type Command struct {
	Name string
	Desc string
	Func func(*Instance, *Message, string) error
}

var COMMANDS []*Command

func init() {
	COMMANDS = []*Command{
		&Command{"help", "Show a list of commands.", cmd_help},
		&Command{"status", "Show my current status.", cmd_status},
		&Command{"say", "Repeat a message in the current channel.", cmd_say},
		&Command{"duck", "Start a duck hunt.", cmd_duck},
		&Command{"shoot", "Shoot a duck.", cmd_shoot_duck},
		&Command{"catch", "Catch a duck.", cmd_catch_duck},
		&Command{"vote", "start/stop a vote or vote yes/no during a vote.", cmd_vote},
		&Command{"mute", "Mute my messages to this channel, for a while.", cmd_mute},
		&Command{"roll", "Throw a dice roll.", cmd_roll},
		&Command{"wiki", "Quote a page from our SS13 wiki.", cmd_wiki},
		&Command{"pun", "Tell a random pun.", cmd_pun},
		&Command{"badpun", "Tell a random, bad pun.", cmd_pun},
		&Command{"catfact", "Tell a random cat fact.", cmd_catfact},
		&Command{"catfacts", "Tell a random cat fact.", cmd_catfact},
		&Command{"goon", "Tell a random goon quote.", cmd_goon},
	}
}

func cmd_help(i *Instance, m *Message, args string) error {
	// TODO: sort the list
	tmp := "Available commands:\n"
	for _, c := range COMMANDS {
		tmp += fmt.Sprintf("- `%s\t%s`\n", c.Name, c.Desc)
	}
	i.UserMsg(m.User, tmp)
	return nil
}

func cmd_say(i *Instance, m *Message, args string) error {
	if len(args) > 1 {
		i.ChannelMsg(m.Channel, args)
	} else {
		return fmt.Errorf("Too short message for `say`.")
	}
	return nil
}

func cmd_duck(i *Instance, m *Message, args string) error {
	i.ModeOn("duck_" + m.Channel)
	i.ChannelMsg(m.Channel, "Oh look, a random *duck* appeard! Try to `shoot` or `catch` it!")
	return nil
}

func cmd_shoot_duck(i *Instance, m *Message, args string) error {
	if i.ModeStatus("duck_" + m.Channel) {
		i.ModeOff("duck_" + m.Channel)
		i.AddScore(1, "duck", m.User)
		tmp := fmt.Sprintf("Pew pew! *%s* has shot the duck!\n*%s* has now shot %d ducks.", i.Users[m.User].Name, i.Users[m.User].Name, i.GetScore("duck", m.User))
		i.ChannelMsg(m.Channel, tmp)
		return nil
	}
	return fmt.Errorf("What are you shooting at, cowboy?")
}

func cmd_catch_duck(i *Instance, m *Message, args string) error {
	if i.ModeStatus("duck_" + m.Channel) {
		i.ModeOff("duck_" + m.Channel)
		tmp := fmt.Sprintf("Yoink! *%s* has caught the duck but let it go after a while...", i.Users[m.User].Name)
		i.ChannelMsg(m.Channel, tmp)
		return nil
	}
	return fmt.Errorf("Nuh uh, can't touch me.")
}

func cmd_vote(i *Instance, m *Message, args string) error {
	if args == "start" {
		i.StartVote(m.Channel)
		i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has started a new vote! Tell me if you would like to `vote yes` or `vote no` on it.", i.Users[m.User].Name))
	} else if args == "stop" {
		votes := i.StopVote(m.Channel)
		var result string
		if votes > 0 {
			result = "*YES* has won"
		} else if votes < 0 {
			result = "*NO* has won"
		} else {
			result = "It's a tie! No one won"
		}
		i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has stopped the vote! The result is...\n%s (score: %d)!", i.Users[m.User].Name, result, votes))
	} else if args == "yes" {
		i.Vote(+1, m.Channel)
	} else if args == "no" {
		i.Vote(-1, m.Channel)
	}
	return nil
}

func cmd_mute(i *Instance, m *Message, args string) error {
	dur, e := time.ParseDuration(args)
	if e != nil {
		return fmt.Errorf("Couldn't parse a duration.")
	}
	if dur.Minutes() < 1 {
		dur = time.Duration(5) * time.Minute
	}
	if dur.Minutes() > 60 {
		dur = time.Duration(60) * time.Minute
	}

	i.ChannelMsg(m.Channel, fmt.Sprintf("I will now shut up for ~%.0f minutes.", dur.Minutes()))
	go func() {
		time.Sleep(5)
		i.Mute(m.Channel, dur)
	}()
	return nil
}

func cmd_status(i *Instance, m *Message, args string) error {
	tmp := "My current status:\n"
	tmp += fmt.Sprintf("`Running: %v`\n", i.running)
	tmp += fmt.Sprintf("`Version: v%v`\n", VERSION)
	tmp += fmt.Sprintf("`Debug mode: %v`\n", i.Debug)
	tmp += fmt.Sprintf("`Latency: %v`\n", i.Latency)
	tmp += fmt.Sprintf("`My User ID: @%v`\n", i.BotId)
	tmp += fmt.Sprintf("`Tracked channels: %v`\n", len(i.Channels))
	tmp += fmt.Sprintf("`Tracked users: %v`\n", len(i.Users))
	tmp += fmt.Sprintf("\nI am currently muted on channels:\n")
	if len(i.mutes) < 1 {
		tmp += "- `None`\n"
	} else {
		for k, v := range i.mutes {
			c := i.Channels[k].Name
			t := v.Sub(time.Now())
			tmp += fmt.Sprintf("- `%v (ends in ~%.0f minutes)`\n", c, t.Minutes())
		}
	}
	i.UserMsg(m.User, tmp)
	return nil
}

func cmd_roll(i *Instance, m *Message, args string) error {
	ret, res, e := dice.Roll(args)
	if e != nil {
		return fmt.Errorf("Bad dice format.")
	}
	i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has rolled: %v, %v\n", i.Users[m.User].Name, ret, res))
	return nil
}

func cmd_wiki(i *Instance, m *Message, args string) error {
	u := WIKI_URL + url.QueryEscape(args)
	doc, e := goquery.NewDocument(u)
	if e != nil {
		return fmt.Errorf("Couldn't open the wiki for you (%v).", u)
	}

	node := doc.Find("div #mw-content-text > p").First()
	text := strings.TrimSpace(node.Text())
	if node.Length() < 1 || len(text) < 1 {
		return fmt.Errorf("Couldn't quote that page for you (%v).", u)
	}

	i.ChannelMsg(m.Channel, fmt.Sprintf(">>>%s\n`Source: %s`", text, u))
	return nil
}

func cmd_pun(i *Instance, m *Message, args string) error {
	resp, e := http.Get("http://www.punoftheday.com/cgi-bin/arandompun.pl")
	if e != nil {
		return fmt.Errorf("Sorry, couldn't make up a pun for you.")
	}
	defer resp.Body.Close()
	body, e := ioutil.ReadAll(resp.Body)
	if e != nil {
		return fmt.Errorf("Sorry, couldn't make up a pun for you.")
	}
	// Yep this is a fucking mess.
	s := strings.TrimSpace(string(body))
	s = strings.TrimPrefix(s, "document.write('"")
	index := strings.Index(s, """)
	s = html.UnescapeString(s[:index])
	i.ChannelMsg(m.Channel, fmt.Sprintf(">>>%v\n`© 1996-2011 PunoftheDay.com`", s))
	return nil
}

type CatFacts struct {
	Facts   []string
	Success string
}

var LAST_CATFACT_TIME time.Time

func cmd_catfact(i *Instance, m *Message, args string) error {
	now := time.Now()
	if now.After(LAST_CATFACT_TIME) != true {
		return fmt.Errorf("Sorry, I can only show a single catfact per day (or else I'll get banned!).")
	}
	LAST_CATFACT_TIME = now.Add(24 * time.Hour)

	resp, e := http.Get("http://catfacts-api.appspot.com/api/facts?number=1")
	if e != nil {
		return fmt.Errorf("Sorry, couldn't find any cat facts.")
	}

	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var cf CatFacts
	e = decoder.Decode(&cf)
	if e != nil {
		return fmt.Errorf("Sorry, couldn't find any cat facts.")
	}

	if len(cf.Facts) > 0 {
		msg := fmt.Sprintf(">>>%v\n`© http://catfacts-api.appspot.com`", cf.Facts[0])
		i.ChannelMsg(m.Channel, msg)
		return nil
	}
	return fmt.Errorf("Sorry, couldn't find any cat facts.")
}

func cmd_goon(i *Instance, m *Message, args string) error {
	q := i.random_goon_quote()
	msg := fmt.Sprintf(">>>%v\n`%v`", q.Quote, q.File)
	i.ChannelMsg(m.Channel, msg)
	return nil
}
<commit_msg>Show stats for goon quotes.<commit_after>package slackbot

import (
	"encoding/json"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/justinian/dice"
)

type Command struct {
	Name string
	Desc string
	Func func(*Instance, *Message, string) error
}

var COMMANDS []*Command

func init() {
	COMMANDS = []*Command{
		&Command{"help", "Show a list of commands.", cmd_help},
		&Command{"status", "Show my current status.", cmd_status},
		&Command{"say", "Repeat a message in the current channel.", cmd_say},
		&Command{"duck", "Start a duck hunt.", cmd_duck},
		&Command{"shoot", "Shoot a duck.", cmd_shoot_duck},
		&Command{"catch", "Catch a duck.", cmd_catch_duck},
		&Command{"vote", "start/stop a vote or vote yes/no during a vote.", cmd_vote},
		&Command{"mute", "Mute my messages to this channel, for a while.", cmd_mute},
		&Command{"roll", "Throw a dice roll.", cmd_roll},
		&Command{"wiki", "Quote a page from our SS13 wiki.", cmd_wiki},
		&Command{"pun", "Tell a random pun.", cmd_pun},
		&Command{"badpun", "Tell a random, bad pun.", cmd_pun},
		&Command{"catfact", "Tell a random cat fact.", cmd_catfact},
		&Command{"catfacts", "Tell a random cat fact.", cmd_catfact},
		&Command{"goon", "Tell a random goon quote.", cmd_goon},
	}
}

func cmd_help(i *Instance, m *Message, args string) error {
	// TODO: sort the list
	tmp := "Available commands:\n"
	for _, c := range COMMANDS {
		tmp += fmt.Sprintf("- `%s\t%s`\n", c.Name, c.Desc)
	}
	i.UserMsg(m.User, tmp)
	return nil
}

func cmd_say(i *Instance, m *Message, args string) error {
	if len(args) > 1 {
		i.ChannelMsg(m.Channel, args)
	} else {
		return fmt.Errorf("Too short message for `say`.")
	}
	return nil
}

func cmd_duck(i *Instance, m *Message, args string) error {
	i.ModeOn("duck_" + m.Channel)
	i.ChannelMsg(m.Channel, "Oh look, a random *duck* appeard! Try to `shoot` or `catch` it!")
	return nil
}

func cmd_shoot_duck(i *Instance, m *Message, args string) error {
	if i.ModeStatus("duck_" + m.Channel) {
		i.ModeOff("duck_" + m.Channel)
		i.AddScore(1, "duck", m.User)
		tmp := fmt.Sprintf("Pew pew! *%s* has shot the duck!\n*%s* has now shot %d ducks.", i.Users[m.User].Name, i.Users[m.User].Name, i.GetScore("duck", m.User))
		i.ChannelMsg(m.Channel, tmp)
		return nil
	}
	return fmt.Errorf("What are you shooting at, cowboy?")
}

func cmd_catch_duck(i *Instance, m *Message, args string) error {
	if i.ModeStatus("duck_" + m.Channel) {
		i.ModeOff("duck_" + m.Channel)
		tmp := fmt.Sprintf("Yoink! *%s* has caught the duck but let it go after a while...", i.Users[m.User].Name)
		i.ChannelMsg(m.Channel, tmp)
		return nil
	}
	return fmt.Errorf("Nuh uh, can't touch me.")
}

func cmd_vote(i *Instance, m *Message, args string) error {
	if args == "start" {
		i.StartVote(m.Channel)
		i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has started a new vote! Tell me if you would like to `vote yes` or `vote no` on it.", i.Users[m.User].Name))
	} else if args == "stop" {
		votes := i.StopVote(m.Channel)
		var result string
		if votes > 0 {
			result = "*YES* has won"
		} else if votes < 0 {
			result = "*NO* has won"
		} else {
			result = "It's a tie! No one won"
		}
		i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has stopped the vote! The result is...\n%s (score: %d)!", i.Users[m.User].Name, result, votes))
	} else if args == "yes" {
		i.Vote(+1, m.Channel)
	} else if args == "no" {
		i.Vote(-1, m.Channel)
	}
	return nil
}

func cmd_mute(i *Instance, m *Message, args string) error {
	dur, e := time.ParseDuration(args)
	if e != nil {
		return fmt.Errorf("Couldn't parse a duration.")
	}
	if dur.Minutes() < 1 {
		dur = time.Duration(5) * time.Minute
	}
	if dur.Minutes() > 60 {
		dur = time.Duration(60) * time.Minute
	}

	i.ChannelMsg(m.Channel, fmt.Sprintf("I will now shut up for ~%.0f minutes.", dur.Minutes()))
	go func() {
		time.Sleep(5)
		i.Mute(m.Channel, dur)
	}()
	return nil
}

func cmd_status(i *Instance, m *Message, args string) error {
	tmp := "My current status:\n"
	tmp += fmt.Sprintf("`Running: %v`\n", i.running)
	tmp += fmt.Sprintf("`Version: v%v`\n", VERSION)
	tmp += fmt.Sprintf("`Debug mode: %v`\n", i.Debug)
	tmp += fmt.Sprintf("`Latency: %v`\n", i.Latency)
	tmp += fmt.Sprintf("`My User ID: @%v`\n", i.BotId)
	tmp += fmt.Sprintf("`Tracked channels: %v`\n", len(i.Channels))
	tmp += fmt.Sprintf("`Tracked users: %v`\n", len(i.Users))
	tmp += fmt.Sprintf("`No. of Goon quotes: %v`\n", len(i.goon))
	tmp += fmt.Sprintf("\nI am currently muted on channels:\n")
	if len(i.mutes) < 1 {
		tmp += "- `None`\n"
	} else {
		for k, v := range i.mutes {
			c := i.Channels[k].Name
			t := v.Sub(time.Now())
			tmp += fmt.Sprintf("- `%v (ends in ~%.0f minutes)`\n", c, t.Minutes())
		}
	}
	i.UserMsg(m.User, tmp)
	return nil
}

func cmd_roll(i *Instance, m *Message, args string) error {
	ret, res, e := dice.Roll(args)
	if e != nil {
		return fmt.Errorf("Bad dice format.")
	}
	i.ChannelMsg(m.Channel, fmt.Sprintf("@%s has rolled: %v, %v\n", i.Users[m.User].Name, ret, res))
	return nil
}

func cmd_wiki(i *Instance, m *Message, args string) error {
	u := WIKI_URL + url.QueryEscape(args)
	doc, e := goquery.NewDocument(u)
	if e != nil {
		return fmt.Errorf("Couldn't open the wiki for you (%v).", u)
	}

	node := doc.Find("div #mw-content-text > p").First()
	text := strings.TrimSpace(node.Text())
	if node.Length() < 1 || len(text) < 1 {
		return fmt.Errorf("Couldn't quote that page for you (%v).", u)
	}

	i.ChannelMsg(m.Channel, fmt.Sprintf(">>>%s\n`Source: %s`", text, u))
	return nil
}

func cmd_pun(i *Instance, m *Message, args string) error {
	resp, e := http.Get("http://www.punoftheday.com/cgi-bin/arandompun.pl")
	if e != nil {
		return fmt.Errorf("Sorry, couldn't make up a pun for you.")
	}
	defer resp.Body.Close()
	body, e := ioutil.ReadAll(resp.Body)
	if e != nil {
		return fmt.Errorf("Sorry, couldn't make up a pun for you.")
	}
	// Yep this is a fucking mess.
	s := strings.TrimSpace(string(body))
	s = strings.TrimPrefix(s, "document.write('"")
	index := strings.Index(s, """)
	s = html.UnescapeString(s[:index])
	i.ChannelMsg(m.Channel, fmt.Sprintf(">>>%v\n`© 1996-2011 PunoftheDay.com`", s))
	return nil
}

type CatFacts struct {
	Facts   []string
	Success string
}

var LAST_CATFACT_TIME time.Time

func cmd_catfact(i *Instance, m *Message, args string) error {
	now := time.Now()
	if now.After(LAST_CATFACT_TIME) != true {
		return fmt.Errorf("Sorry, I can only show a single catfact per day (or else I'll get banned!).")
	}
	LAST_CATFACT_TIME = now.Add(24 * time.Hour)

	resp, e := http.Get("http://catfacts-api.appspot.com/api/facts?number=1")
	if e != nil {
		return fmt.Errorf("Sorry, couldn't find any cat facts.")
	}

	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var cf CatFacts
	e = decoder.Decode(&cf)
	if e != nil {
		return fmt.Errorf("Sorry, couldn't find any cat facts.")
	}

	if len(cf.Facts) > 0 {
		msg := fmt.Sprintf(">>>%v\n`© http://catfacts-api.appspot.com`", cf.Facts[0])
		i.ChannelMsg(m.Channel, msg)
		return nil
	}
	return fmt.Errorf("Sorry, couldn't find any cat facts.")
}

func cmd_goon(i *Instance, m *Message, args string) error {
	q := i.random_goon_quote()
	msg := fmt.Sprintf(">>>%v\n`%v`", q.Quote, q.File)
	i.ChannelMsg(m.Channel, msg)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package merge_test

import (
	"fmt"
	"testing"

	"sigs.k8s.io/structured-merge-diff/merge"
	"sigs.k8s.io/structured-merge-diff/typed"
)

// State of the current test in terms of live object. One can check at
// any time that Live and Owners match the expectations.
type State struct {
	Live   *typed.TypedValue
	Parser *typed.Parser
	// Typename is the typename used to create objects in the
	// schema.
	Typename string
	Owners   merge.Owners
	Updater  *merge.Updater
}

func (s *State) checkInit() error {
	if s.Live == nil {
		obj, err := s.Parser.NewEmpty(s.Typename)
		if err != nil {
			return fmt.Errorf("failed to create new empty object: %v", err)
		}
		s.Live = &obj
	}
	return nil
}

// Update the current state with the passed in object
func (s *State) Update(obj typed.YAMLObject, owner string) error {
	if err := s.checkInit(); err != nil {
		return err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	owners, err := s.Updater.Update(*s.Live, tv, s.Owners, owner)
	if err != nil {
		return err
	}
	s.Live = &tv
	s.Owners = owners

	return nil
}

// Apply the passed in object to the current state
func (s *State) Apply(obj typed.YAMLObject, owner string, force bool) error {
	if err := s.checkInit(); err != nil {
		return err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	if err != nil {
		return err
	}
	new, owners, err := s.Updater.Apply(*s.Live, tv, s.Owners, owner, force)
	if err != nil {
		return err
	}
	s.Live = &new
	s.Owners = owners

	return nil
}

// CompareLive takes a YAML string and returns the comparison with the
// current live object or an error.
func (s *State) CompareLive(obj typed.YAMLObject) (*typed.Comparison, error) {
	if err := s.checkInit(); err != nil {
		return nil, err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	if err != nil {
		return nil, err
	}
	return s.Live.Compare(tv)
}

// TestExample shows how to use the test framework
func TestExample(t *testing.T) {
	parser, err := typed.NewParser(`types:
- name: lists
  struct:
    fields:
    - name: list
      type:
        list:
          elementType:
            scalar: string
          elementRelationship: associative`)
	if err != nil {
		t.Fatalf("Failed to create parser: %v", err)
	}
	state := &State{
		Updater:  &merge.Updater{},
		Parser:   parser,
		Typename: "lists",
	}

	config := typed.YAMLObject(`
list:
- a
- b
- c
`)
	err = state.Apply(config, "default", false)
	if err != nil {
		t.Fatalf("Wanted err = %v, got %v", nil, err)
	}

	config = typed.YAMLObject(`
list:
- a
- b
- c
- d`)
	err = state.Apply(config, "default", false)

	if err != nil {
		t.Fatalf("Wanted err = %v, got %v", nil, err)
	}

	// The following is wrong because the code doesn't work yet.
	_, err = state.CompareLive(config)
	if err != nil {
		t.Fatalf("Failed to compare live with config: %v", err)
	}
}
<commit_msg>Create DummyConverter that doesn't convert<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package merge_test

import (
	"fmt"
	"testing"

	"sigs.k8s.io/structured-merge-diff/merge"
	"sigs.k8s.io/structured-merge-diff/typed"
)

// State of the current test in terms of live object. One can check at
// any time that Live and Owners match the expectations.
type State struct {
	Live   *typed.TypedValue
	Parser *typed.Parser
	// Typename is the typename used to create objects in the
	// schema.
	Typename string
	Owners   merge.Owners
	Updater  *merge.Updater
}

func (s *State) checkInit() error {
	if s.Live == nil {
		obj, err := s.Parser.NewEmpty(s.Typename)
		if err != nil {
			return fmt.Errorf("failed to create new empty object: %v", err)
		}
		s.Live = &obj
	}
	return nil
}

// Update the current state with the passed in object
func (s *State) Update(obj typed.YAMLObject, owner string) error {
	if err := s.checkInit(); err != nil {
		return err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	owners, err := s.Updater.Update(*s.Live, tv, s.Owners, owner)
	if err != nil {
		return err
	}
	s.Live = &tv
	s.Owners = owners

	return nil
}

// Apply the passed in object to the current state
func (s *State) Apply(obj typed.YAMLObject, owner string, force bool) error {
	if err := s.checkInit(); err != nil {
		return err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	if err != nil {
		return err
	}
	new, owners, err := s.Updater.Apply(*s.Live, tv, s.Owners, owner, force)
	if err != nil {
		return err
	}
	s.Live = &new
	s.Owners = owners

	return nil
}

// CompareLive takes a YAML string and returns the comparison with the
// current live object or an error.
func (s *State) CompareLive(obj typed.YAMLObject) (*typed.Comparison, error) {
	if err := s.checkInit(); err != nil {
		return nil, err
	}
	tv, err := s.Parser.FromYAML(obj, s.Typename)
	if err != nil {
		return nil, err
	}
	return s.Live.Compare(tv)
}

// dummyConverter doesn't convert, it just returns the same exact object no matter what.
type dummyConverter struct{}

// Convert returns the object given in input, not doing any conversion.
func (dummyConverter) Convert(v typed.TypedValue, version merge.APIVersion) (typed.TypedValue, error) {
	return v, nil
}

// TestExample shows how to use the test framework
func TestExample(t *testing.T) {
	parser, err := typed.NewParser(`types:
- name: lists
  struct:
    fields:
    - name: list
      type:
        list:
          elementType:
            scalar: string
          elementRelationship: associative`)
	if err != nil {
		t.Fatalf("Failed to create parser: %v", err)
	}
	state := &State{
		Updater:  &merge.Updater{},
		Parser:   parser,
		Typename: "lists",
	}

	config := typed.YAMLObject(`
list:
- a
- b
- c
`)
	err = state.Apply(config, "default", false)
	if err != nil {
		t.Fatalf("Wanted err = %v, got %v", nil, err)
	}

	config = typed.YAMLObject(`
list:
- a
- b
- c
- d`)
	err = state.Apply(config, "default", false)

	if err != nil {
		t.Fatalf("Wanted err = %v, got %v", nil, err)
	}

	// The following is wrong because the code doesn't work yet.
	_, err = state.CompareLive(config)
	if err != nil {
		t.Fatalf("Failed to compare live with config: %v", err)
	}
}
<|endoftext|>


<commit_before>package metainfo

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/anacrolix/missinggo"

	"github.com/anacrolix/torrent/bencode"
)

// Information specific to a single file inside the MetaInfo structure.
type FileInfo struct {
	Length int64    `bencode:"length"`
	Path   []string `bencode:"path"`
}

// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of
// failure.
func Load(r io.Reader) (*MetaInfo, error) {
	var mi MetaInfo
	d := bencode.NewDecoder(r)
	err := d.Decode(&mi)
	if err != nil {
		return nil, err
	}
	return &mi, nil
}

// Convenience function for loading a MetaInfo from a file.
func LoadFromFile(filename string) (*MetaInfo, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Load(f)
}

// The info dictionary.
type Info struct {
	PieceLength int64      `bencode:"piece length"`
	Pieces      []byte     `bencode:"pieces"`
	Name        string     `bencode:"name"`
	Length      int64      `bencode:"length,omitempty"`
	Private     *bool      `bencode:"private,omitempty"`
	Files       []FileInfo `bencode:"files,omitempty"`
}

// This is a helper that sets Files and Pieces from a root path and its
// children.
func (info *Info) BuildFromFilePath(root string) (err error) {
	info.Name = filepath.Base(root)
	info.Files = nil
	err = filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			// Directories are implicit in torrent files.
			return nil
		} else if path == root {
			// The root is a file.
			info.Length = fi.Size()
			return nil
		}
		relPath, err := filepath.Rel(root, path)
		log.Println(relPath, err)
		if err != nil {
			return fmt.Errorf("error getting relative path: %s", err)
		}
		info.Files = append(info.Files, FileInfo{
			Path:   strings.Split(relPath, string(filepath.Separator)),
			Length: fi.Size(),
		})
		return nil
	})
	if err != nil {
		return
	}
	err = info.GeneratePieces(func(fi FileInfo) (io.ReadCloser, error) {
		return os.Open(filepath.Join(root, strings.Join(fi.Path, string(filepath.Separator))))
	})
	if err != nil {
		err = fmt.Errorf("error generating pieces: %s", err)
	}
	return
}

func (info *Info) writeFiles(w io.Writer, open func(fi FileInfo) (io.ReadCloser, error)) error {
	for _, fi := range info.UpvertedFiles() {
		r, err := open(fi)
		if err != nil {
			return fmt.Errorf("error opening %v: %s", fi, err)
		}
		wn, err := io.CopyN(w, r, fi.Length)
		r.Close()
		if wn != fi.Length || err != nil {
			return fmt.Errorf("error hashing %v: %s", fi, err)
		}
	}
	return nil
}

// Set info.Pieces by hashing info.Files.
func (info *Info) GeneratePieces(open func(fi FileInfo) (io.ReadCloser, error)) error {
	if info.PieceLength == 0 {
		return errors.New("piece length must be non-zero")
	}
	pr, pw := io.Pipe()
	go func() {
		err := info.writeFiles(pw, open)
		pw.CloseWithError(err)
	}()
	defer pr.Close()
	var pieces []byte
	for {
		hasher := sha1.New()
		wn, err := io.CopyN(hasher, pr, info.PieceLength)
		if err == io.EOF {
			err = nil
		}
		if err != nil {
			return err
		}
		if wn == 0 {
			break
		}
		pieces = hasher.Sum(pieces)
		if wn < info.PieceLength {
			break
		}
	}
	info.Pieces = pieces
	return nil
}

func (info *Info) TotalLength() (ret int64) {
	if info.IsDir() {
		for _, fi := range info.Files {
			ret += fi.Length
		}
	} else {
		ret = info.Length
	}
	return
}

func (info *Info) NumPieces() int {
	if len(info.Pieces)%20 != 0 {
		panic(len(info.Pieces))
	}
	return len(info.Pieces) / 20
}

func (info *InfoEx) Piece(i int) Piece {
	return Piece{info, i}
}

func (info *Info) IsDir() bool {
	return len(info.Files) != 0
}

// The files field, converted up from the old single-file in the parent info
// dict if necessary. This is a helper to avoid having to conditionally handle
// single and multi-file torrent infos.
func (info *Info) UpvertedFiles() []FileInfo {
	if len(info.Files) == 0 {
		return []FileInfo{{
			Length: info.Length,
			// Callers should determine that Info.Name is the basename, and
			// thus a regular file.
			Path: nil,
		}}
	}
	return info.Files
}

// The info dictionary with its hash and raw bytes exposed, as these are
// important to Bittorrent.
type InfoEx struct {
	Info
	Hash  Hash   // Only set when unmarshalling or UpdateHash.
	Bytes []byte // Only set when unmarshalling or UpdateBytes.
}

var (
	_ bencode.Marshaler   = InfoEx{}
	_ bencode.Unmarshaler = &InfoEx{}
)

func (ie *InfoEx) UnmarshalBencode(data []byte) error {
	ie.Bytes = append([]byte(nil), data...)
	h := sha1.New()
	_, err := h.Write(ie.Bytes)
	if err != nil {
		panic(err)
	}
	missinggo.CopyExact(&ie.Hash, h.Sum(nil))
	return bencode.Unmarshal(data, &ie.Info)
}

func (ie InfoEx) MarshalBencode() ([]byte, error) {
	return bencode.Marshal(&ie.Info)
}

type MetaInfo struct {
	Info         InfoEx      `bencode:"info"`
	Announce     string      `bencode:"announce,omitempty"`
	AnnounceList [][]string  `bencode:"announce-list,omitempty"`
	Nodes        []Node      `bencode:"nodes,omitempty"`
	CreationDate int64       `bencode:"creation date,omitempty"`
	Comment      string      `bencode:"comment,omitempty"`
	CreatedBy    string      `bencode:"created by,omitempty"`
	Encoding     string      `bencode:"encoding,omitempty"`
	URLList      interface{} `bencode:"url-list,omitempty"`
}

// Encode to bencoded form.
func (mi *MetaInfo) Write(w io.Writer) error {
	return bencode.NewEncoder(w).Encode(mi)
}

// Set good default values in preparation for creating a new MetaInfo file.
func (mi *MetaInfo) SetDefaults() {
	mi.Comment = "yoloham"
	mi.CreatedBy = "github.com/anacrolix/torrent"
	mi.CreationDate = time.Now().Unix()
	mi.Info.PieceLength = 256 * 1024
}

// Magnetize creates a Magnet from a MetaInfo
func (mi *MetaInfo) Magnet() (m Magnet) {
	for _, tier := range mi.AnnounceList {
		for _, tracker := range tier {
			m.Trackers = append(m.Trackers, tracker)
		}
	}
	m.DisplayName = mi.Info.Name
	m.InfoHash = mi.Info.Hash
	return
}
<commit_msg>metainfo: Improve doc<commit_after>package metainfo

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/anacrolix/missinggo"

	"github.com/anacrolix/torrent/bencode"
)

// Information specific to a single file inside the MetaInfo structure.
type FileInfo struct {
	Length int64    `bencode:"length"`
	Path   []string `bencode:"path"`
}

// Load a MetaInfo from an io.Reader. Returns a non-nil error in case of
// failure.
func Load(r io.Reader) (*MetaInfo, error) {
	var mi MetaInfo
	d := bencode.NewDecoder(r)
	err := d.Decode(&mi)
	if err != nil {
		return nil, err
	}
	return &mi, nil
}

// Convenience function for loading a MetaInfo from a file.
func LoadFromFile(filename string) (*MetaInfo, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Load(f)
}

// The info dictionary.
type Info struct {
	PieceLength int64      `bencode:"piece length"`
	Pieces      []byte     `bencode:"pieces"`
	Name        string     `bencode:"name"`
	Length      int64      `bencode:"length,omitempty"`
	Private     *bool      `bencode:"private,omitempty"`
	Files       []FileInfo `bencode:"files,omitempty"`
}

// This is a helper that sets Files and Pieces from a root path and its
// children.
func (info *Info) BuildFromFilePath(root string) (err error) {
	info.Name = filepath.Base(root)
	info.Files = nil
	err = filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			// Directories are implicit in torrent files.
			return nil
		} else if path == root {
			// The root is a file.
			info.Length = fi.Size()
			return nil
		}
		relPath, err := filepath.Rel(root, path)
		log.Println(relPath, err)
		if err != nil {
			return fmt.Errorf("error getting relative path: %s", err)
		}
		info.Files = append(info.Files, FileInfo{
			Path:   strings.Split(relPath, string(filepath.Separator)),
			Length: fi.Size(),
		})
		return nil
	})
	if err != nil {
		return
	}
	err = info.GeneratePieces(func(fi FileInfo) (io.ReadCloser, error) {
		return os.Open(filepath.Join(root, strings.Join(fi.Path, string(filepath.Separator))))
	})
	if err != nil {
		err = fmt.Errorf("error generating pieces: %s", err)
	}
	return
}

func (info *Info) writeFiles(w io.Writer, open func(fi FileInfo) (io.ReadCloser, error)) error {
	for _, fi := range info.UpvertedFiles() {
		r, err := open(fi)
		if err != nil {
			return fmt.Errorf("error opening %v: %s", fi, err)
		}
		wn, err := io.CopyN(w, r, fi.Length)
		r.Close()
		if wn != fi.Length || err != nil {
			return fmt.Errorf("error hashing %v: %s", fi, err)
		}
	}
	return nil
}

// Set info.Pieces by hashing info.Files.
func (info *Info) GeneratePieces(open func(fi FileInfo) (io.ReadCloser, error)) error {
	if info.PieceLength == 0 {
		return errors.New("piece length must be non-zero")
	}
	pr, pw := io.Pipe()
	go func() {
		err := info.writeFiles(pw, open)
		pw.CloseWithError(err)
	}()
	defer pr.Close()
	var pieces []byte
	for {
		hasher := sha1.New()
		wn, err := io.CopyN(hasher, pr, info.PieceLength)
		if err == io.EOF {
			err = nil
		}
		if err != nil {
			return err
		}
		if wn == 0 {
			break
		}
		pieces = hasher.Sum(pieces)
		if wn < info.PieceLength {
			break
		}
	}
	info.Pieces = pieces
	return nil
}

func (info *Info) TotalLength() (ret int64) {
	if info.IsDir() {
		for _, fi := range info.Files {
			ret += fi.Length
		}
	} else {
		ret = info.Length
	}
	return
}

func (info *Info) NumPieces() int {
	if len(info.Pieces)%20 != 0 {
		panic(len(info.Pieces))
	}
	return len(info.Pieces) / 20
}

func (info *InfoEx) Piece(i int) Piece {
	return Piece{info, i}
}

func (info *Info) IsDir() bool {
	return len(info.Files) != 0
}

// The files field, converted up from the old single-file in the parent info
// dict if necessary. This is a helper to avoid having to conditionally handle
// single and multi-file torrent infos.
func (info *Info) UpvertedFiles() []FileInfo {
	if len(info.Files) == 0 {
		return []FileInfo{{
			Length: info.Length,
			// Callers should determine that Info.Name is the basename, and
			// thus a regular file.
			Path: nil,
		}}
	}
	return info.Files
}

// The info dictionary with its hash and raw bytes exposed, in case
// remarshalling Info produces a different value.
type InfoEx struct {
	Info
	Hash  Hash   // Only set when unmarshalling or UpdateHash.
	Bytes []byte // Only set when unmarshalling or UpdateBytes.
}

var (
	_ bencode.Marshaler   = InfoEx{}
	_ bencode.Unmarshaler = &InfoEx{}
)

func (ie *InfoEx) UnmarshalBencode(data []byte) error {
	ie.Bytes = append([]byte(nil), data...)
	h := sha1.New()
	_, err := h.Write(ie.Bytes)
	if err != nil {
		panic(err)
	}
	missinggo.CopyExact(&ie.Hash, h.Sum(nil))
	return bencode.Unmarshal(data, &ie.Info)
}

func (ie InfoEx) MarshalBencode() ([]byte, error) {
	return bencode.Marshal(&ie.Info)
}

type MetaInfo struct {
	Info         InfoEx      `bencode:"info"`
	Announce     string      `bencode:"announce,omitempty"`
	AnnounceList [][]string  `bencode:"announce-list,omitempty"`
	Nodes        []Node      `bencode:"nodes,omitempty"`
	CreationDate int64       `bencode:"creation date,omitempty"`
	Comment      string      `bencode:"comment,omitempty"`
	CreatedBy    string      `bencode:"created by,omitempty"`
	Encoding     string      `bencode:"encoding,omitempty"`
	URLList      interface{} `bencode:"url-list,omitempty"`
}

// Encode to bencoded form.
func (mi *MetaInfo) Write(w io.Writer) error {
	return bencode.NewEncoder(w).Encode(mi)
}

// Set good default values in preparation for creating a new MetaInfo file.
func (mi *MetaInfo) SetDefaults() {
	mi.Comment = "yoloham"
	mi.CreatedBy = "github.com/anacrolix/torrent"
	mi.CreationDate = time.Now().Unix()
	mi.Info.PieceLength = 256 * 1024
}

// Magnetize creates a Magnet from a MetaInfo.
func (mi *MetaInfo) Magnet() (m Magnet) {
	for _, tier := range mi.AnnounceList {
		for _, tracker := range tier {
			m.Trackers = append(m.Trackers, tracker)
		}
	}
	m.DisplayName = mi.Info.Name
	m.InfoHash = mi.Info.Hash
	return
}
<|endoftext|>


<commit_before><commit_msg>Explicitly declare the interfaces that base.Module implements<commit_after><|endoftext|>


<commit_before>package snap

import (
	"encoding/json"
	"errors"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"github.com/coreos/etcd/raft"
)

var (
	ErrNoSnapshot  = errors.New("snap: no available snapshot")
	ErrCRCMismatch = errors.New("snap: crc mismatch")
	crcTable       = crc32.MakeTable(crc32.Castagnoli)
)

type Snapshotter struct {
	dir string
}

func New(dir string) *Snapshotter {
	return &Snapshotter{
		dir: dir,
	}
}

func (s *Snapshotter) Save(snapshot *raft.Snapshot) error {
	fname := fmt.Sprintf("%016x-%016x-%016x.snap", snapshot.ClusterId, snapshot.Term, snapshot.Index)
	// TODO(xiangli): make raft.Snapshot a protobuf type
	b, err := json.Marshal(snapshot)
	if err != nil {
		panic(err)
	}
	crc := crc32.Update(0, crcTable, b)
	snap := Snapshot{Crc: crc, Data: b}
	d, err := snap.Marshal()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(s.dir, fname), d, 0666)
}

func (s *Snapshotter) Load() (*raft.Snapshot, error) {
	dir, err := os.Open(s.dir)
	if err != nil {
		return nil, err
	}
	defer dir.Close()
	names, err := dir.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	if len(names) == 0 {
		return nil, ErrNoSnapshot
	}
	sort.Sort(sort.Reverse(sort.StringSlice(names)))

	var snap raft.Snapshot
	var serializedSnap Snapshot
	var b []byte
	for _, name := range names {
		b, err = ioutil.ReadFile(path.Join(s.dir, name))
		if err != nil {
			log.Printf("Snapshotter cannot read file %v: %v", name, err)
			continue
		}
		if err = serializedSnap.Unmarshal(b); err != nil {
			log.Printf("Corruptted snapshot file %v: %v", name, err)
			continue
		}
		crc := crc32.Update(0, crcTable, serializedSnap.Data)
		if crc != serializedSnap.Crc {
			log.Printf("Corruptted snapshot file %v: crc mismatch", name)
			err = ErrCRCMismatch
			continue
		}
		if err = json.Unmarshal(serializedSnap.Data, &snap); err != nil {
			log.Printf("Corruptted snapshot file %v: %v", name, err)
			continue
		}
		break
	}
	if err != nil {
		return nil, err
	}
	return &snap, nil
}
<commit_msg>snap: fix typo<commit_after>package snap

import (
	"encoding/json"
	"errors"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"github.com/coreos/etcd/raft"
)

var (
	ErrNoSnapshot  = errors.New("snap: no available snapshot")
	ErrCRCMismatch = errors.New("snap: crc mismatch")
	crcTable       = crc32.MakeTable(crc32.Castagnoli)
)

type Snapshotter struct {
	dir string
}

func New(dir string) *Snapshotter {
	return &Snapshotter{
		dir: dir,
	}
}

func (s *Snapshotter) Save(snapshot *raft.Snapshot) error {
	fname := fmt.Sprintf("%016x-%016x-%016x.snap", snapshot.ClusterId, snapshot.Term, snapshot.Index)
	// TODO(xiangli): make raft.Snapshot a protobuf type
	b, err := json.Marshal(snapshot)
	if err != nil {
		panic(err)
	}
	crc := crc32.Update(0, crcTable, b)
	snap := Snapshot{Crc: crc, Data: b}
	d, err := snap.Marshal()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(s.dir, fname), d, 0666)
}

func (s *Snapshotter) Load() (*raft.Snapshot, error) {
	dir, err := os.Open(s.dir)
	if err != nil {
		return nil, err
	}
	defer dir.Close()
	names, err := dir.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	if len(names) == 0 {
		return nil, ErrNoSnapshot
	}
	sort.Sort(sort.Reverse(sort.StringSlice(names)))

	var snap raft.Snapshot
	var serializedSnap Snapshot
	var b []byte
	for _, name := range names {
		b, err = ioutil.ReadFile(path.Join(s.dir, name))
		if err != nil {
			log.Printf("Snapshotter cannot read file %v: %v", name, err)
			continue
		}
		if err = serializedSnap.Unmarshal(b); err != nil {
			log.Printf("Corrupted snapshot file %v: %v", name, err)
			continue
		}
		crc := crc32.Update(0, crcTable, serializedSnap.Data)
		if crc != serializedSnap.Crc {
			log.Printf("Corrupted snapshot file %v: crc mismatch", name)
			err = ErrCRCMismatch
			continue
		}
		if err = json.Unmarshal(serializedSnap.Data, &snap); err != nil {
			log.Printf("Corrupted snapshot file %v: %v", name, err)
			continue
		}
		break
	}
	if err != nil {
		return nil, err
	}
	return &snap, nil
}
<|endoftext|>


<commit_before>package cmd

// Version defines the current Pop version.
const Version = "v4.9.4"
<commit_msg>version bump: v4.9.5<commit_after>package cmd

// Version defines the current Pop version.
const Version = "v4.9.5"
<|endoftext|>


<commit_before>package mailck

import (
	"fmt"
	"github.com/siebenmann/smtpd"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
	"time"
	"context"
)

func TestCheckSyntax(t *testing.T) {
	tests := []struct {
		mail  string
		valid bool
	}{
		{"", false},
		{"xxx", false},
		{"s.mancketarent.de", false},
		{"s.mancke@tarentde", false},
		{"s.mancke@tarent@sdc.de", false},
		{"s.mancke@tarent.de", true},
		{"s.Mancke+yzz42@tarent.de", true},
	}

	for _, test := range tests {
		t.Run(test.mail, func(t *testing.T) {
			result := CheckSyntax(test.mail)
			assert.Equal(t, test.valid, result)
		})
	}
}

func TestCheck(t *testing.T) {
	tests := []struct {
		mail   string
		result Result
		err    error
	}{
		{"xxx", InvalidSyntax, nil},
		{"s.mancke@sdcsdcsdcsdctarent.de", InvalidDomain, nil},
		{"foo@example.com", InvalidDomain, nil},
		{"foo@mailinator.com", Disposable, nil},
	}

	for _, test := range tests {
		t.Run(test.mail, func(t *testing.T) {
			start := time.Now()
			result, err := Check("noreply@mancke.net", test.mail)
			assert.Equal(t, test.result, result)
			assert.Equal(t, test.err, err)
			fmt.Printf("check for %30v: %-15v => %-10v (%v)\n", test.mail, time.Since(start), test.result.Result, test.result.ResultDetail)
		})
	}
}

func Test_checkMailbox(t *testing.T) {
	tests := []struct {
		stopAt      smtpd.Command
		result      Result
		expectError bool
	}{
		{smtpd.QUIT, Valid, false},
		{smtpd.RCPTTO, MailboxUnavailable, false},
		{smtpd.MAILFROM, MailserverError, true},
		{smtpd.HELO, MailserverError, true},
	}

	for _, test := range tests {
		t.Run(fmt.Sprintf("stop at: %v", test.stopAt), func(t *testing.T) {
			dummyServer := NewDummySMTPServer("localhost:2525", test.stopAt, 0)
			defer dummyServer.Close()
			result, err := checkMailbox(noContext,"noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 2525)
			assert.Equal(t, test.result, result)
			if test.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func Test_checkMailbox_NetworkError(t *testing.T) {
	result, err := checkMailbox(noContext,"noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 6666)
	assert.Equal(t, NetworkError, result)
	assert.Error(t, err)
}

func Test_checkMailboxContext(t *testing.T) {
	deltas := []struct{
		delayTime      time.Duration
		contextTime    time.Duration
		expectedResult Result
	}{
		{ 0, 0, TimeoutError },
		{ 0, time.Second, Valid },
		{ time.Millisecond * 1500, 200 * time.Millisecond, TimeoutError },
	}
	for _,d := range deltas {
		t.Run(fmt.Sprintf("context time %v delay %v expected %v", d.contextTime,d.delayTime,d.expectedResult.Result), func(t *testing.T) {
			dummyServer := NewDummySMTPServer("localhost:2528", smtpd.QUIT,d.delayTime)
			tt := time.Now()
			ctx, _ := context.WithTimeout(context.Background(), d.contextTime)
			result,err := checkMailbox(ctx, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "127.0.0.1"}}, 2528)
			if d.expectedResult == Valid {
				assert.NoError(t,err)
			} else {
				assert.Error(t,err)
			}
			assert.Equal(t,d.expectedResult, result)
			// confirm that we completed within requested time
			// add 10ms of wiggle room
			assert.WithinDuration(t, time.Now(), tt, d.contextTime + 10 * time.Millisecond)
			dummyServer.Close()
		})
	}
}

type DummySMTPServer struct {
	listener net.Listener
	running  bool
	rejectAt smtpd.Command
	delay time.Duration
}

func NewDummySMTPServer(listen string, rejectAt smtpd.Command, delay time.Duration) *DummySMTPServer {
	ln, err := net.Listen("tcp", listen)
	if err != nil {
		panic(err)
	}
	time.Sleep(10 * time.Millisecond)
	smtpserver := &DummySMTPServer{
		listener: ln,
		running:  true,
		rejectAt: rejectAt,
		delay: delay,
	}

	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				return
			}
			go smtpserver.handleClient(conn)
		}
	}()
	time.Sleep(10 * time.Millisecond)
	return smtpserver
}

func (smtpserver *DummySMTPServer) Close() {
	smtpserver.listener.Close()
	smtpserver.running = false
	time.Sleep(10 * time.Millisecond)
}

func (smtpserver *DummySMTPServer) handleClient(conn net.Conn) {
	cfg := smtpd.Config{
		LocalName: "testserver",
		SftName:   "testserver",
	}
	c := smtpd.NewConn(conn, cfg, nil)
	for smtpserver.running {
		event := c.Next()
		time.Sleep(smtpserver.delay)
		if event.Cmd == smtpserver.rejectAt ||
			(smtpserver.rejectAt == smtpd.HELO && event.Cmd == smtpd.EHLO) {
			c.Reject()
		} else {
			c.Accept()
		}
		if event.What == smtpd.DONE {
			return
		}
	}
}
<commit_msg>Fix leaking context in test<commit_after>package mailck

import (
	"fmt"
	"github.com/siebenmann/smtpd"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
	"time"
	"context"
)

func TestCheckSyntax(t *testing.T) {
	tests := []struct {
		mail  string
		valid bool
	}{
		{"", false},
		{"xxx", false},
		{"s.mancketarent.de", false},
		{"s.mancke@tarentde", false},
		{"s.mancke@tarent@sdc.de", false},
		{"s.mancke@tarent.de", true},
		{"s.Mancke+yzz42@tarent.de", true},
	}

	for _, test := range tests {
		t.Run(test.mail, func(t *testing.T) {
			result := CheckSyntax(test.mail)
			assert.Equal(t, test.valid, result)
		})
	}
}

func TestCheck(t *testing.T) {
	tests := []struct {
		mail   string
		result Result
		err    error
	}{
		{"xxx", InvalidSyntax, nil},
		{"s.mancke@sdcsdcsdcsdctarent.de", InvalidDomain, nil},
		{"foo@example.com", InvalidDomain, nil},
		{"foo@mailinator.com", Disposable, nil},
	}

	for _, test := range tests {
		t.Run(test.mail, func(t *testing.T) {
			start := time.Now()
			result, err := Check("noreply@mancke.net", test.mail)
			assert.Equal(t, test.result, result)
			assert.Equal(t, test.err, err)
			fmt.Printf("check for %30v: %-15v => %-10v (%v)\n", test.mail, time.Since(start), test.result.Result, test.result.ResultDetail)
		})
	}
}

func Test_checkMailbox(t *testing.T) {
	tests := []struct {
		stopAt      smtpd.Command
		result      Result
		expectError bool
	}{
		{smtpd.QUIT, Valid, false},
		{smtpd.RCPTTO, MailboxUnavailable, false},
		{smtpd.MAILFROM, MailserverError, true},
		{smtpd.HELO, MailserverError, true},
	}

	for _, test := range tests {
		t.Run(fmt.Sprintf("stop at: %v", test.stopAt), func(t *testing.T) {
			dummyServer := NewDummySMTPServer("localhost:2525", test.stopAt, 0)
			defer dummyServer.Close()
			result, err := checkMailbox(noContext,"noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 2525)
			assert.Equal(t, test.result, result)
			if test.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func Test_checkMailbox_NetworkError(t *testing.T) {
	result, err := checkMailbox(noContext,"noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "localhost"}}, 6666)
	assert.Equal(t, NetworkError, result)
	assert.Error(t, err)
}

func Test_checkMailboxContext(t *testing.T) {
	deltas := []struct{
		delayTime      time.Duration
		contextTime    time.Duration
		expectedResult Result
	}{
		{ 0, 0, TimeoutError },
		{ 0, time.Second, Valid },
		{ time.Millisecond * 1500, 200 * time.Millisecond, TimeoutError },
	}
	for _,d := range deltas {
		t.Run(fmt.Sprintf("context time %v delay %v expected %v", d.contextTime,d.delayTime,d.expectedResult.Result), func(t *testing.T) {
			dummyServer := NewDummySMTPServer("localhost:2528", smtpd.QUIT,d.delayTime)
			tt := time.Now()
			ctx, cancel := context.WithTimeout(context.Background(), d.contextTime)
			result,err := checkMailbox(ctx, "noreply@mancke.net", "foo@bar.de", []*net.MX{{Host: "127.0.0.1"}}, 2528)
			if d.expectedResult == Valid {
				assert.NoError(t,err)
			} else {
				assert.Error(t,err)
			}
			assert.Equal(t,d.expectedResult, result)
			// confirm that we completed within requested time
			// add 10ms of wiggle room
			assert.WithinDuration(t, time.Now(), tt, d.contextTime + 10 * time.Millisecond)
			dummyServer.Close()
			cancel()
		})
	}
}

type DummySMTPServer struct {
	listener net.Listener
	running  bool
	rejectAt smtpd.Command
	delay time.Duration
}

func NewDummySMTPServer(listen string, rejectAt smtpd.Command, delay time.Duration) *DummySMTPServer {
	ln, err := net.Listen("tcp", listen)
	if err != nil {
		panic(err)
	}
	time.Sleep(10 * time.Millisecond)
	smtpserver := &DummySMTPServer{
		listener: ln,
		running:  true,
		rejectAt: rejectAt,
		delay: delay,
	}

	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				return
			}
			go smtpserver.handleClient(conn)
		}
	}()
	time.Sleep(10 * time.Millisecond)
	return smtpserver
}

func (smtpserver *DummySMTPServer) Close() {
	smtpserver.listener.Close()
	smtpserver.running = false
	time.Sleep(10 * time.Millisecond)
}

func (smtpserver *DummySMTPServer) handleClient(conn net.Conn) {
	cfg := smtpd.Config{
		LocalName: "testserver",
		SftName:   "testserver",
	}
	c := smtpd.NewConn(conn, cfg, nil)
	for smtpserver.running {
		event := c.Next()
		time.Sleep(smtpserver.delay)
		if event.Cmd == smtpserver.rejectAt ||
			(smtpserver.rejectAt == smtpd.HELO && event.Cmd == smtpd.EHLO) {
			c.Reject()
		} else {
			c.Accept()
		}
		if event.What == smtpd.DONE {
			return
		}
	}
}
<|endoftext|>


<commit_before>package jot

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"
)

type Config struct {
	Remote, Editor, CurrentDocument string
}

func SetupConfig() {
	var configParameters Config

	var yesno string
	err := errors.New("Incorrect git repo")
	for {
		fmt.Print("Enter git repo (e.g.: git@github.com:USER/REPO.git): ")
		fmt.Scanln(&yesno)
		cwd, _ := os.Getwd()
		os.Chdir(CachePath)
		if !exists(EncodeBase58(yesno)) {
			fmt.Println("Cloning " + yesno + " ...")
			cmd := exec.Command("git", "clone", yesno, EncodeBase58(yesno))
			out2, _ := cmd.StderrPipe()
			cmd.Start()
			out2b, _ := ioutil.ReadAll(out2)
			cmd.Wait()
			os.Chdir(cwd)
			if strings.Contains(string(out2b), "fatal: ") {
				fmt.Println(strings.TrimSpace(string(out2b)))
				fmt.Println("Could not clone, please re-enter")
			} else {
				// Remove, this cloning only was to check that it was a valid thing
				os.RemoveAll(path.Join(CachePath, EncodeBase58(yesno)))
				break
			}
		} else {
			fmt.Println("Already exists, doing nothing.")
			break
		}
	}
	configParameters.Remote = yesno

	// Loop until user chooses an available program
	for {
		fmt.Printf("Which editor do you want to use: micro (default), vim,  nano, or emacs? ")
		fmt.Scanln(&yesno)
		if strings.TrimSpace(strings.ToLower(yesno)) == "nano" {
			configParameters.Editor = "nano"
		} else if strings.TrimSpace(strings.ToLower(yesno)) == "emacs" {
			configParameters.Editor = "emacs"
		} else if strings.TrimSpace(strings.ToLower(yesno)) == "vim" {
			configParameters.Editor = "vim"
		} else {
			configParameters.Editor = "micro"
		}
		if Version != "dev" && configParameters.Editor == "micro" {
			break
		}
		// check if it actually exists
		cmd := exec.Command(path.Join(ProgramPath, configParameters.Editor+Extension), "--version")
		_, err2 := cmd.Output()
		if err2 == nil {
			break
		}
		cmd = exec.Command(path.Join(".", configParameters.Editor+Extension), "--version")
		_, err2 = cmd.Output()
		if err2 == nil {
			break
		}
		fmt.Printf("\n%s not found, are you sure its installed?\n\n", configParameters.Editor+Extension)
	}

	configParameters.CurrentDocument = ""

	b, err := json.Marshal(configParameters)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(ConfigPath, "config.json"), b, 0644)
}

func LoadConfiguration() {
	defer timeTrack(time.Now(), "Loaded and saved configuration")
	var c Config
	data, err := ioutil.ReadFile(path.Join(ConfigPath, "config.json"))
	if err != nil {
		logger.Error("Could not load config.json")
		return
	}
	json.Unmarshal(data, &c)
	if len(CurrentDocument) == 0 {
		CurrentDocument = c.CurrentDocument
	}
	Editor = c.Editor
	Remote = c.Remote
	RemoteFolder = path.Join(CachePath, EncodeBase58(Remote))
	if len(Remote) == 0 {
		SetupConfig()
	}
}

func SaveConfiguration(editor string, remote string, currentdoc string) {
	defer timeTrack(time.Now(), "Saved configuration")
	c := Config{Editor: editor, Remote: remote, CurrentDocument: currentdoc}
	b, err := json.Marshal(c)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(ConfigPath, "config.json"), b, 0644)
}
<commit_msg>Check assets as well<commit_after>package jot

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"
)

type Config struct {
	Remote, Editor, CurrentDocument string
}

func SetupConfig() {
	var configParameters Config

	var yesno string
	err := errors.New("Incorrect git repo")
	for {
		fmt.Print("Enter git repo (e.g.: git@github.com:USER/REPO.git): ")
		fmt.Scanln(&yesno)
		cwd, _ := os.Getwd()
		os.Chdir(CachePath)
		if !exists(EncodeBase58(yesno)) {
			fmt.Println("Cloning " + yesno + " ...")
			cmd := exec.Command("git", "clone", yesno, EncodeBase58(yesno))
			out2, _ := cmd.StderrPipe()
			cmd.Start()
			out2b, _ := ioutil.ReadAll(out2)
			cmd.Wait()
			os.Chdir(cwd)
			if strings.Contains(string(out2b), "fatal: ") {
				fmt.Println(strings.TrimSpace(string(out2b)))
				fmt.Println("Could not clone, please re-enter")
			} else {
				// Remove, this cloning only was to check that it was a valid thing
				os.RemoveAll(path.Join(CachePath, EncodeBase58(yesno)))
				break
			}
		} else {
			fmt.Println("Already exists, doing nothing.")
			break
		}
	}
	configParameters.Remote = yesno

	// Loop until user chooses an available program
	for {
		fmt.Printf("Which editor do you want to use: micro (default), vim,  nano, or emacs? ")
		fmt.Scanln(&yesno)
		if strings.TrimSpace(strings.ToLower(yesno)) == "nano" {
			configParameters.Editor = "nano"
		} else if strings.TrimSpace(strings.ToLower(yesno)) == "emacs" {
			configParameters.Editor = "emacs"
		} else if strings.TrimSpace(strings.ToLower(yesno)) == "vim" {
			configParameters.Editor = "vim"
		} else {
			configParameters.Editor = "micro"
		}
		if Version != "dev" && configParameters.Editor == "micro" {
			break
		}
		// check if it actually exists
		cmd := exec.Command(path.Join(ProgramPath, configParameters.Editor+Extension), "--version")
		_, err2 := cmd.Output()
		if err2 == nil {
			break
		}
		cmd = exec.Command(path.Join(".", configParameters.Editor+Extension), "--version")
		_, err2 = cmd.Output()
		if err2 == nil {
			break
		}
		_, err := Asset("bin/" + configParameters.Editor + Extension)
		if err == nil {
			break
		}
		fmt.Printf("\n%s not found, are you sure its installed?\n\n", configParameters.Editor+Extension)
	}

	configParameters.CurrentDocument = ""

	b, err := json.Marshal(configParameters)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(ConfigPath, "config.json"), b, 0644)
}

func LoadConfiguration() {
	defer timeTrack(time.Now(), "Loaded and saved configuration")
	var c Config
	data, err := ioutil.ReadFile(path.Join(ConfigPath, "config.json"))
	if err != nil {
		logger.Error("Could not load config.json")
		return
	}
	json.Unmarshal(data, &c)
	if len(CurrentDocument) == 0 {
		CurrentDocument = c.CurrentDocument
	}
	Editor = c.Editor
	Remote = c.Remote
	RemoteFolder = path.Join(CachePath, EncodeBase58(Remote))
	if len(Remote) == 0 {
		SetupConfig()
	}
}

func SaveConfiguration(editor string, remote string, currentdoc string) {
	defer timeTrack(time.Now(), "Saved configuration")
	c := Config{Editor: editor, Remote: remote, CurrentDocument: currentdoc}
	b, err := json.Marshal(c)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(ConfigPath, "config.json"), b, 0644)
}
<|endoftext|>


<commit_before>package cli

import (
	"encoding/json"
	"errors"
	"golang.org/x/net/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
	"io"
	"log"
)

type EventsCommand struct {
	App    *CliApp
	Id     string
	Format string
}

// __jsonp1__([{"id":"1","channel":"/meta/handshake","successful":true,"version":"1.0","supportedConnectionTypes":["long-polling","cross-origin-long-polling","callback-polling","websocket","eventsource","in-process"],"clientId":"jn6854gieb65ld2i0nkwz3yf2rtczwl","advice":{"reconnect":"retry","interval":0,"timeout":25000}}]);

type FayeAuth struct {
	AuthToken string `json:"auth_token"`
}
type FayeMsg struct {
	Channel                  string    `json:"channel"`
	ClientId                 string    `json:"clientId,omitempty"`
	ConnectionType           string    `json:"connectionType,omitempty"`
	Id                       string    `json:"id,omitempty"`
	Subscription             string    `json:"subscription,omitempty"`
	Ext                      *FayeAuth `json:"ext,omitempty"`
	Version                  string    `json:"version,omitempty"`
	SupportedConnectionTypes []string  `json:"supportedConnectionTypes,omitempty"`
	Successful               bool      `json:"successful,omitempty"`
	Error                    string    `json:"error,omitempty"`
	Data                     string    `json:"data,omitempty"`
}

func sendmsg(ws *websocket.Conn, msgs ...FayeMsg) error {
	jmsg, err := json.Marshal(msgs)
	if err != nil {
		return err
	}
	if _, err := ws.Write(jmsg); err != nil {
		return err
	}
	return nil
}
func recvmsg(ws *websocket.Conn) ([]FayeMsg, error) {
	var jmsg = make([]byte, 4096)
	var n int
	n, err := ws.Read(jmsg)
	if err != nil {
		return nil, err
	}
	msgl := make([]FayeMsg, 1)
	err = json.Unmarshal(jmsg[0:n], &msgl)
	if err != nil {
		return nil, err
	}
	if msgl[0].Successful == false {
		return nil, errors.New(msgl[0].Error)
	}
	return msgl, nil
}

func (l *TokenCommand) watch(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	w := tabWriterRight()
	defer w.Flush()

	token, err := l.App.Client.Token()
	if token == nil {
		l.App.Fatalf("No cached OAuth token found for %s", l.App.ClientName)
	}

	handshake := FayeMsg{
		Channel:                  "/meta/handshake",
		Version:                  "1.0",
		SupportedConnectionTypes: []string{"long-polling", "websocket"},
	}

	origin := "https://events.gb1s.brightbox.com"
	url := "wss://events.gb1s.brightbox.com/stream"

	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		return err
	}
	log.Println("Handshake...")
	err = sendmsg(ws, handshake)
	if err != nil {
		return err
	}

	msgl, err := recvmsg(ws)
	if err != nil {
		return err
	}
	log.Println(msgl[0].SupportedConnectionTypes)
	cid := msgl[0].ClientId
	log.Println("Hands shook, got Client Id " + cid)

	connect := FayeMsg{
		Channel:        "/meta/connect",
		ClientId:       cid,
		ConnectionType: "websocket",
		Ext: &FayeAuth{
			AuthToken: token.AccessToken,
		},

	}

	log.Println("Connecting...")
	err = sendmsg(ws, connect)
	if err != nil {
		return err
	}
	msgl, err = recvmsg(ws)
	if err != nil {
		return err
	}
	log.Println("Subscribing...")
	subscribe := FayeMsg{
		Channel:      "/meta/subscribe",
		ClientId:     cid,
		Subscription: "/account/" + l.App.accountId(),
		Ext: &FayeAuth{
			AuthToken: token.AccessToken,
		},
	}
	err = sendmsg(ws, subscribe)
	if err != nil {
		return err
	}
	msgl, err = recvmsg(ws)
	if err != nil {
		return err
	}
	log.Println("Subscribed")

	var jmsg = make([]byte, 4096)
	var n int
	for {
		n, err = ws.Read(jmsg)
		if err == io.EOF {
			log.Println("EOF Disconnected")
			return nil
		}
		if err != nil {
			return err
		}
		log.Println(string(jmsg[0:n]))
	}
}

func ConfigureEventsCommand(app *CliApp) {
	cmd := TokenCommand{App: app}
	events := app.Command("events", "view event stream")
	events.Command("watch", "listen for events and output them").Action(cmd.watch)
}
<commit_msg>events watch command now working<commit_after>package cli

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"gopkg.in/alecthomas/kingpin.v2"
	"io"
	"log"
	"strings"
)

type EventsCommand struct {
	App    *CliApp
	Id     string
	Format string
}

type FayeAdvice struct {
	Timeout int
}
type FayeAuth struct {
	AuthToken string `json:"auth_token"`
}
type FayeMsg struct {
	Channel                  string           `json:"channel,omitempty"`
	ClientId                 string           `json:"clientId,omitempty"`
	ConnectionType           string           `json:"connectionType,omitempty"`
	Id                       string           `json:"id,omitempty"`
	Subscription             string           `json:"subscription,omitempty"`
	Ext                      *FayeAuth        `json:"ext,omitempty"`
	Version                  string           `json:"version,omitempty"`
	SupportedConnectionTypes []string         `json:"supportedConnectionTypes,omitempty"`
	Successful               bool             `json:"successful,omitempty"`
	Error                    string           `json:"error,omitempty"`
	Data                     *json.RawMessage `json:"data,omitempty"`
	Advice                   *FayeAdvice      `json:"advice,omitempty"`
}

type EventResource struct {
	Id    string
	Name  string
	Email *string
}
type Event struct {
	Id       string
	Action   *string
	State    *string
	Resource *EventResource
	Account  *EventResource
	Affects  *[]EventResource
	Touches  *[]EventResource
	User     *EventResource
}

func sendmsg(ws *websocket.Conn, msgs ...*FayeMsg) error {
	jmsg, err := json.Marshal(msgs)
	if err != nil {
		return err
	}
	if err = ws.WriteMessage(websocket.TextMessage, jmsg); err != nil {
		return err
	}
	return nil
}
func recvmsg(ws *websocket.Conn) ([]FayeMsg, error) {
	_, jmsg, err := ws.ReadMessage()
	//log.Println(string(jmsg))
	if err != nil {
		return nil, err
	}
	msgl := make([]FayeMsg, 1)
	err = json.Unmarshal(jmsg, &msgl)
	if err != nil {
		return nil, err
	}
	/*	if msgl[0].Successful == false {
		return nil, errors.New(msgl[0].Error)
	} */
	return msgl, nil
}

func (l *EventsCommand) watch(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	w := tabWriterRight()
	defer w.Flush()

	token, err := l.App.Client.Token()
	if token == nil {
		l.App.Fatalf("No cached OAuth token found for %s", l.App.ClientName)
	}

	handshake := FayeMsg{
		Channel:                  "/meta/handshake",
		Version:                  "1.0",
		SupportedConnectionTypes: []string{"long-polling", "websocket"},
	}

	url := "wss://events.gb1s.brightbox.com/stream"
	ws, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return err
	}
	defer ws.Close()
	err = sendmsg(ws, &handshake)
	if err != nil {
		return err
	}

	msgl, err := recvmsg(ws)
	if err != nil {
		return err
	}
	msg := msgl[0]
	cid := msg.ClientId
	/*timeout := 20000
	if msg.Advice != nil {
		timeout = msg.Advice.Timeout
	}*/

	err = sendmsg(ws, nil)

	connect := FayeMsg{
		Channel:        "/meta/connect",
		ClientId:       cid,
		ConnectionType: "websocket",
	}
	subscribe := FayeMsg{
		Channel:      "/meta/subscribe",
		ClientId:     cid,
		Subscription: "/account/" + l.App.accountId(),
		Ext:          &FayeAuth{AuthToken: token.AccessToken},
	}
	err = sendmsg(ws, &connect, &subscribe)
	if err != nil {
		return err
	}
	for {
		msgl, err := recvmsg(ws)
		if err == io.EOF {
			log.Println("EOF Disconnected")
			return nil
		}
		if err != nil {
			return err
		}
		for _, msg := range msgl {
			if msg.Data != nil && strings.HasPrefix(msg.Channel, "/account/acc") {
				e := Event{}
				err = json.Unmarshal(*msg.Data, &e)
				if err != nil {
					log.Println(err)
					continue
				}
				if e.Resource != nil && e.User != nil {
					log.Printf("%s %s %s\n", *e.User.Email, *e.Action, e.Resource.Id)
				} else if e.Resource != nil {
					log.Printf("%s %s %s\n", e.Resource.Id, *e.State, *e.Action)
				} else {
					log.Println(string(*msg.Data))
				}
			}
			if msg.Channel == "/meta/connect" {
				if msg.Successful {
					err = sendmsg(ws, &connect)
					if err != nil {
						log.Println("Connect error: ", err.Error())
					}
				} else {
					return fmt.Errorf("Event connection failure: " + msg.Error)
				}
			} else if msg.Channel == "/meta/subscribe" && !msg.Successful {
				return fmt.Errorf("Event subscription failure: " + msg.Error)
			}
		}
	}
}

func ConfigureEventsCommand(app *CliApp) {
	cmd := EventsCommand{App: app}
	events := app.Command("events", "view event stream")
	events.Command("watch", "listen for events and output them").Action(cmd.watch)
}
<|endoftext|>


<commit_before>package cli

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

// Interface that must be implemented by actions. This is interface is used by the RegisterAction function. The Run
// method of the implementing type will be called if the given route matches it.
type Runner interface {
	Run() error
}

// Create a new router.
func NewRouter() *Router {
	r := &Router{}
	r.root = &routingTreeNode{children: map[string]*routingTreeNode{}}
	return r
}

// Run the given arguments against the registered actions, i.e. try to find a matching route and run the according
// action.
func (r *Router) Run(args ...string) (e error) {
	if r.initFailed {
		log.Fatal("errors found during initialization")
	}
	// Find action and parse args.
	node, args := r.findNode(args, true)
	if node != nil && node.action != nil {
		if e := node.action.parseArgs(args); e != nil {
			node.showHelp()
			return e
		}
	} else { // Failed to find node.
		node.showHelp()
		return fmt.Errorf("no route matched")
	}

	return node.action.runner.Run()
}

// Run the arguments from the commandline (aka os.Args) against the registered actions, i.e. try to find a matching
// route and run the according action.
func (r *Router) RunWithArgs() (e error) {
	return r.Run(os.Args[1:]...)
}

type annonymousAction struct {
	runner      func() error
	description string
}

func (aA *annonymousAction) Run() error {
	return aA.runner()
}

// Register the given function as handler for the given route. This is a shortcut for actions that don't need options or
// arguments. A description can be provided as an optional argument.
func (r *Router) RegisterFunc(path string, f func() error, desc string) {
	aA := &annonymousAction{runner: f}
	r.Register(path, aA, desc)
}

// Register the given action (some struct implementing the Runner interface) for the given route.
func (r *Router) Register(path string, runner Runner, desc string) {
	a, e := newAction(path, runner, desc)
	if e != nil {
		log.Printf("%s", e)
		r.initFailed = true
		return
	}

	pathSegments := strings.Split(a.path, "/")
	node, pathSegments := r.findNode(pathSegments, false)
	if node != nil {
		if node.action != nil {
			log.Printf("failed to register action for path %q: action for path %q already registered", a.path, node.action.path)
			r.initFailed = true
			return
		} else if len(pathSegments) == 0 && len(node.children) > 0 {
			log.Printf("failed to register action for path %q: longer paths with this prefix exist", a.path)
			r.initFailed = true
			return
		}
	} else {
		node = r.root
	}

	for _, p := range pathSegments {
		newNode := &routingTreeNode{children: map[string]*routingTreeNode{}}
		node.children[p] = newNode
		node = newNode
	}

	node.action = a
}

func (r *Router) showHelp() {
}
<commit_msg>use standardized error for NoRouteError<commit_after>package cli

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

// Interface that must be implemented by actions. This is interface is used by the RegisterAction function. The Run
// method of the implementing type will be called if the given route matches it.
type Runner interface {
	Run() error
}

// Create a new router.
func NewRouter() *Router {
	r := &Router{}
	r.root = &routingTreeNode{children: map[string]*routingTreeNode{}}
	return r
}

var NoRouteError = fmt.Errorf("no route matched")

// Run the given arguments against the registered actions, i.e. try to find a matching route and run the according
// action.
func (r *Router) Run(args ...string) (e error) {
	if r.initFailed {
		log.Fatal("errors found during initialization")
	}
	// Find action and parse args.
	node, args := r.findNode(args, true)
	if node != nil && node.action != nil {
		if e := node.action.parseArgs(args); e != nil {
			node.showHelp()
			return e
		}
	} else { // Failed to find node.
		node.showHelp()
		return NoRouteError
	}

	return node.action.runner.Run()
}

// Run the arguments from the commandline (aka os.Args) against the registered actions, i.e. try to find a matching
// route and run the according action.
func (r *Router) RunWithArgs() (e error) {
	return r.Run(os.Args[1:]...)
}

type annonymousAction struct {
	runner      func() error
	description string
}

func (aA *annonymousAction) Run() error {
	return aA.runner()
}

// Register the given function as handler for the given route. This is a shortcut for actions that don't need options or
// arguments. A description can be provided as an optional argument.
func (r *Router) RegisterFunc(path string, f func() error, desc string) {
	aA := &annonymousAction{runner: f}
	r.Register(path, aA, desc)
}

// Register the given action (some struct implementing the Runner interface) for the given route.
func (r *Router) Register(path string, runner Runner, desc string) {
	a, e := newAction(path, runner, desc)
	if e != nil {
		log.Printf("%s", e)
		r.initFailed = true
		return
	}

	pathSegments := strings.Split(a.path, "/")
	node, pathSegments := r.findNode(pathSegments, false)
	if node != nil {
		if node.action != nil {
			log.Printf("failed to register action for path %q: action for path %q already registered", a.path, node.action.path)
			r.initFailed = true
			return
		} else if len(pathSegments) == 0 && len(node.children) > 0 {
			log.Printf("failed to register action for path %q: longer paths with this prefix exist", a.path)
			r.initFailed = true
			return
		}
	} else {
		node = r.root
	}

	for _, p := range pathSegments {
		newNode := &routingTreeNode{children: map[string]*routingTreeNode{}}
		node.children[p] = newNode
		node = newNode
	}

	node.action = a
}

func (r *Router) showHelp() {
}
<|endoftext|>


<commit_before>// Package client provides a Stripe client for invoking APIs across all resources
package client

import (
	. "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/account"
	"github.com/stripe/stripe-go/balance"
	"github.com/stripe/stripe-go/bankaccount"
	"github.com/stripe/stripe-go/bitcoinreceiver"
	"github.com/stripe/stripe-go/bitcointransaction"
	"github.com/stripe/stripe-go/card"
	"github.com/stripe/stripe-go/charge"
	"github.com/stripe/stripe-go/countryspec"
	"github.com/stripe/stripe-go/coupon"
	"github.com/stripe/stripe-go/customer"
	"github.com/stripe/stripe-go/discount"
	"github.com/stripe/stripe-go/dispute"
	"github.com/stripe/stripe-go/event"
	"github.com/stripe/stripe-go/fee"
	"github.com/stripe/stripe-go/feerefund"
	"github.com/stripe/stripe-go/fileupload"
	"github.com/stripe/stripe-go/invoice"
	"github.com/stripe/stripe-go/invoiceitem"
	"github.com/stripe/stripe-go/order"
	"github.com/stripe/stripe-go/orderreturn"
	"github.com/stripe/stripe-go/paymentsource"
	"github.com/stripe/stripe-go/plan"
	"github.com/stripe/stripe-go/product"
	"github.com/stripe/stripe-go/recipient"
	"github.com/stripe/stripe-go/refund"
	"github.com/stripe/stripe-go/reversal"
	"github.com/stripe/stripe-go/sku"
	"github.com/stripe/stripe-go/source"
	"github.com/stripe/stripe-go/sub"
	"github.com/stripe/stripe-go/token"
	"github.com/stripe/stripe-go/transfer"
)

// API is the Stripe client. It contains all the different resources available.
type API struct {
	// Charges is the client used to invoke /charges APIs.
	// For more details see https://stripe.com/docs/api#charges.
	Charges *charge.Client
	// Customers is the client used to invoke /customers APIs.
	// For more details see https://stripe.com/docs/api#customers.
	Customers *customer.Client
	// Cards is the client used to invoke /cards APIs.
	// For more details see https://stripe.com/docs/api#cards.
	Cards *card.Client
	// Subs is the client used to invoke /subscriptions APIs.
	// For more details see https://stripe.com/docs/api#subscriptions.
	Subs *sub.Client
	// Plans is the client used to invoke /plans APIs.
	// For more details see https://stripe.com/docs/api#plans.
	Plans *plan.Client
	// Coupons is the client used to invoke /coupons APIs.
	// For more details see https://stripe.com/docs/api#coupons.
	Coupons *coupon.Client
	// Discounts is the client used to invoke discount-related APIs.
	// For mode details see https://stripe.com/docs/api#discounts.
	Discounts *discount.Client
	// Invoices is the client used to invoke /invoices APIs.
	// For more details see https://stripe.com/docs/api#invoices.
	Invoices *invoice.Client
	// InvoiceItems is the client used to invoke /invoiceitems APIs.
	// For more details see https://stripe.com/docs/api#invoiceitems.
	InvoiceItems *invoiceitem.Client
	// Disputes is the client used to invoke dispute-related APIs.
	// For more details see https://stripe.com/docs/api#disputes.
	Disputes *dispute.Client
	// Transfers is the client used to invoke /transfers APIs.
	// For more details see https://stripe.com/docs/api#transfers.
	Transfers *transfer.Client
	// Recipients is the client used to invoke /recipients APIs.
	// For more details see https://stripe.com/docs/api#recipients.
	Recipients *recipient.Client
	// Refunds is the client used to invoke /refunds APIs.
	// For more details see https://stripe.com/docs/api#refunds.
	Refunds *refund.Client
	// Fees is the client used to invoke /application_fees APIs.
	// For more details see https://stripe.com/docs/api#application_fees.
	Fees *fee.Client
	// FeeRefunds is the client used to invoke /application_fees/refunds APIs.
	// For more details see https://stripe.com/docs/api#fee_refundss.
	FeeRefunds *feerefund.Client
	// Account is the client used to invoke /account APIs.
	// For more details see https://stripe.com/docs/api#account.
	Account *account.Client
	// CountrySpec is the client used to invoke /country_specs APIs.
	// For more details see https://stripe.com/docs/api#country_specs.
	CountrySpec *countryspec.Client
	// Balance is the client used to invoke /balance and transaction-related APIs.
	// For more details see https://stripe.com/docs/api#balance.
	Balance *balance.Client
	// Events is the client used to invoke /events APIs.
	// For more details see https://stripe.com/docs/api#events.
	Events *event.Client
	// Tokens is the client used to invoke /tokens APIs.
	// For more details see https://stripe.com/docs/api#tokens.
	Tokens *token.Client
	// FileUploads is the client used to invoke the uploads /files APIs.
	// For more details see https://stripe.com/docs/api#file_uploads.
	FileUploads *fileupload.Client
	// BitcoinReceivers is the client used to invoke /bitcoin/receivers APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinReceivers *bitcoinreceiver.Client
	// BitcoinTransactions is the client used to invoke /bitcoin/transactions APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinTransactions *bitcointransaction.Client
	// Reversals is the client used to invoke /transfers/reversals APIs.
	Reversals *reversal.Client
	// BankAccounts is the client used to invoke /accounts/bank_accounts APIs.
	BankAccounts *bankaccount.Client
	// Products is the client used to invoke /products APIs.
	// For more details see https://stripe.com/docs/api#products.
	Products *product.Client
	// Orders is the client used to invoke /orders APIs.
	// For more details see https://stripe.com/docs/api#orders.
	Orders *order.Client
	// OrderReturns is the client used to invoke /order_returns APIs.
	// For more details, see https://stripe.com/docs/api#order_returns.
	OrderReturns *orderreturn.Client
	// Skus is the client used to invoke /skus APIs.
	// For more details see https://stripe.com/docs/api#skus.
	Skus *sku.Client
	// Sources is the client used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api#sources.
	Sources *source.Client
	// PaymentSource is used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api.
	PaymentSource *paymentsource.Client
}

// Init initializes the Stripe client with the appropriate secret key
// as well as providing the ability to override the backend as needed.
func (a *API) Init(key string, backends *Backends) {
	if backends == nil {
		backends = &Backends{GetBackend(APIBackend), GetBackend(UploadsBackend)}
	}

	a.Charges = &charge.Client{B: backends.API, Key: key}
	a.Customers = &customer.Client{B: backends.API, Key: key}
	a.Cards = &card.Client{B: backends.API, Key: key}
	a.Subs = &sub.Client{B: backends.API, Key: key}
	a.Plans = &plan.Client{B: backends.API, Key: key}
	a.Coupons = &coupon.Client{B: backends.API, Key: key}
	a.Discounts = &discount.Client{B: backends.API, Key: key}
	a.Invoices = &invoice.Client{B: backends.API, Key: key}
	a.InvoiceItems = &invoiceitem.Client{B: backends.API, Key: key}
	a.Disputes = &dispute.Client{B: backends.API, Key: key}
	a.Transfers = &transfer.Client{B: backends.API, Key: key}
	a.Recipients = &recipient.Client{B: backends.API, Key: key}
	a.Refunds = &refund.Client{B: backends.API, Key: key}
	a.Fees = &fee.Client{B: backends.API, Key: key}
	a.FeeRefunds = &feerefund.Client{B: backends.API, Key: key}
	a.Account = &account.Client{B: backends.API, Key: key}
	a.CountrySpec = &countryspec.Client{B: backends.API, Key: key}
	a.Balance = &balance.Client{B: backends.API, Key: key}
	a.Events = &event.Client{B: backends.API, Key: key}
	a.Tokens = &token.Client{B: backends.API, Key: key}
	a.FileUploads = &fileupload.Client{B: backends.Uploads, Key: key}
	a.BitcoinReceivers = &bitcoinreceiver.Client{B: backends.API, Key: key}
	a.BitcoinTransactions = &bitcointransaction.Client{B: backends.API, Key: key}
	a.Reversals = &reversal.Client{B: backends.API, Key: key}
	a.BankAccounts = &bankaccount.Client{B: backends.API, Key: key}
	a.Products = &product.Client{B: backends.API, Key: key}
	a.Orders = &order.Client{B: backends.API, Key: key}
	a.OrderReturns = &orderreturn.Client{B: backends.API, Key: key}
	a.Skus = &sku.Client{B: backends.API, Key: key}
	a.Sources = &source.Client{B: backends.API, Key: key}
	a.PaymentSource = &paymentsource.Client{B: backends.API, Key: key}
}

// New creates a new Stripe client with the appropriate secret key
// as well as providing the ability to override the backends as needed.
func New(key string, backends *Backends) *API {
	api := API{}
	api.Init(key, backends)
	return &api
}
<commit_msg>adding subscription items client in main API client<commit_after>// Package client provides a Stripe client for invoking APIs across all resources
package client

import (
	. "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/account"
	"github.com/stripe/stripe-go/balance"
	"github.com/stripe/stripe-go/bankaccount"
	"github.com/stripe/stripe-go/bitcoinreceiver"
	"github.com/stripe/stripe-go/bitcointransaction"
	"github.com/stripe/stripe-go/card"
	"github.com/stripe/stripe-go/charge"
	"github.com/stripe/stripe-go/countryspec"
	"github.com/stripe/stripe-go/coupon"
	"github.com/stripe/stripe-go/customer"
	"github.com/stripe/stripe-go/discount"
	"github.com/stripe/stripe-go/dispute"
	"github.com/stripe/stripe-go/event"
	"github.com/stripe/stripe-go/fee"
	"github.com/stripe/stripe-go/feerefund"
	"github.com/stripe/stripe-go/fileupload"
	"github.com/stripe/stripe-go/invoice"
	"github.com/stripe/stripe-go/invoiceitem"
	"github.com/stripe/stripe-go/order"
	"github.com/stripe/stripe-go/orderreturn"
	"github.com/stripe/stripe-go/paymentsource"
	"github.com/stripe/stripe-go/plan"
	"github.com/stripe/stripe-go/product"
	"github.com/stripe/stripe-go/recipient"
	"github.com/stripe/stripe-go/refund"
	"github.com/stripe/stripe-go/reversal"
	"github.com/stripe/stripe-go/sku"
	"github.com/stripe/stripe-go/source"
	"github.com/stripe/stripe-go/sub"
	"github.com/stripe/stripe-go/subitem"
	"github.com/stripe/stripe-go/token"
	"github.com/stripe/stripe-go/transfer"
)

// API is the Stripe client. It contains all the different resources available.
type API struct {
	// Charges is the client used to invoke /charges APIs.
	// For more details see https://stripe.com/docs/api#charges.
	Charges *charge.Client
	// Customers is the client used to invoke /customers APIs.
	// For more details see https://stripe.com/docs/api#customers.
	Customers *customer.Client
	// Cards is the client used to invoke /cards APIs.
	// For more details see https://stripe.com/docs/api#cards.
	Cards *card.Client
	// Subs is the client used to invoke /subscriptions APIs.
	// For more details see https://stripe.com/docs/api#subscriptions.
	Subs *sub.Client
	// SubItems is the client used to invoke subscription's items-related APIs.
	// For more details see https://stripe.com/docs/api#subscription_items.
	SubItems *subitem.Client
	// Plans is the client used to invoke /plans APIs.
	// For more details see https://stripe.com/docs/api#plans.
	Plans *plan.Client
	// Coupons is the client used to invoke /coupons APIs.
	// For more details see https://stripe.com/docs/api#coupons.
	Coupons *coupon.Client
	// Discounts is the client used to invoke discount-related APIs.
	// For mode details see https://stripe.com/docs/api#discounts.
	Discounts *discount.Client
	// Invoices is the client used to invoke /invoices APIs.
	// For more details see https://stripe.com/docs/api#invoices.
	Invoices *invoice.Client
	// InvoiceItems is the client used to invoke /invoiceitems APIs.
	// For more details see https://stripe.com/docs/api#invoiceitems.
	InvoiceItems *invoiceitem.Client
	// Disputes is the client used to invoke dispute-related APIs.
	// For more details see https://stripe.com/docs/api#disputes.
	Disputes *dispute.Client
	// Transfers is the client used to invoke /transfers APIs.
	// For more details see https://stripe.com/docs/api#transfers.
	Transfers *transfer.Client
	// Recipients is the client used to invoke /recipients APIs.
	// For more details see https://stripe.com/docs/api#recipients.
	Recipients *recipient.Client
	// Refunds is the client used to invoke /refunds APIs.
	// For more details see https://stripe.com/docs/api#refunds.
	Refunds *refund.Client
	// Fees is the client used to invoke /application_fees APIs.
	// For more details see https://stripe.com/docs/api#application_fees.
	Fees *fee.Client
	// FeeRefunds is the client used to invoke /application_fees/refunds APIs.
	// For more details see https://stripe.com/docs/api#fee_refundss.
	FeeRefunds *feerefund.Client
	// Account is the client used to invoke /account APIs.
	// For more details see https://stripe.com/docs/api#account.
	Account *account.Client
	// CountrySpec is the client used to invoke /country_specs APIs.
	// For more details see https://stripe.com/docs/api#country_specs.
	CountrySpec *countryspec.Client
	// Balance is the client used to invoke /balance and transaction-related APIs.
	// For more details see https://stripe.com/docs/api#balance.
	Balance *balance.Client
	// Events is the client used to invoke /events APIs.
	// For more details see https://stripe.com/docs/api#events.
	Events *event.Client
	// Tokens is the client used to invoke /tokens APIs.
	// For more details see https://stripe.com/docs/api#tokens.
	Tokens *token.Client
	// FileUploads is the client used to invoke the uploads /files APIs.
	// For more details see https://stripe.com/docs/api#file_uploads.
	FileUploads *fileupload.Client
	// BitcoinReceivers is the client used to invoke /bitcoin/receivers APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinReceivers *bitcoinreceiver.Client
	// BitcoinTransactions is the client used to invoke /bitcoin/transactions APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinTransactions *bitcointransaction.Client
	// Reversals is the client used to invoke /transfers/reversals APIs.
	Reversals *reversal.Client
	// BankAccounts is the client used to invoke /accounts/bank_accounts APIs.
	BankAccounts *bankaccount.Client
	// Products is the client used to invoke /products APIs.
	// For more details see https://stripe.com/docs/api#products.
	Products *product.Client
	// Orders is the client used to invoke /orders APIs.
	// For more details see https://stripe.com/docs/api#orders.
	Orders *order.Client
	// OrderReturns is the client used to invoke /order_returns APIs.
	// For more details, see https://stripe.com/docs/api#order_returns.
	OrderReturns *orderreturn.Client
	// Skus is the client used to invoke /skus APIs.
	// For more details see https://stripe.com/docs/api#skus.
	Skus *sku.Client
	// Sources is the client used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api#sources.
	Sources *source.Client
	// PaymentSource is used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api.
	PaymentSource *paymentsource.Client
}

// Init initializes the Stripe client with the appropriate secret key
// as well as providing the ability to override the backend as needed.
func (a *API) Init(key string, backends *Backends) {
	if backends == nil {
		backends = &Backends{GetBackend(APIBackend), GetBackend(UploadsBackend)}
	}

	a.Charges = &charge.Client{B: backends.API, Key: key}
	a.Customers = &customer.Client{B: backends.API, Key: key}
	a.Cards = &card.Client{B: backends.API, Key: key}
	a.Subs = &sub.Client{B: backends.API, Key: key}
	a.SubItems = &subitem.Client{B: backends.API, Key: key}
	a.Plans = &plan.Client{B: backends.API, Key: key}
	a.Coupons = &coupon.Client{B: backends.API, Key: key}
	a.Discounts = &discount.Client{B: backends.API, Key: key}
	a.Invoices = &invoice.Client{B: backends.API, Key: key}
	a.InvoiceItems = &invoiceitem.Client{B: backends.API, Key: key}
	a.Disputes = &dispute.Client{B: backends.API, Key: key}
	a.Transfers = &transfer.Client{B: backends.API, Key: key}
	a.Recipients = &recipient.Client{B: backends.API, Key: key}
	a.Refunds = &refund.Client{B: backends.API, Key: key}
	a.Fees = &fee.Client{B: backends.API, Key: key}
	a.FeeRefunds = &feerefund.Client{B: backends.API, Key: key}
	a.Account = &account.Client{B: backends.API, Key: key}
	a.CountrySpec = &countryspec.Client{B: backends.API, Key: key}
	a.Balance = &balance.Client{B: backends.API, Key: key}
	a.Events = &event.Client{B: backends.API, Key: key}
	a.Tokens = &token.Client{B: backends.API, Key: key}
	a.FileUploads = &fileupload.Client{B: backends.Uploads, Key: key}
	a.BitcoinReceivers = &bitcoinreceiver.Client{B: backends.API, Key: key}
	a.BitcoinTransactions = &bitcointransaction.Client{B: backends.API, Key: key}
	a.Reversals = &reversal.Client{B: backends.API, Key: key}
	a.BankAccounts = &bankaccount.Client{B: backends.API, Key: key}
	a.Products = &product.Client{B: backends.API, Key: key}
	a.Orders = &order.Client{B: backends.API, Key: key}
	a.OrderReturns = &orderreturn.Client{B: backends.API, Key: key}
	a.Skus = &sku.Client{B: backends.API, Key: key}
	a.Sources = &source.Client{B: backends.API, Key: key}
	a.PaymentSource = &paymentsource.Client{B: backends.API, Key: key}
}

// New creates a new Stripe client with the appropriate secret key
// as well as providing the ability to override the backends as needed.
func New(key string, backends *Backends) *API {
	api := API{}
	api.Init(key, backends)
	return &api
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 client provides bindings for the etcd APIs.

Create a Config and exchange it for a Client:

	import (
		"net/http"

		"github.com/coreos/etcd/client"
		"golang.org/x/net/context"
	)

	cfg := client.Config{
		Endpoints: []string{"http://127.0.0.1:4001"},
		Transport: DefaultTransport,
	}

	c, err := client.New(cfg)
	if err != nil {
		// handle error
	}

Create a KeysAPI using the Client, then use it to interact with etcd:

	kAPI := client.NewKeysAPI(c)

	// create a new key /foo with the value "bar"
	kAPI.Create(context.Background(), "/foo", "bar")

	// delete the newly created key only if the value is still "bar"
	kAPI.Delete(context.Background(), "/foo", &DeleteOptions{PrevValue: "bar"})

*/
package client
<commit_msg>client: document using a custom context<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 client provides bindings for the etcd APIs.

Create a Config and exchange it for a Client:

	import (
		"net/http"

		"github.com/coreos/etcd/client"
		"golang.org/x/net/context"
	)

	cfg := client.Config{
		Endpoints: []string{"http://127.0.0.1:4001"},
		Transport: DefaultTransport,
	}

	c, err := client.New(cfg)
	if err != nil {
		// handle error
	}

Create a KeysAPI using the Client, then use it to interact with etcd:

	kAPI := client.NewKeysAPI(c)

	// create a new key /foo with the value "bar"
	kAPI.Create(context.Background(), "/foo", "bar")

	// delete the newly created key only if the value is still "bar"
	kAPI.Delete(context.Background(), "/foo", &DeleteOptions{PrevValue: "bar"})

Use a custom context to set timeouts on your operations:

	import "time"

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// set a new key, ignoring it's previous state
	_, err := kAPI.Set(ctx, "/ping", "pong", nil)
	if err != nil {
		if err == context.DeadlineExceeded {
			// request took longer than 5s
		} else {
			// handle error
		}
	}

*/
package client
<|endoftext|>