<commit_before>package netlink

import (
	"fmt"
	"log"
	"net"
	"strings"
	"syscall"

	"github.com/vishvananda/netlink/nl"
	"github.com/vishvananda/netns"
)

// IFA_FLAGS is a u32 attribute.
const IFA_FLAGS = 0x8

// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func AddrAdd(link Link, addr *Addr) error {
	return pkgHandle.AddrAdd(link, addr)
}

// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func AddrReplace(link Link, addr *Addr) error {
	return pkgHandle.AddrReplace(link, addr)
}

// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func AddrDel(link Link, addr *Addr) error {
	return pkgHandle.AddrDel(link, addr)
}

// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) AddrDel(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
	base := link.Attrs()
	if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
		return fmt.Errorf("label must begin with interface name")
	}
	h.ensureIndex(base)

	family := nl.GetIPFamily(addr.IP)

	msg := nl.NewIfAddrmsg(family)
	msg.Index = uint32(base.Index)
	msg.Scope = uint8(addr.Scope)
	prefixlen, _ := addr.Mask.Size()
	msg.Prefixlen = uint8(prefixlen)
	req.AddData(msg)

	var localAddrData []byte
	if family == FAMILY_V4 {
		localAddrData = addr.IP.To4()
	} else {
		localAddrData = addr.IP.To16()
	}

	localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
	req.AddData(localData)
	var peerAddrData []byte
	if addr.Peer != nil {
		if family == FAMILY_V4 {
			peerAddrData = addr.Peer.IP.To4()
		} else {
			peerAddrData = addr.Peer.IP.To16()
		}
	} else {
		peerAddrData = localAddrData
	}

	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
	req.AddData(addressData)

	if addr.Flags != 0 {
		if addr.Flags <= 0xff {
			msg.IfAddrmsg.Flags = uint8(addr.Flags)
		} else {
			b := make([]byte, 4)
			native.PutUint32(b, uint32(addr.Flags))
			flagsData := nl.NewRtAttr(IFA_FLAGS, b)
			req.AddData(flagsData)
		}
	}

	if addr.Broadcast != nil {
		req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
	}

	if addr.Label != "" {
		labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
		req.AddData(labelData)
	}

	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
	return err
}

// AddrList gets a list of IP addresses in the system.
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func AddrList(link Link, family int) ([]Addr, error) {
	return pkgHandle.AddrList(link, family)
}

// AddrList gets a list of IP addresses in the system.
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
	req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
	msg := nl.NewIfInfomsg(family)
	req.AddData(msg)

	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
	if err != nil {
		return nil, err
	}

	indexFilter := 0
	if link != nil {
		base := link.Attrs()
		h.ensureIndex(base)
		indexFilter = base.Index
	}

	var res []Addr
	for _, m := range msgs {
		addr, msgFamily, ifindex, err := parseAddr(m)
		if err != nil {
			return res, err
		}

		if link != nil && ifindex != indexFilter {
			// Ignore messages from other interfaces
			continue
		}

		if family != FAMILY_ALL && msgFamily != family {
			continue
		}

		res = append(res, addr)
	}

	return res, nil
}

func parseAddr(m []byte) (addr Addr, family, index int, err error) {
	msg := nl.DeserializeIfAddrmsg(m)

	family = -1
	index = -1

	attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
	if err1 != nil {
		err = err1
		return
	}

	family = int(msg.Family)
	index = int(msg.Index)

	var local, dst *net.IPNet
	for _, attr := range attrs {
		switch attr.Attr.Type {
		case syscall.IFA_ADDRESS:
			dst = &net.IPNet{
				IP:   attr.Value,
				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
			}
			addr.Peer = dst
		case syscall.IFA_LOCAL:
			local = &net.IPNet{
				IP:   attr.Value,
				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
			}
			addr.IPNet = local
		case syscall.IFA_LABEL:
			addr.Label = string(attr.Value[:len(attr.Value)-1])
		case IFA_FLAGS:
			addr.Flags = int(native.Uint32(attr.Value[0:4]))
		case nl.IFA_CACHEINFO:
			ci := nl.DeserializeIfaCacheInfo(attr.Value)
			addr.PreferedLft = int(ci.IfaPrefered)
			addr.ValidLft = int(ci.IfaValid)
		}
	}

	// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
	if local != nil {
		addr.IPNet = local
	} else {
		addr.IPNet = dst
	}
	addr.Scope = int(msg.Scope)

	return
}

type AddrUpdate struct {
	LinkAddress net.IPNet
	LinkIndex   int
	Flags       int
	Scope       int
	PreferedLft int
	ValidLft    int
	NewAddr     bool // true=added false=deleted
}

// AddrSubscribe takes a chan down which notifications will be sent
// when addresses change.  Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
	return addrSubscribe(netns.None(), netns.None(), ch, done)
}

// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
	return addrSubscribe(ns, netns.None(), ch, done)
}

func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
	s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
	if err != nil {
		return err
	}
	if done != nil {
		go func() {
			<-done
			s.Close()
		}()
	}
	go func() {
		defer close(ch)
		for {
			msgs, err := s.Receive()
			if err != nil {
				log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
				return
			}
			for _, m := range msgs {
				msgType := m.Header.Type
				if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
					log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
					continue
				}

				addr, _, ifindex, err := parseAddr(m.Data)
				if err != nil {
					log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
					continue
				}

				ch <- AddrUpdate{LinkAddress: *addr.IPNet,
					LinkIndex:   ifindex,
					NewAddr:     msgType == syscall.RTM_NEWADDR,
					Flags:       addr.Flags,
					Scope:       addr.Scope,
					PreferedLft: addr.PreferedLft,
					ValidLft:    addr.ValidLft}
			}
		}
	}()

	return nil
}
<commit_msg>Get broadcast addr in AddrList<commit_after>package netlink

import (
	"fmt"
	"log"
	"net"
	"strings"
	"syscall"

	"github.com/vishvananda/netlink/nl"
	"github.com/vishvananda/netns"
)

// IFA_FLAGS is a u32 attribute.
const IFA_FLAGS = 0x8

// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func AddrAdd(link Link, addr *Addr) error {
	return pkgHandle.AddrAdd(link, addr)
}

// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func AddrReplace(link Link, addr *Addr) error {
	return pkgHandle.AddrReplace(link, addr)
}

// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func AddrDel(link Link, addr *Addr) error {
	return pkgHandle.AddrDel(link, addr)
}

// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) AddrDel(link Link, addr *Addr) error {
	req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
	return h.addrHandle(link, addr, req)
}

func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
	base := link.Attrs()
	if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
		return fmt.Errorf("label must begin with interface name")
	}
	h.ensureIndex(base)

	family := nl.GetIPFamily(addr.IP)

	msg := nl.NewIfAddrmsg(family)
	msg.Index = uint32(base.Index)
	msg.Scope = uint8(addr.Scope)
	prefixlen, _ := addr.Mask.Size()
	msg.Prefixlen = uint8(prefixlen)
	req.AddData(msg)

	var localAddrData []byte
	if family == FAMILY_V4 {
		localAddrData = addr.IP.To4()
	} else {
		localAddrData = addr.IP.To16()
	}

	localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
	req.AddData(localData)
	var peerAddrData []byte
	if addr.Peer != nil {
		if family == FAMILY_V4 {
			peerAddrData = addr.Peer.IP.To4()
		} else {
			peerAddrData = addr.Peer.IP.To16()
		}
	} else {
		peerAddrData = localAddrData
	}

	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
	req.AddData(addressData)

	if addr.Flags != 0 {
		if addr.Flags <= 0xff {
			msg.IfAddrmsg.Flags = uint8(addr.Flags)
		} else {
			b := make([]byte, 4)
			native.PutUint32(b, uint32(addr.Flags))
			flagsData := nl.NewRtAttr(IFA_FLAGS, b)
			req.AddData(flagsData)
		}
	}

	if addr.Broadcast != nil {
		req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
	}

	if addr.Label != "" {
		labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
		req.AddData(labelData)
	}

	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
	return err
}

// AddrList gets a list of IP addresses in the system.
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func AddrList(link Link, family int) ([]Addr, error) {
	return pkgHandle.AddrList(link, family)
}

// AddrList gets a list of IP addresses in the system.
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
	req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
	msg := nl.NewIfInfomsg(family)
	req.AddData(msg)

	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
	if err != nil {
		return nil, err
	}

	indexFilter := 0
	if link != nil {
		base := link.Attrs()
		h.ensureIndex(base)
		indexFilter = base.Index
	}

	var res []Addr
	for _, m := range msgs {
		addr, msgFamily, ifindex, err := parseAddr(m)
		if err != nil {
			return res, err
		}

		if link != nil && ifindex != indexFilter {
			// Ignore messages from other interfaces
			continue
		}

		if family != FAMILY_ALL && msgFamily != family {
			continue
		}

		res = append(res, addr)
	}

	return res, nil
}

func parseAddr(m []byte) (addr Addr, family, index int, err error) {
	msg := nl.DeserializeIfAddrmsg(m)

	family = -1
	index = -1

	attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
	if err1 != nil {
		err = err1
		return
	}

	family = int(msg.Family)
	index = int(msg.Index)

	var local, dst *net.IPNet
	for _, attr := range attrs {
		switch attr.Attr.Type {
		case syscall.IFA_ADDRESS:
			dst = &net.IPNet{
				IP:   attr.Value,
				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
			}
			addr.Peer = dst
		case syscall.IFA_LOCAL:
			local = &net.IPNet{
				IP:   attr.Value,
				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
			}
			addr.IPNet = local
		case syscall.IFA_BROADCAST:
			addr.Broadcast = attr.Value
		case syscall.IFA_LABEL:
			addr.Label = string(attr.Value[:len(attr.Value)-1])
		case IFA_FLAGS:
			addr.Flags = int(native.Uint32(attr.Value[0:4]))
		case nl.IFA_CACHEINFO:
			ci := nl.DeserializeIfaCacheInfo(attr.Value)
			addr.PreferedLft = int(ci.IfaPrefered)
			addr.ValidLft = int(ci.IfaValid)
		}
	}

	// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
	if local != nil {
		addr.IPNet = local
	} else {
		addr.IPNet = dst
	}
	addr.Scope = int(msg.Scope)

	return
}

type AddrUpdate struct {
	LinkAddress net.IPNet
	LinkIndex   int
	Flags       int
	Scope       int
	PreferedLft int
	ValidLft    int
	NewAddr     bool // true=added false=deleted
}

// AddrSubscribe takes a chan down which notifications will be sent
// when addresses change.  Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
	return addrSubscribe(netns.None(), netns.None(), ch, done)
}

// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
	return addrSubscribe(ns, netns.None(), ch, done)
}

func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
	s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
	if err != nil {
		return err
	}
	if done != nil {
		go func() {
			<-done
			s.Close()
		}()
	}
	go func() {
		defer close(ch)
		for {
			msgs, err := s.Receive()
			if err != nil {
				log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
				return
			}
			for _, m := range msgs {
				msgType := m.Header.Type
				if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
					log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
					continue
				}

				addr, _, ifindex, err := parseAddr(m.Data)
				if err != nil {
					log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
					continue
				}

				ch <- AddrUpdate{LinkAddress: *addr.IPNet,
					LinkIndex:   ifindex,
					NewAddr:     msgType == syscall.RTM_NEWADDR,
					Flags:       addr.Flags,
					Scope:       addr.Scope,
					PreferedLft: addr.PreferedLft,
					ValidLft:    addr.ValidLft}
			}
		}
	}()

	return nil
}
<|endoftext|>


<commit_before>package reply

import (
	"regexp"
	"math/rand"
	"time"

	"github.com/tucnak/telebot"
	"github.com/asdine/storm"

	"github.com/focusshifter/muxgoob/registry"
)

type ReplyPlugin struct {
}

var db *storm.DB
var rng *rand.Rand

func init() {
	registry.RegisterPlugin(&ReplyPlugin{})
}

func (p *ReplyPlugin) Start(sharedDb *storm.DB) {
	db = sharedDb
	rng = rand.New(rand.NewSource(time.Now().UnixNano()))
}

func (p *ReplyPlugin) Process(message telebot.Message) {
	bot := registry.Bot

	techExp := regexp.MustCompile(`(?i)^\!ттх$`)
	questionExp := regexp.MustCompile(`(?i)^.*(gooby|губи|губ(я)+н).*\?$`)
	// highlightedExp := regexp.MustCompile(`(?i)^.*(gooby|губи|губ(я)+н).*$`)

	switch {
		case techExp.MatchString(message.Text):
			bot.SendMessage(message.Chat,
						"ТТХ: " + registry.Config.ReplyTechLink,
						&telebot.SendOptions{DisableWebPagePreview: true, DisableNotification: true})

		case questionExp.MatchString(message.Text):
			var replyText string

			rngInt := rng.Int()

			switch {
				case rngInt % 100 == 0:
					replyText = "Заткнись, пидор"
				case rngInt % 2 == 0:
					replyText = "Да"
				default:
					replyText = "Нет"
			}

			bot.SendMessage(message.Chat, replyText, &telebot.SendOptions{ReplyTo: message})

		// case highlightedExp.MatchString(message.Text):
		// 	bot.SendMessage(message.Chat, "herp derp", nil)
	}
}
<commit_msg>Add dotka response to bot replies plugin<commit_after>package reply

import (
	"regexp"
	"math/rand"
	"time"

	"github.com/tucnak/telebot"
	"github.com/asdine/storm"

	"github.com/focusshifter/muxgoob/registry"
)

type ReplyPlugin struct {
}

var db *storm.DB
var rng *rand.Rand

func init() {
	registry.RegisterPlugin(&ReplyPlugin{})
}

func (p *ReplyPlugin) Start(sharedDb *storm.DB) {
	db = sharedDb
	rng = rand.New(rand.NewSource(time.Now().UnixNano()))
}

func (p *ReplyPlugin) Process(message telebot.Message) {
	bot := registry.Bot
	rngInt := rng.Int()
	var replyText string

	techExp := regexp.MustCompile(`(?i)^\!ттх$`)
	questionExp := regexp.MustCompile(`(?i)^.*(gooby|губи|губ(я)+н).*\?$`)
	dotkaExp := regexp.MustCompile(`(?i)^.*(dota|дота|дот((ец)|(к)+(а|у))).*$`)
	// highlightedExp := regexp.MustCompile(`(?i)^.*(gooby|губи|губ(я)+н).*$`)

	switch {
		case techExp.MatchString(message.Text):
			bot.SendMessage(message.Chat,
						"ТТХ: " + registry.Config.ReplyTechLink,
						&telebot.SendOptions{DisableWebPagePreview: true, DisableNotification: true})

		case questionExp.MatchString(message.Text):
			switch {
				case rngInt % 100 == 0:
					replyText = "Заткнись, пидор"
				case rngInt % 2 == 0:
					replyText = "Да"
				default:
					replyText = "Нет"
			}

			bot.SendMessage(message.Chat, replyText, &telebot.SendOptions{ReplyTo: message})

		case dotkaExp.MatchString(message.Text):
			switch {
				case rngInt % 100 == 0:
					replyText = "Щяб в дотку с Сашкой!"
				case rngInt % 2 == 0:
					replyText = "Щяб в дотку. Как в старые добрые времена."
				default:
					replyText = "Щяб в дотку!"
			}

			bot.SendMessage(message.Chat, replyText)

		// case highlightedExp.MatchString(message.Text):
		// 	bot.SendMessage(message.Chat, "herp derp", nil)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/urfave/cli"
)

func getNamesFromArguments(context *cli.Context) []string {
	names := context.Args()

	if context.String("names-file") != "" {
		namesFile, _ := os.Open(context.String("names-file"))
		names = append(names, ParseNamesFile(namesFile)...)
	}
	return names
}

// ParseNamesFile reads a file containing one name of a gitignore patterns file per line
func ParseNamesFile(namesFile io.Reader) []string {
	var a []string
	scanner := bufio.NewScanner(namesFile)
	for scanner.Scan() {
		name := strings.TrimSpace(scanner.Text())
		if len(name) > 0 {
			a = append(a, name)
		}
	}
	return a
}

// CreateNamesOrdering creates a mapping of each name to its respective input position
func CreateNamesOrdering(names []string) map[string]int {
	namesOrdering := make(map[string]int)
	for i, name := range names {
		namesOrdering[name] = i
	}
	return namesOrdering
}

// HTTPIgnoreGetter provides an implementation to retrieve gitignore patterns from
// files available over HTTP
type HTTPIgnoreGetter struct {
	baseURL          string
	defaultExtension string
}

// RetrievedContents represents the result of retrieving contents of a gitignore patterns
// file
type RetrievedContents struct {
	namedSource NamedSource
	contents    string
	err         error
}

// NamedSource represents a source containing gitignore patterns, along with a given name
type NamedSource struct {
	name   string
	source string
}

// GetIgnoreFiles retrieves gitignore patterns files via HTTP and sends their contents
// over a channel. It registers each request made with a WaitGroup instance, so the
// responses can be awaited.
func (getter *HTTPIgnoreGetter) GetIgnoreFiles(names []string, contentsChannel chan RetrievedContents, requestsPending *sync.WaitGroup) {
	namedURLs := getter.NamesToUrls(names)
	for _, namedURL := range namedURLs {
		requestsPending.Add(1)
		log.Println("Retrieving", namedURL.source)
		go downloadIgnoreFile(namedURL, contentsChannel, requestsPending)
	}
}

// NamesToUrls converts names of gitignore files to URLs
func (getter *HTTPIgnoreGetter) NamesToUrls(names []string) []NamedSource {
	urls := make([]NamedSource, len(names))
	for i, name := range names {
		urls[i] = getter.nameToURL(name)
	}
	return urls
}

func (getter *HTTPIgnoreGetter) nameToURL(name string) NamedSource {
	nameWithExtension := getter.getNameWithExtension(name)
	url := getter.baseURL + "/" + nameWithExtension
	return NamedSource{name, url}
}

func (getter *HTTPIgnoreGetter) getNameWithExtension(name string) string {
	if filepath.Ext(name) == "" {
		name = name + getter.defaultExtension
	}
	return name
}

// FailedSource represents a source unable to be retrieved or processed
type FailedSource struct {
	source string
	err    error
}

func (fs *FailedSource) Error() string {
	return fmt.Sprintf("%s %s", fs.source, fs.err.Error())
}

func downloadIgnoreFile(namedURL NamedSource, contentsChannel chan RetrievedContents, requestsPending *sync.WaitGroup) {
	defer requestsPending.Done()
	var fc RetrievedContents
	url := namedURL.source
	response, err := http.Get(url)
	if err != nil {
		fc = RetrievedContents{namedURL, "", err}
	} else if response.StatusCode != 200 {
		fc = RetrievedContents{namedURL, "", fmt.Errorf("Got status code %d", response.StatusCode)}
	} else {
		defer response.Body.Close()
		content, err := getContent(response.Body)
		if err != nil {
			fc = RetrievedContents{namedURL, "", fmt.Errorf("Error reading response body: %s", err.Error())}
		} else {
			fc = RetrievedContents{namedURL, content, nil}
		}
	}
	contentsChannel <- fc
}

func getContent(body io.ReadCloser) (content string, err error) {
	scanner := bufio.NewScanner(body)
	for scanner.Scan() {
		content = content + fmt.Sprintln(scanner.Text())
	}
	err = scanner.Err()
	return content, err
}

// FailedSources represents a collection of FailedSource instances
type FailedSources struct {
	sources []*FailedSource
}

// Add adds a FailedSource instance to the FailedSources collection
func (failedSources *FailedSources) Add(failedSource *FailedSource) {
	failedSources.sources = append(failedSources.sources, failedSource)
}

func (failedSources *FailedSources) Error() string {
	sourceErrors := make([]string, len(failedSources.sources))
	for i, failedSource := range failedSources.sources {
		sourceErrors[i] = failedSource.Error()
	}
	stringOfErrors := strings.Join(sourceErrors, "\n")
	return "Errors for the following URLs:\n" + stringOfErrors
}

// NamedIgnoreContents represents the contents (patterns and comments) of a
// gitignore file
type NamedIgnoreContents struct {
	name     string
	contents string
}

// DisplayName returns the decorated name, suitable for a section header in a
// gitignore file
func (nic *NamedIgnoreContents) DisplayName() string {
	baseName := filepath.Base(nic.name)
	return strings.TrimSuffix(baseName, filepath.Ext(baseName))
}

func processContents(contentsChannel chan RetrievedContents, namesOrdering map[string]int) ([]NamedIgnoreContents, error) {
	allRetrievedContents := make([]NamedIgnoreContents, len(namesOrdering))
	var err error
	failedSources := new(FailedSources)
	for retrievedContents := range contentsChannel {
		if retrievedContents.err != nil {
			failedSource := &FailedSource{retrievedContents.namedSource.source, retrievedContents.err}
			failedSources.Add(failedSource)
		} else {
			name := retrievedContents.namedSource.name
			position, present := namesOrdering[name]
			if !present {
				return allRetrievedContents, fmt.Errorf("Could not find name %s in ordering", name)
			}
			allRetrievedContents[position] = NamedIgnoreContents{name, retrievedContents.contents}
		}
	}
	if len(failedSources.sources) > 0 {
		err = failedSources
	}
	return allRetrievedContents, err
}

func getOutputFile(context *cli.Context) (outputFilePath string, outputFile io.Writer, err error) {
	outputFilePath = context.String("o")
	if outputFilePath == "" {
		outputFilePath = "STDOUT"
		outputFile = os.Stdout
	} else {
		outputFile, err = os.Create(outputFilePath)
	}
	return
}

func writeIgnoreFile(ignoreFile io.Writer, contents []NamedIgnoreContents) (err error) {
	writer := bufio.NewWriter(ignoreFile)
	for i, nc := range contents {
		if i > 0 {
			writer.WriteString("\n\n")
		}
		writer.WriteString(decorateName(nc.DisplayName()))
		writer.WriteString(nc.contents)
	}
	if writer.Flush() != nil {
		err = writer.Flush()
	}
	return
}

func decorateName(name string) string {
	nameLength := len(name)
	fullHashLine := strings.Repeat("#", nameLength+4)
	nameLine := fmt.Sprintf("# %s #", name)
	decoratedName := strings.Join([]string{fullHashLine, nameLine, fullHashLine, ""}, "\n")
	return decoratedName
}

func creatCLI() *cli.App {
	app := cli.NewApp()
	app.Name = "getignore"
	app.Version = "0.2.0.dev"
	app.Usage = "Bootstraps gitignore files from central sources"

	app.Commands = []cli.Command{
		cli.Command{
			Name:  "get",
			Usage: "Retrieves gitignore patterns files from a central source and concatenates them",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "base-url, u",
					Usage: "The URL under which gitignore files can be found",
					Value: "https://raw.githubusercontent.com/github/gitignore/master",
				},
				cli.StringFlag{
					Name:  "default-extension, e",
					Usage: "The default file extension appended to names when retrieving them",
					Value: ".gitignore",
				},
				cli.IntFlag{
					Name:  "max-connections",
					Usage: "The number of maximum connections to open for HTTP requests",
					Value: 8,
				},
				cli.StringFlag{
					Name:  "names-file, n",
					Usage: "Path to file containing names of gitignore patterns files",
				},
				cli.StringFlag{
					Name:  "o",
					Usage: "Path to output file (default: STDOUT)",
				},
			},
			ArgsUsage: "[gitignore_name] [gitignore_name …]",
			Action:    downloadAllIgnoreFiles,
		},
	}

	return app
}

func downloadAllIgnoreFiles(context *cli.Context) error {
	names := getNamesFromArguments(context)
	namesOrdering := CreateNamesOrdering(names)
	getter := HTTPIgnoreGetter{context.String("base-url"), context.String("default-extension")}
	contentsChannel := make(chan RetrievedContents, context.Int("max-connections"))
	var requestsPending sync.WaitGroup
	getter.GetIgnoreFiles(names, contentsChannel, &requestsPending)
	requestsPending.Wait()
	close(contentsChannel)
	contents, err := processContents(contentsChannel, namesOrdering)
	if err != nil {
		return err
	}
	outputFilePath, outputFile, err := getOutputFile(context)
	if err != nil {
		return err
	}
	log.Println("Writing contents to", outputFilePath)
	err = writeIgnoreFile(outputFile, contents)
	if err != nil {
		return err
	}
	log.Print("Finished")
	return err
}

func main() {
	log.SetFlags(0)
	app := creatCLI()
	app.RunAndExitOnError()
}
<commit_msg>Remove superfluous log statement<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/urfave/cli"
)

func getNamesFromArguments(context *cli.Context) []string {
	names := context.Args()

	if context.String("names-file") != "" {
		namesFile, _ := os.Open(context.String("names-file"))
		names = append(names, ParseNamesFile(namesFile)...)
	}
	return names
}

// ParseNamesFile reads a file containing one name of a gitignore patterns file per line
func ParseNamesFile(namesFile io.Reader) []string {
	var a []string
	scanner := bufio.NewScanner(namesFile)
	for scanner.Scan() {
		name := strings.TrimSpace(scanner.Text())
		if len(name) > 0 {
			a = append(a, name)
		}
	}
	return a
}

// CreateNamesOrdering creates a mapping of each name to its respective input position
func CreateNamesOrdering(names []string) map[string]int {
	namesOrdering := make(map[string]int)
	for i, name := range names {
		namesOrdering[name] = i
	}
	return namesOrdering
}

// HTTPIgnoreGetter provides an implementation to retrieve gitignore patterns from
// files available over HTTP
type HTTPIgnoreGetter struct {
	baseURL          string
	defaultExtension string
}

// RetrievedContents represents the result of retrieving contents of a gitignore patterns
// file
type RetrievedContents struct {
	namedSource NamedSource
	contents    string
	err         error
}

// NamedSource represents a source containing gitignore patterns, along with a given name
type NamedSource struct {
	name   string
	source string
}

// GetIgnoreFiles retrieves gitignore patterns files via HTTP and sends their contents
// over a channel. It registers each request made with a WaitGroup instance, so the
// responses can be awaited.
func (getter *HTTPIgnoreGetter) GetIgnoreFiles(names []string, contentsChannel chan RetrievedContents, requestsPending *sync.WaitGroup) {
	namedURLs := getter.NamesToUrls(names)
	for _, namedURL := range namedURLs {
		requestsPending.Add(1)
		log.Println("Retrieving", namedURL.source)
		go downloadIgnoreFile(namedURL, contentsChannel, requestsPending)
	}
}

// NamesToUrls converts names of gitignore files to URLs
func (getter *HTTPIgnoreGetter) NamesToUrls(names []string) []NamedSource {
	urls := make([]NamedSource, len(names))
	for i, name := range names {
		urls[i] = getter.nameToURL(name)
	}
	return urls
}

func (getter *HTTPIgnoreGetter) nameToURL(name string) NamedSource {
	nameWithExtension := getter.getNameWithExtension(name)
	url := getter.baseURL + "/" + nameWithExtension
	return NamedSource{name, url}
}

func (getter *HTTPIgnoreGetter) getNameWithExtension(name string) string {
	if filepath.Ext(name) == "" {
		name = name + getter.defaultExtension
	}
	return name
}

// FailedSource represents a source unable to be retrieved or processed
type FailedSource struct {
	source string
	err    error
}

func (fs *FailedSource) Error() string {
	return fmt.Sprintf("%s %s", fs.source, fs.err.Error())
}

func downloadIgnoreFile(namedURL NamedSource, contentsChannel chan RetrievedContents, requestsPending *sync.WaitGroup) {
	defer requestsPending.Done()
	var fc RetrievedContents
	url := namedURL.source
	response, err := http.Get(url)
	if err != nil {
		fc = RetrievedContents{namedURL, "", err}
	} else if response.StatusCode != 200 {
		fc = RetrievedContents{namedURL, "", fmt.Errorf("Got status code %d", response.StatusCode)}
	} else {
		defer response.Body.Close()
		content, err := getContent(response.Body)
		if err != nil {
			fc = RetrievedContents{namedURL, "", fmt.Errorf("Error reading response body: %s", err.Error())}
		} else {
			fc = RetrievedContents{namedURL, content, nil}
		}
	}
	contentsChannel <- fc
}

func getContent(body io.ReadCloser) (content string, err error) {
	scanner := bufio.NewScanner(body)
	for scanner.Scan() {
		content = content + fmt.Sprintln(scanner.Text())
	}
	err = scanner.Err()
	return content, err
}

// FailedSources represents a collection of FailedSource instances
type FailedSources struct {
	sources []*FailedSource
}

// Add adds a FailedSource instance to the FailedSources collection
func (failedSources *FailedSources) Add(failedSource *FailedSource) {
	failedSources.sources = append(failedSources.sources, failedSource)
}

func (failedSources *FailedSources) Error() string {
	sourceErrors := make([]string, len(failedSources.sources))
	for i, failedSource := range failedSources.sources {
		sourceErrors[i] = failedSource.Error()
	}
	stringOfErrors := strings.Join(sourceErrors, "\n")
	return "Errors for the following URLs:\n" + stringOfErrors
}

// NamedIgnoreContents represents the contents (patterns and comments) of a
// gitignore file
type NamedIgnoreContents struct {
	name     string
	contents string
}

// DisplayName returns the decorated name, suitable for a section header in a
// gitignore file
func (nic *NamedIgnoreContents) DisplayName() string {
	baseName := filepath.Base(nic.name)
	return strings.TrimSuffix(baseName, filepath.Ext(baseName))
}

func processContents(contentsChannel chan RetrievedContents, namesOrdering map[string]int) ([]NamedIgnoreContents, error) {
	allRetrievedContents := make([]NamedIgnoreContents, len(namesOrdering))
	var err error
	failedSources := new(FailedSources)
	for retrievedContents := range contentsChannel {
		if retrievedContents.err != nil {
			failedSource := &FailedSource{retrievedContents.namedSource.source, retrievedContents.err}
			failedSources.Add(failedSource)
		} else {
			name := retrievedContents.namedSource.name
			position, present := namesOrdering[name]
			if !present {
				return allRetrievedContents, fmt.Errorf("Could not find name %s in ordering", name)
			}
			allRetrievedContents[position] = NamedIgnoreContents{name, retrievedContents.contents}
		}
	}
	if len(failedSources.sources) > 0 {
		err = failedSources
	}
	return allRetrievedContents, err
}

func getOutputFile(context *cli.Context) (outputFilePath string, outputFile io.Writer, err error) {
	outputFilePath = context.String("o")
	if outputFilePath == "" {
		outputFilePath = "STDOUT"
		outputFile = os.Stdout
	} else {
		outputFile, err = os.Create(outputFilePath)
	}
	return
}

func writeIgnoreFile(ignoreFile io.Writer, contents []NamedIgnoreContents) (err error) {
	writer := bufio.NewWriter(ignoreFile)
	for i, nc := range contents {
		if i > 0 {
			writer.WriteString("\n\n")
		}
		writer.WriteString(decorateName(nc.DisplayName()))
		writer.WriteString(nc.contents)
	}
	if writer.Flush() != nil {
		err = writer.Flush()
	}
	return
}

func decorateName(name string) string {
	nameLength := len(name)
	fullHashLine := strings.Repeat("#", nameLength+4)
	nameLine := fmt.Sprintf("# %s #", name)
	decoratedName := strings.Join([]string{fullHashLine, nameLine, fullHashLine, ""}, "\n")
	return decoratedName
}

func creatCLI() *cli.App {
	app := cli.NewApp()
	app.Name = "getignore"
	app.Version = "0.2.0.dev"
	app.Usage = "Bootstraps gitignore files from central sources"

	app.Commands = []cli.Command{
		cli.Command{
			Name:  "get",
			Usage: "Retrieves gitignore patterns files from a central source and concatenates them",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "base-url, u",
					Usage: "The URL under which gitignore files can be found",
					Value: "https://raw.githubusercontent.com/github/gitignore/master",
				},
				cli.StringFlag{
					Name:  "default-extension, e",
					Usage: "The default file extension appended to names when retrieving them",
					Value: ".gitignore",
				},
				cli.IntFlag{
					Name:  "max-connections",
					Usage: "The number of maximum connections to open for HTTP requests",
					Value: 8,
				},
				cli.StringFlag{
					Name:  "names-file, n",
					Usage: "Path to file containing names of gitignore patterns files",
				},
				cli.StringFlag{
					Name:  "o",
					Usage: "Path to output file (default: STDOUT)",
				},
			},
			ArgsUsage: "[gitignore_name] [gitignore_name …]",
			Action:    downloadAllIgnoreFiles,
		},
	}

	return app
}

func downloadAllIgnoreFiles(context *cli.Context) error {
	names := getNamesFromArguments(context)
	namesOrdering := CreateNamesOrdering(names)
	getter := HTTPIgnoreGetter{context.String("base-url"), context.String("default-extension")}
	contentsChannel := make(chan RetrievedContents, context.Int("max-connections"))
	var requestsPending sync.WaitGroup
	getter.GetIgnoreFiles(names, contentsChannel, &requestsPending)
	requestsPending.Wait()
	close(contentsChannel)
	contents, err := processContents(contentsChannel, namesOrdering)
	if err != nil {
		return err
	}
	outputFilePath, outputFile, err := getOutputFile(context)
	if err != nil {
		return err
	}
	log.Println("Writing contents to", outputFilePath)
	err = writeIgnoreFile(outputFile, contents)
	if err != nil {
		return err
	}
	return err
}

func main() {
	log.SetFlags(0)
	app := creatCLI()
	app.RunAndExitOnError()
}
<|endoftext|>


<commit_before>package formatters

import (
	"reflect"
	"testing"
	"time"

	"github.com/openconfig/gnmi/proto/gnmi"
)

type item struct {
	ev *EventMsg
	m  map[string]interface{}
}

var eventMsgtestSet = map[string][]item{
	"nil": {
		{
			ev: nil,
			m:  nil,
		},
		{
			ev: new(EventMsg),
			m:  make(map[string]interface{}),
		},
	},
	"filled": {
		{
			ev: &EventMsg{
				Timestamp: 100,
				Values:    map[string]interface{}{"value1": int64(1)},
				Tags:      map[string]string{"tag1": "1"},
			},
			m: map[string]interface{}{
				"timestamp": int64(100),
				"values": map[string]interface{}{
					"value1": int64(1),
				},
				"tags": map[string]interface{}{
					"tag1": "1",
				},
			},
		},
		{
			ev: &EventMsg{
				Name:      "sub1",
				Timestamp: 100,
				Tags: map[string]string{
					"tag1": "1",
					"tag2": "1",
				},
			},
			m: map[string]interface{}{
				"name":      "sub1",
				"timestamp": int64(100),
				"tags": map[string]interface{}{
					"tag1": "1",
					"tag2": "1",
				},
			},
		},
		{
			ev: &EventMsg{
				Name:      "sub1",
				Timestamp: 100,
				Values: map[string]interface{}{
					"value1": int64(1),
					"value2": int64(1),
				},
				Tags: map[string]string{
					"tag1": "1",
					"tag2": "1",
				},
			},
			m: map[string]interface{}{
				"name":      "sub1",
				"timestamp": int64(100),
				"values": map[string]interface{}{
					"value1": int64(1),
					"value2": int64(1),
				},
				"tags": map[string]interface{}{
					"tag1": "1",
					"tag2": "1",
				},
			},
		},
	},
}

func TestToMap(t *testing.T) {
	for name, items := range eventMsgtestSet {
		for i, item := range items {
			t.Run(name, func(t *testing.T) {
				t.Logf("running test item %d", i)
				out := item.ev.ToMap()
				if !reflect.DeepEqual(out, item.m) {
					t.Logf("failed at %q item %d", name, i)
					t.Logf("expected: (%T)%+v", item.m, item.m)
					t.Logf("     got: (%T)%+v", out, out)
					t.Fail()
				}
			})
		}
	}
}

func TestFromMap(t *testing.T) {
	for name, items := range eventMsgtestSet {
		for i, item := range items {
			t.Run(name, func(t *testing.T) {
				t.Logf("running test item %d", i)
				out, err := EventFromMap(item.m)
				if err != nil {
					t.Logf("failed at %q: %v", name, err)
					t.Fail()
				}
				if !reflect.DeepEqual(out, item.ev) {
					t.Logf("failed at %q item %d", name, i)
					t.Logf("expected: (%T)%+v", item.m, item.m)
					t.Logf("     got: (%T)%+v", out, out)
					t.Fail()
				}
			})
		}
	}
}

var jsonData = `
{
    "admin-state": "enable",
    "ipv4": {
        "primary": {
            "address": "1.1.1.1",
            "prefix-length": 32
        }
    }
}
`
var value = &gnmi.TypedValue{
	Value: &gnmi.TypedValue_JsonVal{
		JsonVal: []byte(jsonData),
	},
}

func TestGetValueFlat(t *testing.T) {
	v, err := getValueFlat("/configure/router[router-name=Base]/interface[interface-name=int1]", value)
	if err != nil {
		t.Error(err)
	}
	//fmt.Printf("%+v\n", v)
	t.Logf("%v", v)
}

func TestResponseToEventMsgs(t *testing.T) {
	rsp := &gnmi.SubscribeResponse{
		Response: &gnmi.SubscribeResponse_Update{
			Update: &gnmi.Notification{
				Timestamp: time.Now().UnixNano(),
				Prefix: &gnmi.Path{
					Elem: []*gnmi.PathElem{
						{Name: "a"},
					},
				},
				Update: []*gnmi.Update{
					{
						Path: &gnmi.Path{
							Elem: []*gnmi.PathElem{
								{Name: "b",
									Key: map[string]string{
										"k1": "v1",
									},
								},
								{Name: "c",
									Key: map[string]string{
										"k2": "v2",
									}},
							},
						},
						Val: &gnmi.TypedValue{
							Value: &gnmi.TypedValue_StringVal{
								StringVal: "value",
							},
						},
					},
				},
			},
		},
	}
	evs, err := ResponseToEventMsgs("subname", rsp, map[string]string{"k1": "v0"})
	if err != nil {
		t.Error(err)
	}
	t.Logf("%v", evs)
	//b, _ := json.MarshalIndent(evs, "", "  ")
	//fmt.Println(string(b))
}
<commit_msg>add extra tests<commit_after>package formatters

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/openconfig/gnmi/proto/gnmi"
)

type item struct {
	ev *EventMsg
	m  map[string]interface{}
}

var eventMsgtestSet = map[string][]item{
	"nil": {
		{
			ev: nil,
			m:  nil,
		},
		{
			ev: new(EventMsg),
			m:  make(map[string]interface{}),
		},
	},
	"filled": {
		{
			ev: &EventMsg{
				Timestamp: 100,
				Values:    map[string]interface{}{"value1": int64(1)},
				Tags:      map[string]string{"tag1": "1"},
			},
			m: map[string]interface{}{
				"timestamp": int64(100),
				"values": map[string]interface{}{
					"value1": int64(1),
				},
				"tags": map[string]interface{}{
					"tag1": "1",
				},
			},
		},
		{
			ev: &EventMsg{
				Name:      "sub1",
				Timestamp: 100,
				Tags: map[string]string{
					"tag1": "1",
					"tag2": "1",
				},
			},
			m: map[string]interface{}{
				"name":      "sub1",
				"timestamp": int64(100),
				"tags": map[string]interface{}{
					"tag1": "1",
					"tag2": "1",
				},
			},
		},
		{
			ev: &EventMsg{
				Name:      "sub1",
				Timestamp: 100,
				Values: map[string]interface{}{
					"value1": int64(1),
					"value2": int64(1),
				},
				Tags: map[string]string{
					"tag1": "1",
					"tag2": "1",
				},
			},
			m: map[string]interface{}{
				"name":      "sub1",
				"timestamp": int64(100),
				"values": map[string]interface{}{
					"value1": int64(1),
					"value2": int64(1),
				},
				"tags": map[string]interface{}{
					"tag1": "1",
					"tag2": "1",
				},
			},
		},
	},
}

func TestToMap(t *testing.T) {
	for name, items := range eventMsgtestSet {
		for i, item := range items {
			t.Run(name, func(t *testing.T) {
				t.Logf("running test item %d", i)
				out := item.ev.ToMap()
				if !reflect.DeepEqual(out, item.m) {
					t.Logf("failed at %q item %d", name, i)
					t.Logf("expected: (%T)%+v", item.m, item.m)
					t.Logf("     got: (%T)%+v", out, out)
					t.Fail()
				}
			})
		}
	}
}

func TestFromMap(t *testing.T) {
	for name, items := range eventMsgtestSet {
		for i, item := range items {
			t.Run(name, func(t *testing.T) {
				t.Logf("running test item %d", i)
				out, err := EventFromMap(item.m)
				if err != nil {
					t.Logf("failed at %q: %v", name, err)
					t.Fail()
				}
				if !reflect.DeepEqual(out, item.ev) {
					t.Logf("failed at %q item %d", name, i)
					t.Logf("expected: (%T)%+v", item.m, item.m)
					t.Logf("     got: (%T)%+v", out, out)
					t.Fail()
				}
			})
		}
	}
}

func TestResponseToEventMsgs(t *testing.T) {
	rsp := &gnmi.SubscribeResponse{
		Response: &gnmi.SubscribeResponse_Update{
			Update: &gnmi.Notification{
				Timestamp: time.Now().UnixNano(),
				Prefix: &gnmi.Path{
					Elem: []*gnmi.PathElem{
						{Name: "a"},
					},
				},
				Update: []*gnmi.Update{
					{
						Path: &gnmi.Path{
							Elem: []*gnmi.PathElem{
								{Name: "b",
									Key: map[string]string{
										"k1": "v1",
									},
								},
								{Name: "c",
									Key: map[string]string{
										"k2": "v2",
									}},
							},
						},
						Val: &gnmi.TypedValue{
							Value: &gnmi.TypedValue_StringVal{
								StringVal: "value",
							},
						},
					},
				},
			},
		},
	}
	evs, err := ResponseToEventMsgs("subname", rsp, map[string]string{"k1": "v0"})
	if err != nil {
		t.Error(err)
	}
	t.Logf("%v", evs)
}

func TestTagsFromGNMIPath(t *testing.T) {
	type args struct {
		p *gnmi.Path
	}
	tests := []struct {
		name  string
		args  args
		want  string
		want1 map[string]string
	}{
		{
			name:  "nil",
			args:  args{p: nil},
			want:  "",
			want1: nil,
		},
		{
			name: "path_no_keys",
			args: args{p: &gnmi.Path{
				Elem: []*gnmi.PathElem{
					{
						Name: "interface",
					},
					{
						Name: "statistics",
					},
				},
			}},
			want:  "/interface/statistics",
			want1: make(map[string]string),
		},
		{
			name: "path_with_keys",
			args: args{p: &gnmi.Path{
				Elem: []*gnmi.PathElem{
					{
						Name: "interface",
						Key: map[string]string{
							"name": "ethernet-1/1",
						},
					},
					{
						Name: "statistics",
					},
				},
			}},
			want: "/interface/statistics",
			want1: map[string]string{
				"interface_name": "ethernet-1/1",
			},
		},
		{
			name: "path_with_multiple_keys",
			args: args{p: &gnmi.Path{
				Elem: []*gnmi.PathElem{
					{
						Name: "elem1",
						Key: map[string]string{
							"bar": "bar_val",
							"foo": "foo_val",
						},
					},
					{
						Name: "elem2",
					},
				},
			}},
			want: "/elem1/elem2",
			want1: map[string]string{
				"elem1_bar": "bar_val",
				"elem1_foo": "foo_val",
			},
		},
		{
			name: "path_with_multiple_keys_and_target",
			args: args{p: &gnmi.Path{
				Target: "target1",
				Elem: []*gnmi.PathElem{
					{
						Name: "elem1",
						Key: map[string]string{
							"bar": "bar_val",
							"foo": "foo_val",
						},
					},
					{
						Name: "elem2",
					},
				},
			}},
			want: "/elem1/elem2",
			want1: map[string]string{
				"elem1_bar": "bar_val",
				"elem1_foo": "foo_val",
				"target":    "target1",
			},
		},
		{
			name: "path_with_multiple_keys_target_and_origin",
			args: args{p: &gnmi.Path{
				Origin: "origin1",
				Target: "target1",
				Elem: []*gnmi.PathElem{
					{
						Name: "elem1",
						Key: map[string]string{
							"bar": "bar_val",
							"foo": "foo_val",
						},
					},
					{
						Name: "elem2",
					},
				},
			}},
			want: "origin1:/elem1/elem2",
			want1: map[string]string{
				"elem1_bar": "bar_val",
				"elem1_foo": "foo_val",
				"target":    "target1",
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, got1 := TagsFromGNMIPath(tt.args.p)
			if got != tt.want {
				t.Errorf("TagsFromGNMIPath() got = %v, want %v", got, tt.want)
			}
			if !cmp.Equal(got1, tt.want1) {
				t.Errorf("TagsFromGNMIPath() got1 = %v, want %v", got1, tt.want1)
			}
		})
	}
}

func Test_getValueFlat(t *testing.T) {
	type args struct {
		prefix   string
		updValue *gnmi.TypedValue
	}
	tests := []struct {
		name    string
		args    args
		want    map[string]interface{}
		wantErr bool
	}{
		{
			name: "simple_json_value",
			args: args{
				prefix: "/configure/router/interface",
				updValue: &gnmi.TypedValue{
					Value: &gnmi.TypedValue_JsonVal{
						JsonVal: []byte(`{
							"admin-state": "enable",
							"ipv4": {
								"primary": {
									"address": "1.1.1.1",
									"prefix-length": 32
								}
							}
						}`),
					},
				},
			},
			want: map[string]interface{}{
				"/configure/router/interface/admin-state":                "enable",
				"/configure/router/interface/ipv4/primary/address":       "1.1.1.1",
				"/configure/router/interface/ipv4/primary/prefix-length": float64(32),
			},
			wantErr: false,
		},
		{
			name: "json_value_with_list",
			args: args{
				prefix: "/network-instance",
				updValue: &gnmi.TypedValue{
					Value: &gnmi.TypedValue_JsonVal{
						JsonVal: []byte(`{
							"interface": [
								"ethernet-1/1",
								"ethernet-1/2",
								"ethernet-1/3",
								"ethernet-1/4"
							]
						}`),
					},
				},
			},
			want: map[string]interface{}{
				"/network-instance/interface.0": "ethernet-1/1",
				"/network-instance/interface.1": "ethernet-1/2",
				"/network-instance/interface.2": "ethernet-1/3",
				"/network-instance/interface.3": "ethernet-1/4",
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := getValueFlat(tt.args.prefix, tt.args.updValue)
			if (err != nil) != tt.wantErr {
				t.Errorf("getValueFlat() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !cmp.Equal(got, tt.want) {
				for k, v := range got {
					fmt.Printf("%s: %v: %T\n", k, v, v)
				}
				t.Errorf("got:  %+v", got)
				t.Errorf("want: %+v", tt.want)
				t.Errorf("getValueFlat() = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>package jira

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
)

func TestFilterService_GetList(t *testing.T) {
	setup()
	defer teardown()
	testAPIEdpoint := "/rest/api/2/filter"
	raw, err := ioutil.ReadFile("./mocks/all_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEdpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEdpoint)
		fmt.Fprint(writer, string(raw))
	})

	filters, _, err := testClient.Filter.GetList()
	if filters == nil {
		t.Error("Expected Filters list. Filters list is nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
}

func TestFilterService_Get(t *testing.T) {
	setup()
	defer teardown()
	testAPIEdpoint := "/rest/api/2/filter/10000"
	raw, err := ioutil.ReadFile("./mocks/filter.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEdpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEdpoint)
		fmt.Fprintf(writer, string(raw))
	})

	filter, _, err := testClient.Filter.Get(10000)
	if filter == nil {
		t.Errorf("Expected Filter, got nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}

}

func TestFilterService_GetFavouriteList(t *testing.T) {
	setup()
	defer teardown()
	testAPIEdpoint := "/rest/api/2/filter/favourite"
	raw, err := ioutil.ReadFile("./mocks/favourite_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEdpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEdpoint)
		fmt.Fprint(writer, string(raw))
	})

	filters, _, err := testClient.Filter.GetFavouriteList()
	if filters == nil {
		t.Error("Expected Filters list. Filters list is nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
}

func TestFilterService_GetMyFilters(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/3/filter/my"
	raw, err := ioutil.ReadFile("./mocks/my_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	opts := GetMyFiltersQueryOptions{}
	filters, _, err := testClient.Filter.GetMyFilters(&opts)
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
	if filters == nil {
		t.Errorf("Expected Filters, got nil")
	}
}

func TestFilterService_Search(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/3/filter/search"
	raw, err := ioutil.ReadFile("./mocks/search_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	opt := FilterSearchOptions{}
	filters, _, err := testClient.Filter.Search(&opt)
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
	if filters == nil {
		t.Errorf("Expected Filters, got nil")
	}
}
<commit_msg>fix: Fix typos in filter_test.go<commit_after>package jira

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
)

func TestFilterService_GetList(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/2/filter"
	raw, err := ioutil.ReadFile("./mocks/all_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	filters, _, err := testClient.Filter.GetList()
	if filters == nil {
		t.Error("Expected Filters list. Filters list is nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
}

func TestFilterService_Get(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/2/filter/10000"
	raw, err := ioutil.ReadFile("./mocks/filter.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprintf(writer, string(raw))
	})

	filter, _, err := testClient.Filter.Get(10000)
	if filter == nil {
		t.Errorf("Expected Filter, got nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}

}

func TestFilterService_GetFavouriteList(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/2/filter/favourite"
	raw, err := ioutil.ReadFile("./mocks/favourite_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	filters, _, err := testClient.Filter.GetFavouriteList()
	if filters == nil {
		t.Error("Expected Filters list. Filters list is nil")
	}
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
}

func TestFilterService_GetMyFilters(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/3/filter/my"
	raw, err := ioutil.ReadFile("./mocks/my_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	opts := GetMyFiltersQueryOptions{}
	filters, _, err := testClient.Filter.GetMyFilters(&opts)
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
	if filters == nil {
		t.Errorf("Expected Filters, got nil")
	}
}

func TestFilterService_Search(t *testing.T) {
	setup()
	defer teardown()
	testAPIEndpoint := "/rest/api/3/filter/search"
	raw, err := ioutil.ReadFile("./mocks/search_filters.json")
	if err != nil {
		t.Error(err.Error())
	}
	testMux.HandleFunc(testAPIEndpoint, func(writer http.ResponseWriter, request *http.Request) {
		testMethod(t, request, "GET")
		testRequestURL(t, request, testAPIEndpoint)
		fmt.Fprint(writer, string(raw))
	})

	opt := FilterSearchOptions{}
	filters, _, err := testClient.Filter.Search(&opt)
	if err != nil {
		t.Errorf("Error given: %s", err)
	}
	if filters == nil {
		t.Errorf("Expected Filters, got nil")
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package identicon

import (
	"crypto/md5"
	"fmt"
	"image"
	"image/color"
)

const (
	minSize       = 16 // 图片的最小尺寸
	maxForeColors = 32 // 在New()函数中可以指定的最大颜色数量
)

// Identicon 用于产生统一尺寸的头像。
// 可以根据用户提供的数据，经过一定的算法，自动产生相应的图案和颜色。
type Identicon struct {
	foreColors []color.Color
	backColor  color.Color
	size       int
}

// 声明一个Identicon实例。
// size表示整个头像的大小。
// back表示前景色。
// fore表示所有可能的前景色，会为每个图像随机挑选一个作为其前景色。不要与背景色太相近。
func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) {
	if len(fore) == 0 || len(fore) > maxForeColors {
		return nil, fmt.Errorf("前景色数量必须介于[1]~[%v]之间，当前为[%v]", maxForeColors, len(fore))
	}

	if size < minSize {
		return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize)
	}

	return &Identicon{
		foreColors: fore,
		backColor:  back,
		size:       size,
	}, nil
}

// 根据data数据产生一张唯一性的头像图片。
func (i *Identicon) Make(data []byte) image.Image {
	h := md5.New()
	h.Write(data)
	sum := h.Sum(nil)

	// 第一个方块
	index := abs(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks)
	b1 := blocks[index]

	// 第二个方块
	index = abs(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks)
	b2 := blocks[index]

	// 中间方块
	index = abs(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks)
	c := centerBlocks[index]

	// 旋转角度
	angle := abs(sum[12]+sum[13]+sum[14]) % 4

	// 根据最后一个字段，获取前景颜色
	index = abs(sum[15]) % len(i.foreColors)

	// 画布坐标从0开始，其长度应该是size-1
	p := image.NewPaletted(image.Rect(0, 0, i.size-1, i.size-1), []color.Color{i.backColor, i.foreColors[index]})
	drawBlocks(p, i.size, c, b1, b2, angle)
	return p
}

// 根据data数据产生一张唯一性的头像图片。
// size 头像的大小。
// back, fore头像的背景和前景色。
func Make(size int, back, fore color.Color, data []byte) (image.Image, error) {
	if size < minSize {
		return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize)
	}

	h := md5.New()
	h.Write(data)
	sum := h.Sum(nil)

	// 第一个方块
	index := abs(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks)
	b1 := blocks[index]

	// 第二个方块
	index = abs(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks)
	b2 := blocks[index]

	// 中间方块
	index = abs(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks)
	c := centerBlocks[index]

	// 旋转角度
	angle := abs(sum[12]+sum[13]+sum[14]+sum[15]) % 4

	// 画布坐标从0开始，其长度应该是size-1
	p := image.NewPaletted(image.Rect(0, 0, size-1, size-1), []color.Color{back, fore})
	drawBlocks(p, size, c, b1, b2, angle)
	return p, nil
}

// 将九个方格都填上内容。
// p为画板。
// c为中间方格的填充函数。
// b1,b2为边上8格的填充函数。
// angle为b1,b2的起始旋转角度。
func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, angle int) {
	blockSize := float64(size / 3) // 每个格子的长宽
	twoBlockSize := 2 * blockSize

	incr := func() { // 增加angle的值，但不会大于3
		if angle > 2 {
			angle = 0
		} else {
			angle++
		}
	}

	c(p, blockSize, blockSize, blockSize, 0)

	b1(p, 0, 0, blockSize, angle)
	b2(p, blockSize, 0, blockSize, angle)

	incr()
	b1(p, twoBlockSize, 0, blockSize, angle)
	b2(p, twoBlockSize, blockSize, blockSize, angle)

	incr()
	b1(p, twoBlockSize, twoBlockSize, blockSize, angle)
	b2(p, blockSize, twoBlockSize, blockSize, angle)

	incr()
	b1(p, 0, twoBlockSize, blockSize, angle)
	b2(p, 0, blockSize, blockSize, angle)
}

func abs(x byte) int {
	if x < 0 {
		return int(-x)
	}
	return int(x)
}
<commit_msg>缓存Identicon中图片的大小<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package identicon

import (
	"crypto/md5"
	"fmt"
	"image"
	"image/color"
)

const (
	minSize       = 16 // 图片的最小尺寸
	maxForeColors = 32 // 在New()函数中可以指定的最大颜色数量
)

// Identicon 用于产生统一尺寸的头像。
// 可以根据用户提供的数据，经过一定的算法，自动产生相应的图案和颜色。
type Identicon struct {
	foreColors []color.Color
	backColor  color.Color
	size       int
	rect       image.Rectangle
}

// 声明一个Identicon实例。
// size表示整个头像的大小。
// back表示前景色。
// fore表示所有可能的前景色，会为每个图像随机挑选一个作为其前景色。不要与背景色太相近。
func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) {
	if len(fore) == 0 || len(fore) > maxForeColors {
		return nil, fmt.Errorf("前景色数量必须介于[1]~[%v]之间，当前为[%v]", maxForeColors, len(fore))
	}

	if size < minSize {
		return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize)
	}

	return &Identicon{
		foreColors: fore,
		backColor:  back,
		size:       size,
		rect:       image.Rect(0, 0, size-1, size-1),
	}, nil
}

// 根据data数据产生一张唯一性的头像图片。
func (i *Identicon) Make(data []byte) image.Image {
	h := md5.New()
	h.Write(data)
	sum := h.Sum(nil)

	// 第一个方块
	index := abs(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks)
	b1 := blocks[index]

	// 第二个方块
	index = abs(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks)
	b2 := blocks[index]

	// 中间方块
	index = abs(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks)
	c := centerBlocks[index]

	// 旋转角度
	angle := abs(sum[12]+sum[13]+sum[14]) % 4

	// 根据最后一个字段，获取前景颜色
	index = abs(sum[15]) % len(i.foreColors)

	// 画布坐标从0开始，其长度应该是size-1
	p := image.NewPaletted(i.rect, []color.Color{i.backColor, i.foreColors[index]})
	drawBlocks(p, i.size, c, b1, b2, angle)
	return p
}

// 根据data数据产生一张唯一性的头像图片。
// size 头像的大小。
// back, fore头像的背景和前景色。
func Make(size int, back, fore color.Color, data []byte) (image.Image, error) {
	if size < minSize {
		return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize)
	}

	h := md5.New()
	h.Write(data)
	sum := h.Sum(nil)

	// 第一个方块
	index := abs(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks)
	b1 := blocks[index]

	// 第二个方块
	index = abs(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks)
	b2 := blocks[index]

	// 中间方块
	index = abs(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks)
	c := centerBlocks[index]

	// 旋转角度
	angle := abs(sum[12]+sum[13]+sum[14]+sum[15]) % 4

	// 画布坐标从0开始，其长度应该是size-1
	p := image.NewPaletted(image.Rect(0, 0, size-1, size-1), []color.Color{back, fore})
	drawBlocks(p, size, c, b1, b2, angle)
	return p, nil
}

// 将九个方格都填上内容。
// p为画板。
// c为中间方格的填充函数。
// b1,b2为边上8格的填充函数。
// angle为b1,b2的起始旋转角度。
func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, angle int) {
	blockSize := float64(size / 3) // 每个格子的长宽
	twoBlockSize := 2 * blockSize

	incr := func() { // 增加angle的值，但不会大于3
		if angle > 2 {
			angle = 0
		} else {
			angle++
		}
	}

	c(p, blockSize, blockSize, blockSize, 0)

	b1(p, 0, 0, blockSize, angle)
	b2(p, blockSize, 0, blockSize, angle)

	incr()
	b1(p, twoBlockSize, 0, blockSize, angle)
	b2(p, twoBlockSize, blockSize, blockSize, angle)

	incr()
	b1(p, twoBlockSize, twoBlockSize, blockSize, angle)
	b2(p, blockSize, twoBlockSize, blockSize, angle)

	incr()
	b1(p, 0, twoBlockSize, blockSize, angle)
	b2(p, 0, blockSize, blockSize, angle)
}

func abs(x byte) int {
	if x < 0 {
		return int(-x)
	}
	return int(x)
}
<|endoftext|>


<commit_before>// +build lambdabinary,!noop

package cgo

// #include <stdlib.h>
// #include <string.h>
import "C"

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/mweagle/Sparta"
	spartaAWS "github.com/mweagle/Sparta/aws"
)

// Lock to update CGO related config
var muCredentials sync.Mutex
var pythonCredentialsValue credentials.Value

////////////////////////////////////////////////////////////////////////////////
// spartaMockHTTPResponse is the buffered response to handle the HTTP
// response provided by the underlying function
type spartaMockHTTPResponse struct {
	// Private vars
	statusCode int
	headers    http.Header
	bytes      bytes.Buffer
}

func (spartaResp *spartaMockHTTPResponse) Header() http.Header {
	return spartaResp.headers
}

func (spartaResp *spartaMockHTTPResponse) Write(data []byte) (int, error) {
	return spartaResp.bytes.Write(data)
}

func (spartaResp *spartaMockHTTPResponse) WriteHeader(statusCode int) {
	spartaResp.statusCode = statusCode
}

func newspartaMockHTTPResponse() *spartaMockHTTPResponse {
	resp := &spartaMockHTTPResponse{
		statusCode: 200,
		headers:    make(map[string][]string, 0),
	}
	return resp
}

////////////////////////////////////////////////////////////////////////////////
// lambdaFunctionErrResponse is the struct used to return a CGO error response
type lambdaFunctionErrResponse struct {
	Code    int         `json:"code"`
	Status  string      `json:"status"`
	Headers http.Header `json:"headers"`
	Error   string      `json:"error"`
}

////////////////////////////////////////////////////////////////////////////////
// cgoLambdaHTTPAdapterStruct is the binding between the various params
// supplied to the LambdaHandler
type cgoLambdaHTTPAdapterStruct struct {
	serviceName               string
	lambdaHTTPHandlerInstance *sparta.LambdaHTTPHandler
	logger                    *logrus.Logger
}

var cgoLambdaHTTPAdapter cgoLambdaHTTPAdapterStruct

////////////////////////////////////////////////////////////////////////////////
// cgoMain is the primary entrypoint for the library version
func cgoMain(callerFile string,
	serviceName string,
	serviceDescription string,
	lambdaAWSInfos []*sparta.LambdaAWSInfo,
	api *sparta.API,
	site *sparta.S3Site,
	workflowHooks *sparta.WorkflowHooks) error {
	logger, loggerErr := sparta.NewLogger("info")
	if nil != loggerErr {
		panic("Failed to initialize logger")
	}
	cgoLambdaHTTPAdapter = cgoLambdaHTTPAdapterStruct{
		serviceName:               serviceName,
		lambdaHTTPHandlerInstance: sparta.NewLambdaHTTPHandler(lambdaAWSInfos, logger),
		logger: logger,
	}
	return nil
}

func makeRequest(functionName string,
	eventBody io.ReadCloser,
	eventBodySize int64) ([]byte, http.Header, error) {
	spartaResp := newspartaMockHTTPResponse()

	// Create an http.Request object with this data...
	spartaReq := &http.Request{
		Method: "POST",
		URL: &url.URL{
			Scheme: "http",
			Path:   fmt.Sprintf("/%s", functionName),
		},
		Proto:            "HTTP/1.1",
		ProtoMajor:       1,
		ProtoMinor:       1,
		Body:             eventBody,
		ContentLength:    eventBodySize,
		TransferEncoding: make([]string, 0),
		Host:             "localhost",
	}
	cgoLambdaHTTPAdapter.lambdaHTTPHandlerInstance.ServeHTTP(spartaResp, spartaReq)

	// If there was an HTTP error, transform that into a stable
	// error payload and continue. This is the same format that's
	// used by the NodeJS proxying tier at /resources/index.js
	if spartaResp.statusCode >= 400 {
		errResponseBody := lambdaFunctionErrResponse{
			Code:    spartaResp.statusCode,
			Status:  http.StatusText(spartaResp.statusCode),
			Headers: spartaResp.Header(),
			Error:   spartaResp.bytes.String(),
		}

		// Replace the response with a new one
		jsonBytes, jsonBytesErr := json.Marshal(errResponseBody)
		if nil != jsonBytesErr {
			return nil, nil, jsonBytesErr
		} else {
			errResponse := newspartaMockHTTPResponse()
			errResponse.Write(jsonBytes)
			errResponse.Header().Set("content-length", strconv.Itoa(len(jsonBytes)))
			errResponse.Header().Set("content-type", "application/json")
			spartaResp = errResponse
		}
	}
	return spartaResp.bytes.Bytes(), spartaResp.headers, nil
}

func postMetrics(awsCredentials *credentials.Credentials,
	path string,
	responseBodyLength int,
	duration time.Duration) {

	awsCloudWatchService := cloudwatch.New(NewSession())
	metricNamespace := fmt.Sprintf("Sparta/%s", cgoLambdaHTTPAdapter.serviceName)
	lambdaFunctionName := os.Getenv("AWS_LAMBDA_FUNCTION_NAME")

	metricData := make([]*cloudwatch.MetricDatum, 0)
	sharedDimensions := make([]*cloudwatch.Dimension, 0)
	sharedDimensions = append(sharedDimensions,
		&cloudwatch.Dimension{
			Name:  aws.String("Path"),
			Value: aws.String(path),
		},
		&cloudwatch.Dimension{
			Name:  aws.String("Name"),
			Value: aws.String(lambdaFunctionName),
		})

	var sysinfo syscall.Sysinfo_t
	sysinfoErr := syscall.Sysinfo(&sysinfo)
	if nil == sysinfoErr {
		metricData = append(metricData, &cloudwatch.MetricDatum{
			MetricName: aws.String("Uptime"),
			Dimensions: sharedDimensions,
			Unit:       aws.String("Seconds"),
			Value:      aws.Float64(float64(sysinfo.Uptime)),
		})
	}
	metricData = append(metricData, &cloudwatch.MetricDatum{
		MetricName: aws.String("LambdaResponseLength"),
		Dimensions: sharedDimensions,
		Unit:       aws.String("Bytes"),
		Value:      aws.Float64(float64(responseBodyLength)),
	})
	params := &cloudwatch.PutMetricDataInput{
		MetricData: metricData,
		Namespace:  aws.String(metricNamespace),
	}
	awsCloudWatchService.PutMetricData(params)
}

// LambdaHandler is the public handler that's called by the transformed
// CGO compliant userinput. Users should not need to call this function
// directly
func LambdaHandler(functionName string,
	eventJSON string,
	awsCredentials *credentials.Credentials) ([]byte, http.Header, error) {
	startTime := time.Now()
	readableBody := ioutil.NopCloser(strings.NewReader(eventJSON))

	// Update the credentials
	muCredentials.Lock()
	value, valueErr := awsCredentials.Get()
	if nil != valueErr {
		muCredentials.Unlock()
		return nil, nil, valueErr
	}
	pythonCredentialsValue.AccessKeyID = value.AccessKeyID
	pythonCredentialsValue.SecretAccessKey = value.SecretAccessKey
	pythonCredentialsValue.SessionToken = value.SessionToken
	pythonCredentialsValue.ProviderName = "PythonCGO"
	muCredentials.Unlock()

	// Update the credentials in the HTTP handler
	// in case we're ultimately forwarding to a custom
	// resource provider
	cgoLambdaHTTPAdapter.lambdaHTTPHandlerInstance.Credentials(pythonCredentialsValue)

	// Make the request...
	response, header, err := makeRequest(functionName, readableBody, int64(len(eventJSON)))

	// TODO: Consider go routine
	postMetrics(awsCredentials, functionName, len(response), time.Since(startTime))
	return response, header, err
}

// NewSession returns a CGO-aware AWS session that uses the Python
// credentials provided by the CGO interface.
func NewSession() *session.Session {
	muCredentials.Lock()
	defer muCredentials.Unlock()

	awsConfig := aws.
		NewConfig().
		WithCredentials(credentials.NewStaticCredentialsFromCreds(pythonCredentialsValue))
	return spartaAWS.NewSessionWithConfig(awsConfig, cgoLambdaHTTPAdapter.logger)
}
<commit_msg>Make function name interCap friendly<commit_after>// +build lambdabinary,!noop

package cgo

// #include <stdlib.h>
// #include <string.h>
import "C"

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/mweagle/Sparta"
	spartaAWS "github.com/mweagle/Sparta/aws"
)

// Lock to update CGO related config
var muCredentials sync.Mutex
var pythonCredentialsValue credentials.Value

////////////////////////////////////////////////////////////////////////////////
// spartaMockHTTPResponse is the buffered response to handle the HTTP
// response provided by the underlying function
type spartaMockHTTPResponse struct {
	// Private vars
	statusCode int
	headers    http.Header
	bytes      bytes.Buffer
}

func (spartaResp *spartaMockHTTPResponse) Header() http.Header {
	return spartaResp.headers
}

func (spartaResp *spartaMockHTTPResponse) Write(data []byte) (int, error) {
	return spartaResp.bytes.Write(data)
}

func (spartaResp *spartaMockHTTPResponse) WriteHeader(statusCode int) {
	spartaResp.statusCode = statusCode
}

func newSpartaMockHTTPResponse() *spartaMockHTTPResponse {
	resp := &spartaMockHTTPResponse{
		statusCode: 200,
		headers:    make(map[string][]string, 0),
	}
	return resp
}

////////////////////////////////////////////////////////////////////////////////
// lambdaFunctionErrResponse is the struct used to return a CGO error response
type lambdaFunctionErrResponse struct {
	Code    int         `json:"code"`
	Status  string      `json:"status"`
	Headers http.Header `json:"headers"`
	Error   string      `json:"error"`
}

////////////////////////////////////////////////////////////////////////////////
// cgoLambdaHTTPAdapterStruct is the binding between the various params
// supplied to the LambdaHandler
type cgoLambdaHTTPAdapterStruct struct {
	serviceName               string
	lambdaHTTPHandlerInstance *sparta.LambdaHTTPHandler
	logger                    *logrus.Logger
}

var cgoLambdaHTTPAdapter cgoLambdaHTTPAdapterStruct

////////////////////////////////////////////////////////////////////////////////
// cgoMain is the primary entrypoint for the library version
func cgoMain(callerFile string,
	serviceName string,
	serviceDescription string,
	lambdaAWSInfos []*sparta.LambdaAWSInfo,
	api *sparta.API,
	site *sparta.S3Site,
	workflowHooks *sparta.WorkflowHooks) error {
	logger, loggerErr := sparta.NewLogger("info")
	if nil != loggerErr {
		panic("Failed to initialize logger")
	}
	cgoLambdaHTTPAdapter = cgoLambdaHTTPAdapterStruct{
		serviceName:               serviceName,
		lambdaHTTPHandlerInstance: sparta.NewLambdaHTTPHandler(lambdaAWSInfos, logger),
		logger: logger,
	}
	return nil
}

func makeRequest(functionName string,
	eventBody io.ReadCloser,
	eventBodySize int64) ([]byte, http.Header, error) {

	// Create an http.Request object with this data...
	spartaResp := newSpartaMockHTTPResponse()
	spartaReq := &http.Request{
		Method: "POST",
		URL: &url.URL{
			Scheme: "http",
			Path:   fmt.Sprintf("/%s", functionName),
		},
		Proto:            "HTTP/1.1",
		ProtoMajor:       1,
		ProtoMinor:       1,
		Body:             eventBody,
		ContentLength:    eventBodySize,
		TransferEncoding: make([]string, 0),
		Host:             "localhost",
	}
	cgoLambdaHTTPAdapter.lambdaHTTPHandlerInstance.ServeHTTP(spartaResp, spartaReq)

	// If there was an HTTP error, transform that into a stable
	// error payload and continue. This is the same format that's
	// used by the NodeJS proxying tier at /resources/index.js
	if spartaResp.statusCode >= 400 {
		errResponseBody := lambdaFunctionErrResponse{
			Code:    spartaResp.statusCode,
			Status:  http.StatusText(spartaResp.statusCode),
			Headers: spartaResp.Header(),
			Error:   spartaResp.bytes.String(),
		}

		// Replace the response with a new one
		jsonBytes, jsonBytesErr := json.Marshal(errResponseBody)
		if nil != jsonBytesErr {
			return nil, nil, jsonBytesErr
		} else {
			errResponse := newSpartaMockHTTPResponse()
			errResponse.Write(jsonBytes)
			errResponse.Header().Set("content-length", strconv.Itoa(len(jsonBytes)))
			errResponse.Header().Set("content-type", "application/json")
			spartaResp = errResponse
		}
	}
	return spartaResp.bytes.Bytes(), spartaResp.headers, nil
}

func postMetrics(awsCredentials *credentials.Credentials,
	path string,
	responseBodyLength int,
	duration time.Duration) {

	awsCloudWatchService := cloudwatch.New(NewSession())
	metricNamespace := fmt.Sprintf("Sparta/%s", cgoLambdaHTTPAdapter.serviceName)
	lambdaFunctionName := os.Getenv("AWS_LAMBDA_FUNCTION_NAME")

	metricData := make([]*cloudwatch.MetricDatum, 0)
	sharedDimensions := make([]*cloudwatch.Dimension, 0)
	sharedDimensions = append(sharedDimensions,
		&cloudwatch.Dimension{
			Name:  aws.String("Path"),
			Value: aws.String(path),
		},
		&cloudwatch.Dimension{
			Name:  aws.String("Name"),
			Value: aws.String(lambdaFunctionName),
		})

	var sysinfo syscall.Sysinfo_t
	sysinfoErr := syscall.Sysinfo(&sysinfo)
	if nil == sysinfoErr {
		metricData = append(metricData, &cloudwatch.MetricDatum{
			MetricName: aws.String("Uptime"),
			Dimensions: sharedDimensions,
			Unit:       aws.String("Seconds"),
			Value:      aws.Float64(float64(sysinfo.Uptime)),
		})
	}
	metricData = append(metricData, &cloudwatch.MetricDatum{
		MetricName: aws.String("LambdaResponseLength"),
		Dimensions: sharedDimensions,
		Unit:       aws.String("Bytes"),
		Value:      aws.Float64(float64(responseBodyLength)),
	})
	params := &cloudwatch.PutMetricDataInput{
		MetricData: metricData,
		Namespace:  aws.String(metricNamespace),
	}
	awsCloudWatchService.PutMetricData(params)
}

// LambdaHandler is the public handler that's called by the transformed
// CGO compliant userinput. Users should not need to call this function
// directly
func LambdaHandler(functionName string,
	eventJSON string,
	awsCredentials *credentials.Credentials) ([]byte, http.Header, error) {
	startTime := time.Now()
	readableBody := ioutil.NopCloser(strings.NewReader(eventJSON))

	// Update the credentials
	muCredentials.Lock()
	value, valueErr := awsCredentials.Get()
	if nil != valueErr {
		muCredentials.Unlock()
		return nil, nil, valueErr
	}
	pythonCredentialsValue.AccessKeyID = value.AccessKeyID
	pythonCredentialsValue.SecretAccessKey = value.SecretAccessKey
	pythonCredentialsValue.SessionToken = value.SessionToken
	pythonCredentialsValue.ProviderName = "PythonCGO"
	muCredentials.Unlock()

	// Update the credentials in the HTTP handler
	// in case we're ultimately forwarding to a custom
	// resource provider
	cgoLambdaHTTPAdapter.lambdaHTTPHandlerInstance.Credentials(pythonCredentialsValue)

	// Make the request...
	response, header, err := makeRequest(functionName, readableBody, int64(len(eventJSON)))

	// TODO: Consider go routine
	postMetrics(awsCredentials, functionName, len(response), time.Since(startTime))
	return response, header, err
}

// NewSession returns a CGO-aware AWS session that uses the Python
// credentials provided by the CGO interface.
func NewSession() *session.Session {
	muCredentials.Lock()
	defer muCredentials.Unlock()

	awsConfig := aws.
		NewConfig().
		WithCredentials(credentials.NewStaticCredentialsFromCreds(pythonCredentialsValue))
	return spartaAWS.NewSessionWithConfig(awsConfig, cgoLambdaHTTPAdapter.logger)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 gcs

import (
	"io"
	"math/rand"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
)

// A bucket that wraps another, calling its methods in a retry loop with
// randomized exponential backoff.
type retryBucket struct {
	maxSleep time.Duration
	wrapped  Bucket
}

func newRetryBucket(
	maxSleep time.Duration,
	wrapped Bucket) (b Bucket) {
	b = &retryBucket{
		maxSleep: maxSleep,
		wrapped:  wrapped,
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Exponential backoff for a function that might fail.
//
// This is essentially what is described in the "Best practices" section of the
// "Upload Objects" docs:
//
//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
//
// with the following exceptions:
//
//  *  We perform backoff for all errors except:
//      *  HTTP 40x errors
//      *  Error types defined by this package
//
//  *  We perform backoff for all operations.
//
//  *  The random component scales with the delay, so that the first sleep
//     cannot be as long as one second. The algorithm used matches the
//     description at http://en.wikipedia.org/wiki/Exponential_backoff.
//
func expBackoff(
	ctx context.Context,
	maxSleep time.Duration,
	f func() error) (err error) {
	const baseDelay = time.Millisecond
	var totalSleep time.Duration

	for n := uint(0); ; n++ {
		// Make an attempt.
		err = f()

		// Is this an error we want to pass through?
		if _, ok := err.(*NotFoundError); ok {
			return
		}

		if _, ok := err.(*PreconditionError); ok {
			return
		}

		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code >= 400 && typed.Code < 500 {
				return
			}
		}

		// Choose a a delay in [0, 2^n * baseDelay).
		d := (1 << n) * baseDelay
		d = time.Duration(float64(d) * rand.Float64())

		// Are we out of credit?
		if totalSleep+d > maxSleep {
			// Return the most recent error.
			return
		}

		// Sleep, returning early if cancelled.
		select {
		case <-ctx.Done():
			err = ctx.Err()
			return

		case <-time.After(d):
			totalSleep += d
			continue
		}
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (rb *retryBucket) Name() (name string) {
	name = rb.wrapped.Name()
	return
}

func (rb *retryBucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			rc, err = rb.wrapped.NewReader(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.CreateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.StatObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			listing, err = rb.wrapped.ListObjects(ctx, req)
			return
		})
	return
}

func (rb *retryBucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.UpdateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			err = rb.wrapped.DeleteObject(ctx, name)
			return
		})

	return
}
<commit_msg>Stop when successful. Oops.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 gcs

import (
	"io"
	"math/rand"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
)

// A bucket that wraps another, calling its methods in a retry loop with
// randomized exponential backoff.
type retryBucket struct {
	maxSleep time.Duration
	wrapped  Bucket
}

func newRetryBucket(
	maxSleep time.Duration,
	wrapped Bucket) (b Bucket) {
	b = &retryBucket{
		maxSleep: maxSleep,
		wrapped:  wrapped,
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Exponential backoff for a function that might fail.
//
// This is essentially what is described in the "Best practices" section of the
// "Upload Objects" docs:
//
//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
//
// with the following exceptions:
//
//  *  We perform backoff for all errors except:
//      *  HTTP 40x errors
//      *  Error types defined by this package
//
//  *  We perform backoff for all operations.
//
//  *  The random component scales with the delay, so that the first sleep
//     cannot be as long as one second. The algorithm used matches the
//     description at http://en.wikipedia.org/wiki/Exponential_backoff.
//
func expBackoff(
	ctx context.Context,
	maxSleep time.Duration,
	f func() error) (err error) {
	const baseDelay = time.Millisecond
	var totalSleep time.Duration

	for n := uint(0); ; n++ {
		// Make an attempt. Stop if successful.
		err = f()
		if err == nil {
			return
		}

		// Is this an error we want to pass through?
		if _, ok := err.(*NotFoundError); ok {
			return
		}

		if _, ok := err.(*PreconditionError); ok {
			return
		}

		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code >= 400 && typed.Code < 500 {
				return
			}
		}

		// Choose a a delay in [0, 2^n * baseDelay).
		d := (1 << n) * baseDelay
		d = time.Duration(float64(d) * rand.Float64())

		// Are we out of credit?
		if totalSleep+d > maxSleep {
			// Return the most recent error.
			return
		}

		// Sleep, returning early if cancelled.
		select {
		case <-ctx.Done():
			err = ctx.Err()
			return

		case <-time.After(d):
			totalSleep += d
			continue
		}
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (rb *retryBucket) Name() (name string) {
	name = rb.wrapped.Name()
	return
}

func (rb *retryBucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			rc, err = rb.wrapped.NewReader(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.CreateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.StatObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			listing, err = rb.wrapped.ListObjects(ctx, req)
			return
		})
	return
}

func (rb *retryBucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.UpdateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			err = rb.wrapped.DeleteObject(ctx, name)
			return
		})

	return
}
<|endoftext|>


<commit_before>package force

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

const (
	grantType    = "password"
	loginUri     = "http://login.salesforce.com/services/oauth2/token"
	testLoginUri = "http://test.salesforce.com/services/oauth2/token"

	invalidSessionErrorCode = "INVALID_SESSION_ID"
)

type forceOauth struct {
	AccessToken string `json:"access_token"`
	InstanceUrl string `json:"instance_url"`
	Id          string `json:"id"`
	IssuedAt    string `json:"issued_at"`
	Signature   string `json:"signature"`

	clientId      string
	clientSecret  string
	userName      string
	password      string
	securityToken string
	environment   string

	client *http.Client
}

func (oauth *forceOauth) Validate() error {
	if oauth == nil || len(oauth.InstanceUrl) == 0 || len(oauth.AccessToken) == 0 {
		return fmt.Errorf("Invalid Force Oauth Object: %#v", oauth)
	}

	return nil
}

func (oauth *forceOauth) Expired(apiErrors ApiErrors) bool {
	for _, err := range apiErrors {
		if err.ErrorCode == invalidSessionErrorCode {
			return true
		}
	}

	return false
}

func (oauth *forceOauth) Authenticate() error {
	payload := url.Values{
		"grant_type":    {grantType},
		"client_id":     {oauth.clientId},
		"client_secret": {oauth.clientSecret},
		"username":      {oauth.userName},
		"password":      {fmt.Sprintf("%v%v", oauth.password, oauth.securityToken)},
	}

	// Build Uri
	uri := loginUri
	proxyURL := &url.URL{Scheme: "http"}
	if oauth.environment == "sandbox" {
		uri = testLoginUri
		proxyURL.Host = "staging-proxy.beomni.com:8000"
	} else {
		proxyURL.Host = "proxy.beomni.com:8000"
	}

	// Build Body
	body := strings.NewReader(payload.Encode())

	// Build Request
	req, err := http.NewRequest("POST", uri, body)
	if err != nil {
		return fmt.Errorf("Error creating authenitcation request: %v", err)
	}

	// Add Headers
	req.Header.Set("User-Agent", userAgent)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", responseType)

	oauth.client = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}}
	resp, err := oauth.client.Do(req)
	if err != nil {
		return fmt.Errorf("Error sending authentication request %v to %v! Error: %v", body, uri, err)
	}
	defer resp.Body.Close()

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("Error reading authentication response bytes: %v", err)
	}

	// Attempt to parse response as a force.com api error
	apiError := &ApiError{}
	if err := json.Unmarshal(respBytes, apiError); err == nil {
		// Check if api error is valid
		if apiError.Validate() {
			return apiError
		}
	}

	if err := json.Unmarshal(respBytes, oauth); err != nil {
		return fmt.Errorf("Unable to unmarshal authentication response: %v", err)
	}

	return nil
}
<commit_msg>disable the fucking shim<commit_after>package force

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

const (
	grantType    = "password"
	loginUri     = "https://login.salesforce.com/services/oauth2/token"
	testLoginUri = "https://test.salesforce.com/services/oauth2/token"

	invalidSessionErrorCode = "INVALID_SESSION_ID"
)

type forceOauth struct {
	AccessToken string `json:"access_token"`
	InstanceUrl string `json:"instance_url"`
	Id          string `json:"id"`
	IssuedAt    string `json:"issued_at"`
	Signature   string `json:"signature"`

	clientId      string
	clientSecret  string
	userName      string
	password      string
	securityToken string
	environment   string

	client *http.Client
}

func (oauth *forceOauth) Validate() error {
	if oauth == nil || len(oauth.InstanceUrl) == 0 || len(oauth.AccessToken) == 0 {
		return fmt.Errorf("Invalid Force Oauth Object: %#v", oauth)
	}

	return nil
}

func (oauth *forceOauth) Expired(apiErrors ApiErrors) bool {
	for _, err := range apiErrors {
		if err.ErrorCode == invalidSessionErrorCode {
			return true
		}
	}

	return false
}

func (oauth *forceOauth) Authenticate() error {
	payload := url.Values{
		"grant_type":    {grantType},
		"client_id":     {oauth.clientId},
		"client_secret": {oauth.clientSecret},
		"username":      {oauth.userName},
		"password":      {fmt.Sprintf("%v%v", oauth.password, oauth.securityToken)},
	}

	// Build Uri
	uri := loginUri
	if oauth.environment == "sandbox" {
		uri = testLoginUri
	}

	// Build Body
	body := strings.NewReader(payload.Encode())

	// Build Request
	req, err := http.NewRequest("POST", uri, body)
	if err != nil {
		return fmt.Errorf("Error creating authenitcation request: %v", err)
	}

	// Add Headers
	req.Header.Set("User-Agent", userAgent)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", responseType)

	oauth.client = &http.Client{}
	resp, err := oauth.client.Do(req)
	if err != nil {
		return fmt.Errorf("Error sending authentication request %v to %v! Error: %v", body, uri, err)
	}
	defer resp.Body.Close()

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("Error reading authentication response bytes: %v", err)
	}

	// Attempt to parse response as a force.com api error
	apiError := &ApiError{}
	if err := json.Unmarshal(respBytes, apiError); err == nil {
		// Check if api error is valid
		if apiError.Validate() {
			return apiError
		}
	}

	if err := json.Unmarshal(respBytes, oauth); err != nil {
		return fmt.Errorf("Unable to unmarshal authentication response: %v", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

func GeneratorHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		t, err := template.ParseFiles("templates/generator.html")

		if err != nil {
			log.Println("Failed to parse files")
		}
		t.Execute(w, nil)

	case "POST":
		if err := r.ParseForm(); err != nil {
			log.Println("Failed to get post values")
		}

		rawText := r.PostFormValue("desc")
		titleField, minusTitle := ParseTitle(rawText)
		dateField := ParseDate(rawText)
		//desc := blackfriday.MarkdownCommon([]byte(rawText))

		docId, err := pageCol.Insert(map[string]interface{}{
			"title": titleField,
			"desc":  minusTitle,
			"date":  dateField,
			"bg": "",
		})

		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/p/"+strconv.Itoa(docId), http.StatusFound)
	default:
		http.Error(w, "Method not allowed", 405)

	}
}

func ParseDate(sample string) time.Time {
	datePattern, err := regexp.Compile(`(\d{1,2}\b\D{3,9}\b\d{4})|([a-zA-Z]{3,9}\s\d{1,2}\s\d{4})`)

	if err != nil {
		panic(err)
	}

	colloquialPattern, err := regexp.Compile(`(\d{1,2}\b\D{3,9}\b\d{4})`)

	if err != nil {
		panic(err)
	}

	americanPattern, err := regexp.Compile(`([a-zA-Z]{3,9}\s\d{1,2}\s\d{4})`)
	if err != nil {
		panic(err)
	}
	var t time.Time
	dateString := datePattern.FindString(sample)
	switch {
	case americanPattern.MatchString(dateString):
		t, _ = time.Parse("January 2 2006", datePattern.FindString(sample))

	case colloquialPattern.MatchString(dateString):
		t, _ = time.Parse("2 January 2006", datePattern.FindString(sample))
	}
	return t
}

func ParseTitle(sample string) (title, minusTitle string) {
 titlePattern, err := regexp.Compile(`^(#\s).*`)
 if err != nil {
 	panic(err)
 }

 title = titlePattern.FindString(sample)
 minusTitle = sample[len(title):]
 title = title[2:]
 return

}
<commit_msg>Fixed fatal absence of title bug in gen<commit_after>package main

import (
	"html/template"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

func GeneratorHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		t, err := template.ParseFiles("templates/generator.html")

		if err != nil {
			log.Println("Failed to parse files")
		}
		t.Execute(w, nil)

	case "POST":
		if err := r.ParseForm(); err != nil {
			log.Println("Failed to get post values")
		}

		rawText := r.PostFormValue("desc")
		titleField, minusTitle := ParseTitle(rawText)
		dateField := ParseDate(rawText)
		//desc := blackfriday.MarkdownCommon([]byte(rawText))

		docId, err := pageCol.Insert(map[string]interface{}{
			"title": titleField,
			"desc":  minusTitle,
			"date":  dateField,
			"bg": "",
		})

		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/p/"+strconv.Itoa(docId), http.StatusFound)
	default:
		http.Error(w, "Method not allowed", 405)

	}
}

func ParseDate(sample string) time.Time {
	datePattern, err := regexp.Compile(`(\d{1,2}\b\D{3,9}\b\d{4})|([a-zA-Z]{3,9}\s\d{1,2}\s\d{4})`)

	if err != nil {
		panic(err)
	}

	colloquialPattern, err := regexp.Compile(`(\d{1,2}\b\D{3,9}\b\d{4})`)

	if err != nil {
		panic(err)
	}

	americanPattern, err := regexp.Compile(`([a-zA-Z]{3,9}\s\d{1,2}\s\d{4})`)
	if err != nil {
		panic(err)
	}
	var t time.Time
	dateString := datePattern.FindString(sample)
	switch {
	case americanPattern.MatchString(dateString):
		t, _ = time.Parse("January 2 2006", datePattern.FindString(sample))

	case colloquialPattern.MatchString(dateString):
		t, _ = time.Parse("2 January 2006", datePattern.FindString(sample))
	}
	return t
}

func ParseTitle(sample string) (title, minusTitle string) {
 titlePattern, err := regexp.Compile(`^(#\s).*`)
 if err != nil {
 	panic(err)
 }

 title = titlePattern.FindString(sample)
 minusTitle = sample[len(title):]
 if len(title) > 3 {
	 title = title[2:]
 } else {
 		title = "Your event"
 }
 return

}
<|endoftext|>


<commit_before>package charset

import (
	"testing"
)

func TestHeader(t *testing.T) {
	s := "¡Hola, señor!"

	enc := EncodeHeader(s)
	dec, err := DecodeHeader(enc)

	if err != nil {
		t.Error("Expected no error while decoding header, got:", err)
	} else if s != dec {
		t.Errorf("Expected decoded string to be %q but got %q", s, dec)
	}
}
<commit_msg>charset: adds unknwon charset test for DecodeHeader<commit_after>package charset

import (
	"testing"
)

func TestHeader(t *testing.T) {
	s := "¡Hola, señor!"

	enc := EncodeHeader(s)
	dec, err := DecodeHeader(enc)

	if err != nil {
		t.Error("Expected no error while decoding header, got:", err)
	} else if s != dec {
		t.Errorf("Expected decoded string to be %q but got %q", s, dec)
	}
}

func TestDecodeHeader_unknownCharset(t *testing.T) {
	enc := "=?idontexist?q?Hey you?="

	dec, err := DecodeHeader(enc)

	if err == nil {
		t.Error("Expected an error while decoding invalid header")
	}
	if dec != enc {
		t.Errorf("Expected decoded string to fallback to %q but got %q", enc, dec)
	}
}
<|endoftext|>