<commit_before>package utils

import (
	"fmt"
	"path/filepath"

	"github.com/bitrise-tools/go-xcode/plistutil"
	"github.com/bitrise-tools/xcode-project/serialized"
	"github.com/bitrise-tools/xcode-project/xcodeproj"
	"github.com/bitrise-tools/xcode-project/xcscheme"
	"github.com/bitrise-tools/xcode-project/xcworkspace"
)

// ProjectEntitlementsByBundleID ...
func ProjectEntitlementsByBundleID(pth, schemeName, configurationName string) (map[string]plistutil.PlistData, error) {
	var scheme xcscheme.Scheme
	var schemeContainerDir string

	if xcodeproj.IsXcodeProj(pth) {
		project, err := xcodeproj.Open(pth)
		if err != nil {
			return nil, err
		}

		var ok bool
		scheme, ok = project.Scheme(schemeName)
		if !ok {
			return nil, fmt.Errorf("no scheme found with name: %s in project: %s", schemeName, pth)
		}
		schemeContainerDir = filepath.Dir(pth)
	} else if xcworkspace.IsWorkspace(pth) {
		workspace, err := xcworkspace.Open(pth)
		if err != nil {
			return nil, err
		}

		var ok bool
		scheme, schemeContainerDir, ok = workspace.Scheme(schemeName)
		if !ok {
			return nil, fmt.Errorf("no scheme found with name: %s in workspace: %s", schemeName, pth)
		}
	} else {
		return nil, fmt.Errorf("unknown project extension: %s", filepath.Ext(pth))
	}

	if configurationName == "" {
		configurationName = scheme.ArchiveAction.BuildConfiguration
	}

	if configurationName == "" {
		return nil, fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName)
	}

	var archiveEntry xcscheme.BuildActionEntry
	for _, entry := range scheme.BuildAction.BuildActionEntries {
		if entry.BuildForArchiving != "YES" {
			continue
		}
		archiveEntry = entry
		break
	}

	if archiveEntry.BuildableReference.BlueprintIdentifier == "" {
		return nil, fmt.Errorf("archivable entry not found")
	}

	projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(schemeContainerDir)
	if err != nil {
		return nil, err
	}

	project, err := xcodeproj.Open(projectPth)
	if err != nil {
		return nil, err
	}

	mainTarget, ok := project.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier)
	if !ok {
		return nil, fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier)
	}

	targets := append([]xcodeproj.Target{mainTarget}, mainTarget.DependentTargets()...)

	entitlementsByBundleID := map[string]serialized.Object{}

	for _, target := range targets {
		bundleID, err := project.TargetBundleID(target.Name, configurationName)
		if err != nil {
			return nil, fmt.Errorf("Failed to get target (%s) bundle id: %s", target.Name, err)
		}

		entitlements, err := project.TargetCodeSignEntitlements(target.Name, configurationName)
		if err != nil && !serialized.IsKeyNotFoundError(err) {
			return nil, fmt.Errorf("Failed to get target (%s) bundle id: %s", target.Name, err)
		}

		entitlementsByBundleID[bundleID] = entitlements
	}

	return toMapStringPlistData(entitlementsByBundleID), nil
}

func toMapStringPlistData(object map[string]serialized.Object) map[string]plistutil.PlistData {
	converted := map[string]plistutil.PlistData{}
	for key, value := range object {
		converted[key] = plistutil.PlistData(value)
	}
	return converted
}
<commit_msg>scheme container project fix (#119)<commit_after>package utils

import (
	"fmt"
	"path/filepath"

	"github.com/bitrise-tools/go-xcode/plistutil"
	"github.com/bitrise-tools/xcode-project/serialized"
	"github.com/bitrise-tools/xcode-project/xcodeproj"
	"github.com/bitrise-tools/xcode-project/xcscheme"
	"github.com/bitrise-tools/xcode-project/xcworkspace"
)

// ProjectEntitlementsByBundleID ...
func ProjectEntitlementsByBundleID(pth, schemeName, configurationName string) (map[string]plistutil.PlistData, error) {
	var scheme xcscheme.Scheme
	var schemeContainerDir string

	if xcodeproj.IsXcodeProj(pth) {
		project, err := xcodeproj.Open(pth)
		if err != nil {
			return nil, err
		}

		var ok bool
		scheme, ok = project.Scheme(schemeName)
		if !ok {
			return nil, fmt.Errorf("no scheme found with name: %s in project: %s", schemeName, pth)
		}
		schemeContainerDir = filepath.Dir(pth)
	} else if xcworkspace.IsWorkspace(pth) {
		workspace, err := xcworkspace.Open(pth)
		if err != nil {
			return nil, err
		}

		var ok bool
		var containerProject string
		scheme, containerProject, ok = workspace.Scheme(schemeName)
		if !ok {
			return nil, fmt.Errorf("no scheme found with name: %s in workspace: %s", schemeName, pth)
		}
		schemeContainerDir = filepath.Dir(containerProject)
	} else {
		return nil, fmt.Errorf("unknown project extension: %s", filepath.Ext(pth))
	}

	if configurationName == "" {
		configurationName = scheme.ArchiveAction.BuildConfiguration
	}

	if configurationName == "" {
		return nil, fmt.Errorf("no configuration provided nor default defined for the scheme's (%s) archive action", schemeName)
	}

	var archiveEntry xcscheme.BuildActionEntry
	for _, entry := range scheme.BuildAction.BuildActionEntries {
		if entry.BuildForArchiving != "YES" {
			continue
		}
		archiveEntry = entry
		break
	}

	if archiveEntry.BuildableReference.BlueprintIdentifier == "" {
		return nil, fmt.Errorf("archivable entry not found")
	}

	projectPth, err := archiveEntry.BuildableReference.ReferencedContainerAbsPath(schemeContainerDir)
	if err != nil {
		return nil, err
	}

	project, err := xcodeproj.Open(projectPth)
	if err != nil {
		return nil, err
	}

	mainTarget, ok := project.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier)
	if !ok {
		return nil, fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier)
	}

	targets := append([]xcodeproj.Target{mainTarget}, mainTarget.DependentTargets()...)

	entitlementsByBundleID := map[string]serialized.Object{}

	for _, target := range targets {
		bundleID, err := project.TargetBundleID(target.Name, configurationName)
		if err != nil {
			return nil, fmt.Errorf("Failed to get target (%s) bundle id: %s", target.Name, err)
		}

		entitlements, err := project.TargetCodeSignEntitlements(target.Name, configurationName)
		if err != nil && !serialized.IsKeyNotFoundError(err) {
			return nil, fmt.Errorf("Failed to get target (%s) bundle id: %s", target.Name, err)
		}

		entitlementsByBundleID[bundleID] = entitlements
	}

	return toMapStringPlistData(entitlementsByBundleID), nil
}

func toMapStringPlistData(object map[string]serialized.Object) map[string]plistutil.PlistData {
	converted := map[string]plistutil.PlistData{}
	for key, value := range object {
		converted[key] = plistutil.PlistData(value)
	}
	return converted
}
<|endoftext|>


<commit_before>package packetio

import (
	"bufio"
	"encoding/binary"
	"errors"
	"io"
)

// Marshaler is an interface for encoding objects that is compatible with gogoprotobuf.
type Marshaler interface {
	Size() int
	MarshalTo([]byte) (int, error)
}

// Unmarshaler is an interface for decoding objects that is compatible with gogoprotobuf.
type Unmarshaler interface {
	Unmarshal(data []byte) error
}

const packetWriterExtra = 8

// PacketWriter writes packets that are Marshalers into a io.Writer.
type PacketWriter struct {
	w   io.Writer
	tmp []byte
}

// Init initializes a PacketWriter with the destination io.Writer.
func (pw *PacketWriter) Init(w io.Writer) {
	pw.w = w
}

// WritePacket writes the Marshaller to the destination with a length prefix and
// a single byte type field.
func (pw *PacketWriter) WritePacket(packetType byte, msg Marshaler) (int, error) {
	siz := msg.Size()
	if siz+packetWriterExtra > len(pw.tmp) {
		freeiobuffer(pw.tmp)
		pw.tmp = newiobuffer(siz + packetWriterExtra)
	}
	n, e := msg.MarshalTo(pw.tmp[packetWriterExtra:])
	if e != nil {
		return 0, e
	}

	if n > 0xFFffFF {
		return 0, errors.New("WritePacket: too large packet")
	}

	binary.BigEndian.PutUint32(pw.tmp[4:], uint32(n))
	pw.tmp[4] = packetType

	buf := pw.tmp[4 : packetWriterExtra+n]
	wn, e := pw.w.Write(buf)
	return wn, e
}

// PacketReader is for decoding values encoded with PacketWriter from an io.Reader.
type PacketReader struct {
	br    *bufio.Reader
	umarr []Unmarshaler
	tmp   []byte
	b0    [4]byte
}

// Init initializes the PacketReader with the source io.Reader and a slice
// of Unmarshaler values, with each index used to decode values of that
// packetType. Nil-values are permitted, and if the type is out of range
// or the corresponding Unmarshaller is nil an error is returned.
func (pr *PacketReader) Init(rd io.Reader, uvs []Unmarshaler) {
	pr.br = bufio.NewReader(rd)
	pr.umarr = uvs
}

// ReadPacket reads a packet from the stream using the unmarshallers
// passed to Init. Note that the Unmarshaler itself is used for decoding
// and returned rather than making a copy.
func (pr *PacketReader) ReadPacket() (Unmarshaler, error) {
	buf := pr.b0[:]
	_, e := io.ReadFull(pr.br, buf)
	if e != nil {
		return nil, e
	}
	st := int(buf[0])
	buf[0] = 0
	next := int(binary.BigEndian.Uint32(buf))
	if st > len(pr.umarr) || pr.umarr[st] == nil {
		return nil, errors.New("No unmarshaller for type")
	}
	if next > len(pr.tmp) {
		freeiobuffer(pr.tmp)
		pr.tmp = newiobuffer(next)
	}
	_, e = io.ReadFull(pr.br, pr.tmp[:next])
	if e != nil {
		return nil, e
	}
	res := pr.umarr[st]
	res.Unmarshal(pr.tmp)
	return res, nil
}

func freeiobuffer([]byte) {}
func newiobuffer(size int) []byte {
	if size < 8*1024 {
		size = 8 * 1024
	}
	return make([]byte, size)
}
<commit_msg>Package comment<commit_after>/*Package packetio provides length delimeted typed serialization compatible with protobuf.

packetio provides an easy way to delimit messages with length and a type. This makes
serializing e.g. protobuf (gogoprotobuf) messages much easier. No dependency on
protobuf however.

*/
package packetio

import (
	"bufio"
	"encoding/binary"
	"errors"
	"io"
)

// Marshaler is an interface for encoding objects that is compatible with gogoprotobuf.
type Marshaler interface {
	Size() int
	MarshalTo([]byte) (int, error)
}

// Unmarshaler is an interface for decoding objects that is compatible with gogoprotobuf.
type Unmarshaler interface {
	Unmarshal(data []byte) error
}

const packetWriterExtra = 8

// PacketWriter writes packets that are Marshalers into a io.Writer.
type PacketWriter struct {
	w   io.Writer
	tmp []byte
}

// Init initializes a PacketWriter with the destination io.Writer.
func (pw *PacketWriter) Init(w io.Writer) {
	pw.w = w
}

// WritePacket writes the Marshaller to the destination with a length prefix and
// a single byte type field.
func (pw *PacketWriter) WritePacket(packetType byte, msg Marshaler) (int, error) {
	siz := msg.Size()
	if siz+packetWriterExtra > len(pw.tmp) {
		freeiobuffer(pw.tmp)
		pw.tmp = newiobuffer(siz + packetWriterExtra)
	}
	n, e := msg.MarshalTo(pw.tmp[packetWriterExtra:])
	if e != nil {
		return 0, e
	}

	if n > 0xFFffFF {
		return 0, errors.New("WritePacket: too large packet")
	}

	binary.BigEndian.PutUint32(pw.tmp[4:], uint32(n))
	pw.tmp[4] = packetType

	buf := pw.tmp[4 : packetWriterExtra+n]
	wn, e := pw.w.Write(buf)
	return wn, e
}

// PacketReader is for decoding values encoded with PacketWriter from an io.Reader.
type PacketReader struct {
	br    *bufio.Reader
	umarr []Unmarshaler
	tmp   []byte
	b0    [4]byte
}

// Init initializes the PacketReader with the source io.Reader and a slice
// of Unmarshaler values, with each index used to decode values of that
// packetType. Nil-values are permitted, and if the type is out of range
// or the corresponding Unmarshaller is nil an error is returned.
func (pr *PacketReader) Init(rd io.Reader, uvs []Unmarshaler) {
	pr.br = bufio.NewReader(rd)
	pr.umarr = uvs
}

// ReadPacket reads a packet from the stream using the unmarshallers
// passed to Init. Note that the Unmarshaler itself is used for decoding
// and returned rather than making a copy.
func (pr *PacketReader) ReadPacket() (Unmarshaler, error) {
	buf := pr.b0[:]
	_, e := io.ReadFull(pr.br, buf)
	if e != nil {
		return nil, e
	}
	st := int(buf[0])
	buf[0] = 0
	next := int(binary.BigEndian.Uint32(buf))
	if st > len(pr.umarr) || pr.umarr[st] == nil {
		return nil, errors.New("No unmarshaller for type")
	}
	if next > len(pr.tmp) {
		freeiobuffer(pr.tmp)
		pr.tmp = newiobuffer(next)
	}
	_, e = io.ReadFull(pr.br, pr.tmp[:next])
	if e != nil {
		return nil, e
	}
	res := pr.umarr[st]
	res.Unmarshal(pr.tmp)
	return res, nil
}

func freeiobuffer([]byte) {}
func newiobuffer(size int) []byte {
	if size < 8*1024 {
		size = 8 * 1024
	}
	return make([]byte, size)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"
	"fmt"

	"github.com/williambailey/pacproxy/pac"
)

// Name of the app
const Name = "pacproxy"

// Version of the app
const Version = "2.0.1"

var (
	fPac     string
	fListen  string
	fVerbose bool
)

func init() {
	flag.StringVar(&fPac, "c", "", "PAC file name, url or javascript to use (required)")
	flag.StringVar(&fListen, "l", "127.0.0.1:8080", "Interface and port to listen on")
	flag.BoolVar(&fVerbose, "v", false, "send verbose output to STDERR")
}

func main() {
	required := []string{"c"}
      	flag.Parse()

	seen := make(map[string]bool)
	flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
        for _, req := range required {
	    if !seen[req] {
	        fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
	        os.Exit(2) // the same exit code flag.Parse uses
	    }
        }

	if fVerbose {
		log.SetOutput(os.Stderr)
	} else {
		log.SetOutput(ioutil.Discard)
	}
	log.SetPrefix("")
	log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile | log.LUTC)
	log.Printf("Starting %s v%s", Name, Version)

	otto := pac.NewOttoEngine(
		pac.OttoLoader(pac.SmartLoader(fPac)),
	)
	if err := otto.Start(); err != nil {
		log.Panic(err)
	}
	defer otto.Stop()

	initSignalNotify(otto)

	srv := &http.Server{
		Addr:              fListen,
		ReadHeaderTimeout: 2 * time.Second,
		IdleTimeout:       60 * time.Second,
		Handler: newProxyHTTPHandler(
			otto,
			&pac.FirstItemSelector{},
			newNonProxyHTTPHandler(),
		),
	}
	log.Printf("Listening on %q", fListen)
	if err := srv.ListenAndServe(); err != nil {
		log.Panic(err)
	}
}
<commit_msg>Check for empty -c flag<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/williambailey/pacproxy/pac"
)

// Name of the app
const Name = "pacproxy"

// Version of the app
const Version = "2.0.1"

var (
	fPac     string
	fListen  string
	fVerbose bool
)

func init() {
	flag.StringVar(&fPac, "c", "", "PAC file name, url or javascript to use (required)")
	flag.StringVar(&fListen, "l", "127.0.0.1:8080", "Interface and port to listen on")
	flag.BoolVar(&fVerbose, "v", false, "send verbose output to STDERR")
}

func main() {
	flag.Parse()

	seen := make(map[string]bool)
	flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
	required := []string{"c"}
	for _, req := range required {
		if !seen[req] {
			exitWithUsage(fmt.Sprintf("Missing required flag -%s", req))
		}
	}
	if strings.TrimSpace(fPac) == "" {
		exitWithUsage("Unexpected empty value for -c")
	}

	if fVerbose {
		log.SetOutput(os.Stderr)
	} else {
		log.SetOutput(ioutil.Discard)
	}
	log.SetPrefix("")
	log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile | log.LUTC)
	log.Printf("Starting %s v%s", Name, Version)

	otto := pac.NewOttoEngine(
		pac.OttoLoader(pac.SmartLoader(fPac)),
	)
	if err := otto.Start(); err != nil {
		log.Panic(err)
	}
	defer otto.Stop()

	initSignalNotify(otto)

	srv := &http.Server{
		Addr:              fListen,
		ReadHeaderTimeout: 2 * time.Second,
		IdleTimeout:       60 * time.Second,
		Handler: newProxyHTTPHandler(
			otto,
			&pac.FirstItemSelector{},
			newNonProxyHTTPHandler(),
		),
	}
	log.Printf("Listening on %q", fListen)
	if err := srv.ListenAndServe(); err != nil {
		log.Panic(err)
	}
}

func exitWithUsage(message string) {
	os.Stderr.WriteString(message)
	os.Stderr.WriteString("\n")
	flag.Usage()
	os.Exit(2) // the same exit code flag.Parse uses
}
<|endoftext|>


<commit_before>package relay

import (
	"context"
	"fmt"
	"math/rand"

	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/transport"
	ma "github.com/multiformats/go-multiaddr"
)

func (d *RelayTransport) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) {
	c, err := d.Relay().Dial(ctx, a, p)
	if err != nil {
		return nil, err
	}
	c.tagHop()
	return d.upgrader.UpgradeOutbound(ctx, d, c, p)
}

func (r *Relay) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (*Conn, error) {
	if !r.Matches(a) {
		return nil, fmt.Errorf("%s is not a relay address", a)
	}
	parts := ma.Split(a)

	spl := ma.Cast(ma.CodeToVarint(P_CIRCUIT))

	var relayaddr, destaddr ma.Multiaddr
	for i, p := range parts {
		if p.Equal(spl) {
			relayaddr = ma.Join(parts[:i]...)
			destaddr = ma.Join(parts[i+1:]...)
			break
		}
	}

	dinfo := &peer.AddrInfo{ID: p, Addrs: []ma.Multiaddr{}}
	if len(destaddr.Bytes()) > 0 {
		dinfo.Addrs = append(dinfo.Addrs, destaddr)
	}

	if len(relayaddr.Bytes()) == 0 {
		// unspecific relay address, try dialing using known hop relays
		return r.tryDialRelays(ctx, *dinfo)
	}

	var rinfo *peer.AddrInfo
	rinfo, err := peer.AddrInfoFromP2pAddr(relayaddr)
	if err != nil {
		return nil, fmt.Errorf("error parsing multiaddr '%s': %s", relayaddr.String(), err)
	}

	return r.DialPeer(ctx, *rinfo, *dinfo)
}

func (r *Relay) tryDialRelays(ctx context.Context, dinfo peer.AddrInfo) (*Conn, error) {
	var relays []peer.ID
	r.mx.Lock()
	for p := range r.relays {
		relays = append(relays, p)
	}
	r.mx.Unlock()

	// shuffle list of relays, avoid overloading a specific relay
	for i := range relays {
		j := rand.Intn(i + 1)
		relays[i], relays[j] = relays[j], relays[i]
	}

	for _, relay := range relays {
		if len(r.host.Network().ConnsToPeer(relay)) == 0 {
			continue
		}

		rctx, cancel := context.WithTimeout(ctx, HopConnectTimeout)
		c, err := r.DialPeer(rctx, peer.AddrInfo{ID: relay}, dinfo)
		cancel()

		if err == nil {
			return c, nil
		}

		log.Debugf("error opening relay connection through %s: %s", dinfo.ID, err.Error())
	}

	return nil, fmt.Errorf("Failed to dial through %d known relay hosts", len(relays))
}
<commit_msg>chore: better address parsing<commit_after>package relay

import (
	"context"
	"fmt"
	"math/rand"

	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/transport"
	ma "github.com/multiformats/go-multiaddr"
)

func (d *RelayTransport) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) {
	c, err := d.Relay().Dial(ctx, a, p)
	if err != nil {
		return nil, err
	}
	c.tagHop()
	return d.upgrader.UpgradeOutbound(ctx, d, c, p)
}

func (r *Relay) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (*Conn, error) {
	// split /a/p2p-circuit/b into (/a, /p2p-circuit/b)
	relayaddr, destaddr := ma.SplitFunc(a, func(c ma.Component) bool {
		return c.Protocol().Code == P_CIRCUIT
	})

	// If the address contained no /p2p-circuit part, the second part is nil.
	if destaddr == nil {
		return nil, fmt.Errorf("%s is not a relay address", a)
	}

	// Strip the /p2p-circuit prefix from the destaddr.
	_, destaddr = ma.SplitFirst(destaddr)

	dinfo := &peer.AddrInfo{ID: p, Addrs: []ma.Multiaddr{}}
	if destaddr != nil {
		dinfo.Addrs = append(dinfo.Addrs, destaddr)
	}

	if relayaddr == nil {
		// unspecific relay address, try dialing using known hop relays
		return r.tryDialRelays(ctx, *dinfo)
	}

	var rinfo *peer.AddrInfo
	rinfo, err := peer.AddrInfoFromP2pAddr(relayaddr)
	if err != nil {
		return nil, fmt.Errorf("error parsing multiaddr '%s': %s", relayaddr.String(), err)
	}

	return r.DialPeer(ctx, *rinfo, *dinfo)
}

func (r *Relay) tryDialRelays(ctx context.Context, dinfo peer.AddrInfo) (*Conn, error) {
	var relays []peer.ID
	r.mx.Lock()
	for p := range r.relays {
		relays = append(relays, p)
	}
	r.mx.Unlock()

	// shuffle list of relays, avoid overloading a specific relay
	for i := range relays {
		j := rand.Intn(i + 1)
		relays[i], relays[j] = relays[j], relays[i]
	}

	for _, relay := range relays {
		if len(r.host.Network().ConnsToPeer(relay)) == 0 {
			continue
		}

		rctx, cancel := context.WithTimeout(ctx, HopConnectTimeout)
		c, err := r.DialPeer(rctx, peer.AddrInfo{ID: relay}, dinfo)
		cancel()

		if err == nil {
			return c, nil
		}

		log.Debugf("error opening relay connection through %s: %s", dinfo.ID, err.Error())
	}

	return nil, fmt.Errorf("Failed to dial through %d known relay hosts", len(relays))
}
<|endoftext|>


<commit_before>package utils

import (
	"fmt"
	"math"
	"strconv"
)

func Atoi32(s string) (int32, error) {
	res, err := strconv.Atoi(s)
	if err != nil {
		return 0, nil
	}
	if res > math.MaxInt32 {
		return 0, fmt.Errorf("int32 overflow")
	}
	return int32(res), nil
}
<commit_msg>time <-> bytes conversions<commit_after>package utils

import (
	"encoding/binary"
	"fmt"
	"math"
	"strconv"
	"time"
)

func Atoi32(s string) (int32, error) {
	res, err := strconv.Atoi(s)
	if err != nil {
		return 0, nil
	}
	if res > math.MaxInt32 {
		return 0, fmt.Errorf("int32 overflow")
	}
	return int32(res), nil
}

func Time2Bytes(t time.Time, dst []byte) []byte {
	if cap(dst) < binary.MaxVarintLen32 {
		dst = make([]byte, binary.MaxVarintLen32)
	}
	dst = dst[:binary.MaxVarintLen32]
	n := binary.PutVarint(dst, t.UnixNano())
	return dst[:n]
}

func Bytes2Time(b []byte) (time.Time, int) {
	var ts time.Time
	t, n := binary.Varint(b)
	if n <= 0 {
		return ts, n
	}
	return time.Unix(0, t), n
}
<|endoftext|>


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

// Benchmany runs Go benchmarks across many git commits.
//
// Usage:
//
//	benchmany run [-C git-dir] [-n iterations] <commit or range>...
//
//      benchmany plot [-C git-dir] <commit or range>...
//
//      benchmany list [-C git-dir] <commit or range>...
//
// run
//
// "benchmany run" runs the benchmarks in the current directory
// <iterations> times for each commit in <commit or range> and writes
// the benchmark results to log.<commit hash>. Benchmarks may be Go
// testing framework benchmarks or benchmarks from
// golang.org/x/benchmarks.
//
// <commit or range>... can be either a list of individual commits or
// a revision range. For the spelling of a revision range, see
// "SPECIFYING RANGES" in gitrevisions(7). For exact details, see the
// --no-walk option to git-rev-list(1).
//
// Benchmany will check out each revision in git-dir. The current
// directory may or may not be in the same git repository as git-dir.
// If git-dir refers to a Go installation, benchmany will run
// make.bash at each revision; otherwise, it assumes go test can
// rebuild the necessary dependencies.
//
// Benchmany is safe to interrupt. If it is restarted, it will parse
// the benchmark log files to recover its state.
//
// Benchmany supports multiple ways of prioritizing the order in which
// individual iterations are run. By default, it runs in "sequential"
// mode: it runs the first iteration of all benchmarks, then the
// second, and so forth. It also supports a "spread" mode designed to
// quickly get coverage for large sets of revisions. This mode
// randomizes the order to run iterations in, but biases this order
// toward covering an evenly distributed set of revisions early and
// finishing all of the iterations of the revisions it has started on
// before moving on to new revisions. This way, if benchmany is
// interrupted, the revisions benchmarked cover the space more-or-less
// evenly. Finally, it supports a "metric" mode, which zeroes in on
// changes in a benchmark metric by selecting the commit half way
// between the pair of commits with the biggest difference in the
// metric. This is like "git bisect", but for performance.
//
// plot
//
// "benchmany plot" reads the benchmark logs generated by "benchmany
// run" for the given <commit or range> and outputs tables that can be
// used to plot these benchmarks over time.
//
// list
//
// "benchmany list" prints a list of log file names generated by
// "benchmany run" for the given <commit or range>. By default, logs
// are listed from oldest to newest revision. This is useful as input
// to comparison tools like http://rsc.io/benchstat.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

var gitDir string
var dryRun bool

// maxFails is the maximum number of benchmark run failures to
// tolerate for a commit before giving up on trying to benchmark that
// commit. Build failures always disqualify a commit.
const maxFails = 5

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <subcommand> <args...>\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Subcommands:\n")
		for _, sub := range subcommands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", sub.name, sub.desc)
		}
		fmt.Fprintf(os.Stderr, "See %s <subcommand> -h for details.\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() < 1 || subcommands[flag.Arg(0)] == nil {
		flag.Usage()
		os.Exit(2)
	}

	sub := subcommands[flag.Arg(0)]
	sub.flags.Parse(flag.Args()[1:])
	sub.cmd()
}

type subcommand struct {
	name, desc string
	cmd        func()
	flags      *flag.FlagSet
}

var subcommands = make(map[string]*subcommand)

func registerSubcommand(name, desc string, cmd func(), flags *flag.FlagSet) {
	subcommands[name] = &subcommand{name, desc, cmd, flags}
}

// git runs git subcommand subcmd and returns its stdout. If git
// fails, it prints the failure and exits.
func git(subcmd string, args ...string) string {
	gitargs := []string{}
	if gitDir != "" {
		gitargs = append(gitargs, "-C", gitDir)
	}
	gitargs = append(gitargs, subcmd)
	gitargs = append(gitargs, args...)
	cmd := exec.Command("git", gitargs...)
	cmd.Stderr = os.Stderr
	if dryRun {
		dryPrint(cmd)
		if !(subcmd == "rev-parse" || subcmd == "rev-list" || subcmd == "show") {
			return ""
		}
	}
	out, err := cmd.Output()
	if err != nil {
		fmt.Fprintf(os.Stderr, "git %s failed: %s\n", shellEscapeList(gitargs), err)
		os.Exit(1)
	}
	return string(out)
}

func dryPrint(cmd *exec.Cmd) {
	out := shellEscape(cmd.Path)
	for _, a := range cmd.Args[1:] {
		out += " " + shellEscape(a)
	}
	if cmd.Dir != "" {
		out = fmt.Sprintf("(cd %s && %s)", shellEscape(cmd.Dir), out)
	}
	fmt.Fprintln(os.Stderr, out)
}

func shellEscape(x string) string {
	if len(x) == 0 {
		return "''"
	}
	for _, r := range x {
		if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || strings.ContainsRune("@%_-+:,./", r) {
			continue
		}
		// Unsafe character.
		return "'" + strings.Replace(x, "'", "'\"'\"'", -1) + "'"
	}
	return x
}

func shellEscapeList(xs []string) string {
	out := make([]string, len(xs))
	for i, x := range xs {
		out[i] = shellEscape(x)
	}
	return strings.Join(out, " ")
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func trimNL(s string) string {
	return strings.TrimRight(s, "\n")
}

// indent returns s with each line indented by four spaces. If s is
// non-empty, the returned string is guaranteed to end in a "\n".
func indent(s string) string {
	if len(s) == 0 {
		return s
	}
	if strings.HasSuffix(s, "\n") {
		s = s[:len(s)-1]
	}
	return "    " + strings.Replace(s, "\n", "\n    ", -1) + "\n"
}

// lines splits s in to lines. It omits a final blank line, if any.
func lines(s string) []string {
	l := strings.Split(s, "\n")
	if len(l) > 0 && l[len(l)-1] == "" {
		l = l[:len(l)-1]
	}
	return l
}
<commit_msg>benchmany: improve command doc<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Benchmany runs Go benchmarks across many git commits.
//
// Usage:
//
//      benchmany run [-C git-dir] [-n iterations] <commit or range>...
//
//      benchmany plot [-C git-dir] <commit or range>...
//
//      benchmany list [-C git-dir] <commit or range>...
//
// Run subcommand
//
// "benchmany run" runs the benchmarks in the current directory
// <iterations> times for each commit in <commit or range> and writes
// the benchmark results to log.<commit hash>. Benchmarks may be Go
// testing framework benchmarks or benchmarks from
// golang.org/x/benchmarks.
//
// <commit or range>... can be either a list of individual commits or
// a revision range. For the spelling of a revision range, see
// "SPECIFYING RANGES" in gitrevisions(7). For exact details, see the
// --no-walk option to git-rev-list(1).
//
// Benchmany will check out each revision in git-dir. The current
// directory may or may not be in the same git repository as git-dir.
// If git-dir refers to a Go installation, benchmany will run
// make.bash at each revision; otherwise, it assumes go test can
// rebuild the necessary dependencies. Benchmany also supports using
// gover (https://godoc.org/github.com/aclements/go-misc/gover) to
// save and reuse Go build trees. This is useful for saving time
// across multiple benchmark runs and for benchmarks that depend on
// the Go tree itself (such as compiler benchmarks).
//
// Benchmany supports multiple ways of prioritizing the order in which
// individual iterations are run. By default, it runs in "sequential"
// mode: it runs the first iteration of all benchmarks, then the
// second, and so forth. It also supports a "spread" mode designed to
// quickly get coverage for large sets of revisions. This mode
// randomizes the order to run iterations in, but biases this order
// toward covering an evenly distributed set of revisions early and
// finishing all of the iterations of the revisions it has started on
// before moving on to new revisions. This way, if benchmany is
// interrupted, the revisions benchmarked cover the space more-or-less
// evenly. Finally, it supports a "metric" mode, which zeroes in on
// changes in a benchmark metric by selecting the commit half way
// between the pair of commits with the biggest difference in the
// metric. This is like "git bisect", but for performance.
//
// Benchmany is safe to interrupt. If it is restarted, it will parse
// the benchmark log files to recover its state.
//
// Plot subcommand
//
// "benchmany plot" reads the benchmark logs generated by "benchmany
// run" for the given <commit or range> and plots the results of
// benchmarks over time.
//
// Plot supports various output formats. By default, it outputs a text
// table that can be used as input to most plotting programs. The
// -html option produces a Google Charts page that can be used to
// interactively view benchmark results.
//
// Plot supports a -filter flag that reduces noise in benchmark
// results using an adaptive Kolmogorov-Zurbenko (KZA) low-pass
// filter. This filter retains sharp changes in performance, so you
// can see exactly when significant changes happened, while smoothing
// out transient noise.
//
// Plot supports normalizing results to a baseline using the -baseline
// flag. This is useful when looking for relative changes, or when
// plotting many different benchmarks that may have wildly different
// expected results.
//
// List subcommand
//
// "benchmany list" prints a list of log file names generated by
// "benchmany run" for the given <commit or range>. By default, logs
// are listed from oldest to newest revision. This is useful as input
// to comparison tools like http://rsc.io/benchstat.
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

var gitDir string
var dryRun bool

// maxFails is the maximum number of benchmark run failures to
// tolerate for a commit before giving up on trying to benchmark that
// commit. Build failures always disqualify a commit.
const maxFails = 5

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <subcommand> <args...>\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Subcommands:\n")
		for _, sub := range subcommands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", sub.name, sub.desc)
		}
		fmt.Fprintf(os.Stderr, "See %s <subcommand> -h for details.\n", os.Args[0])
	}
	flag.Parse()
	if flag.NArg() < 1 || subcommands[flag.Arg(0)] == nil {
		flag.Usage()
		os.Exit(2)
	}

	sub := subcommands[flag.Arg(0)]
	sub.flags.Parse(flag.Args()[1:])
	sub.cmd()
}

type subcommand struct {
	name, desc string
	cmd        func()
	flags      *flag.FlagSet
}

var subcommands = make(map[string]*subcommand)

func registerSubcommand(name, desc string, cmd func(), flags *flag.FlagSet) {
	subcommands[name] = &subcommand{name, desc, cmd, flags}
}

// git runs git subcommand subcmd and returns its stdout. If git
// fails, it prints the failure and exits.
func git(subcmd string, args ...string) string {
	gitargs := []string{}
	if gitDir != "" {
		gitargs = append(gitargs, "-C", gitDir)
	}
	gitargs = append(gitargs, subcmd)
	gitargs = append(gitargs, args...)
	cmd := exec.Command("git", gitargs...)
	cmd.Stderr = os.Stderr
	if dryRun {
		dryPrint(cmd)
		if !(subcmd == "rev-parse" || subcmd == "rev-list" || subcmd == "show") {
			return ""
		}
	}
	out, err := cmd.Output()
	if err != nil {
		fmt.Fprintf(os.Stderr, "git %s failed: %s\n", shellEscapeList(gitargs), err)
		os.Exit(1)
	}
	return string(out)
}

func dryPrint(cmd *exec.Cmd) {
	out := shellEscape(cmd.Path)
	for _, a := range cmd.Args[1:] {
		out += " " + shellEscape(a)
	}
	if cmd.Dir != "" {
		out = fmt.Sprintf("(cd %s && %s)", shellEscape(cmd.Dir), out)
	}
	fmt.Fprintln(os.Stderr, out)
}

func shellEscape(x string) string {
	if len(x) == 0 {
		return "''"
	}
	for _, r := range x {
		if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || strings.ContainsRune("@%_-+:,./", r) {
			continue
		}
		// Unsafe character.
		return "'" + strings.Replace(x, "'", "'\"'\"'", -1) + "'"
	}
	return x
}

func shellEscapeList(xs []string) string {
	out := make([]string, len(xs))
	for i, x := range xs {
		out[i] = shellEscape(x)
	}
	return strings.Join(out, " ")
}

func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func trimNL(s string) string {
	return strings.TrimRight(s, "\n")
}

// indent returns s with each line indented by four spaces. If s is
// non-empty, the returned string is guaranteed to end in a "\n".
func indent(s string) string {
	if len(s) == 0 {
		return s
	}
	if strings.HasSuffix(s, "\n") {
		s = s[:len(s)-1]
	}
	return "    " + strings.Replace(s, "\n", "\n    ", -1) + "\n"
}

// lines splits s in to lines. It omits a final blank line, if any.
func lines(s string) []string {
	l := strings.Split(s, "\n")
	if len(l) > 0 && l[len(l)-1] == "" {
		l = l[:len(l)-1]
	}
	return l
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/util/configv3"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Config", func() {
	Describe("Version Management", func() {
		var oldTarget string
		var oldVersion int
		var oldSkipSSLValidation bool

		BeforeEach(func() {
			config := helpers.GetConfig()
			oldTarget = config.Target()
			oldVersion = config.ConfigFile.ConfigVersion
			oldSkipSSLValidation = config.ConfigFile.SkipSSLValidation

		})

		It("reset config to default if version mismatch", func() {
			helpers.SetConfig(func(config *configv3.Config) {
				config.ConfigFile.ConfigVersion = configv3.CurrentConfigVersion - 1
				config.ConfigFile.Target = "api.my-target"
			})
			helpers.LoginCF()
			config := helpers.GetConfig()
			Expect(config.ConfigFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion))
			Expect(config.ConfigFile.Target).To(Equal(""))
			helpers.SetConfig(func(config *configv3.Config) {
				config.ConfigFile.ConfigVersion = oldVersion
				config.ConfigFile.Target = oldTarget
				config.ConfigFile.SkipSSLValidation = oldSkipSSLValidation
			})
		})
	})
})
<commit_msg>Fix config test for client credentials<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/util/configv3"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Config", func() {
	Describe("Version Management", func() {
		It("reset config to default if version mismatch", func() {
			helpers.SetConfig(func(config *configv3.Config) {
				config.ConfigFile.ConfigVersion = configv3.CurrentConfigVersion - 1
				config.ConfigFile.Target = "api.my-target"
			})
			helpers.CF("plugins")
			config := helpers.GetConfig()
			Expect(config.ConfigFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion))
			Expect(config.ConfigFile.Target).To(Equal(""))
		})
	})
})
<|endoftext|>


<commit_before>package sorter

import (
	"fmt"
	"testing"
)

// TestMergeSort generates array with 8 elements and checks if orders correctly or not
func TestMergeSort(t *testing.T) {
	generatedArr, err := GenerateArray(8)
	if err != nil {
		t.Fatal(err.Error())
	}

	arr := MergeSort(generatedArr)
	b, err := IsSorted(arr)
	if err != nil {
		t.Fatal(err.Error())
	}

	if !b {
		fmt.Println("Array is not sorted")
		return
	}
}

func TestMergeSortParallel(t *testing.T) {
	tests := []struct {
		arraySize int
		isSorted  bool
		err       error
	}{
		{0, false, ErrArrayNoLength},
		{1, true, nil},
		{2, true, nil},
		{3, true, nil},
		{4, true, nil},
		{10, true, nil},
	}

	for _, test := range tests {
		test := test // capture variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			arr, err := GenerateArray(test.arraySize)
			if err != test.err {
				t.Fatalf("error should be: %v, but got: %v", test.err, err)
			}

			if len(arr) != test.arraySize {
				t.Fatalf("array length should equal: %v, but got: %v", test.arraySize, len(arr))
			}

			sorted, err := IsSorted(MergeSort(arr))
			if err != nil {
				t.Fatalf("error should be nil, but got:%v", err)
			}
			if !sorted {
				t.Fatalf("array should be sorted:%v", sorted)
			}
		})
	}
}
<commit_msg>tests: add comment to satisfy golint<commit_after>package sorter

import (
	"fmt"
	"testing"
)

// TestMergeSort generates array with 8 elements and checks if orders correctly or not
func TestMergeSort(t *testing.T) {
	generatedArr, err := GenerateArray(8)
	if err != nil {
		t.Fatal(err.Error())
	}

	arr := MergeSort(generatedArr)
	b, err := IsSorted(arr)
	if err != nil {
		t.Fatal(err.Error())
	}

	if !b {
		fmt.Println("Array is not sorted")
		return
	}
}

// TestMergeSortParallel tests the given arrays if sorted or not
// with parallelization
func TestMergeSortParallel(t *testing.T) {
	tests := []struct {
		arraySize int
		isSorted  bool
		err       error
	}{
		{0, false, ErrArrayNoLength},
		{1, true, nil},
		{2, true, nil},
		{3, true, nil},
		{4, true, nil},
		{10, true, nil},
	}

	for _, test := range tests {
		test := test // capture variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			arr, err := GenerateArray(test.arraySize)
			if err != test.err {
				t.Fatalf("error should be: %v, but got: %v", test.err, err)
			}

			if len(arr) != test.arraySize {
				t.Fatalf("array length should equal: %v, but got: %v", test.arraySize, len(arr))
			}

			sorted, err := IsSorted(MergeSort(arr))
			if err != nil {
				t.Fatalf("error should be nil, but got:%v", err)
			}
			if !sorted {
				t.Fatalf("array should be sorted:%v", sorted)
			}
		})
	}
}
<|endoftext|>


<commit_before>package broker

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/streadway/amqp"
	"labix.org/v2/mgo"
)

type Handler interface {
	HandleEvent(string, []byte) error
	ErrHandler
}

type ErrHandler interface {
	// bool is whether publishing the message to maintenance qeueue or not
	DefaultErrHandler(amqp.Delivery, error) bool
}

func (c *Consumer) withMetrics(handler *SubscriptionHandler, delivery amqp.Delivery) error {
	// if metrics is not enabled just invoke the function
	if c.Metrics == nil {
		return handler.HandleEvent(c.contextValue, delivery.Body)
	}

	c.Metrics.GetCounter("message").Inc(1)

	var err error

	c.Metrics.GetTimer(delivery.Type).Time(func() {
		err = handler.HandleEvent(c.contextValue, delivery.Body)
	})

	return err
}

func (c *Consumer) withCounter(counterName string, fn func()) {
	if c.Metrics == nil {
		fn()
	}

	c.Metrics.GetCounter(counterName).Inc(1)
	fn()
}

func (c *Consumer) Start() func(delivery amqp.Delivery) {
	c.Log.Info("Broker sarted to consume")
	return func(delivery amqp.Delivery) {
		if _, ok := c.handlers[delivery.Type]; !ok {
			// if no handler found, just ack message
			c.Log.Debug("No handler for %s", delivery.Type)
			c.withCounter("nohandlerforevent", func() { delivery.Ack(false) })
			return
		}

		go func() {
			var err error
			for _, handler := range c.handlers[delivery.Type] {
				// do not continue, if one of the handler gives error
				if err != nil {
					break
				}

				err = c.withMetrics(handler, delivery)
			}
			c.handleError(err, delivery)
		}()

	}
}

func (c *Consumer) handleError(err error, delivery amqp.Delivery) {
	switch err {
	case nil:
		c.withCounter("success", func() { delivery.Ack(false) })
	case ErrNoHandlerFound:
		c.withCounter("handlernotfound", func() { delivery.Ack(false) })
		c.Log.Debug("unknown event type (%s) recieved, deleting message from RMQ", delivery.Type)
	case gorm.RecordNotFound:
		c.withCounter("gormrecordnotfound", func() { delivery.Ack(false) })
		c.Log.Warning("Record not found in our db (%s) recieved, deleting message from RMQ", string(delivery.Body))
	case mgo.ErrNotFound:
		c.withCounter("mgorecordnotfound", func() { delivery.Ack(false) })
		c.Log.Warning("Record not found in our mongo db (%s) recieved, deleting message from RMQ", string(delivery.Body))
	default:
		c.withCounter("othererror", func() {
			// default err handler should handle the ack process
			if c.context.DefaultErrHandler(delivery, err) {
				if c.MaintenancePublisher == nil {
					return
				}

				data, err := json.Marshal(delivery)
				if err != nil {
					return
				}

				msg := amqp.Publishing{
					Body:  []byte(data),
					AppId: c.WorkerName,
				}

				c.withCounter("publishedtomaintenancequeue", func() {
					c.MaintenancePublisher.Publish(msg)
				})
			}
		})
	}
}

type SubscriptionHandler struct {
	v reflect.Value
}

func NewSubscriptionHandler(i interface{}) (*SubscriptionHandler, error) {
	t := reflect.TypeOf(i)
	if t.Kind() != reflect.Func {
		return nil, fmt.Errorf("kind was %v, not Func", t.Kind())
	}

	// check input parameter count
	if t.NumIn() != 2 {
		return nil, fmt.Errorf("input arity was %v, not 2", t.NumIn())
	}

	// check output parameter count
	if t.NumOut() != 1 {
		return nil, fmt.Errorf("output arity was %v, not 1", t.NumOut())
	}

	// output should be errors
	if t.Out(0).String() != "error" {
		return nil, fmt.Errorf("type of return value was %v, not error", t.Out(0))
	}

	return &SubscriptionHandler{reflect.ValueOf(i)}, nil
}

var nilParameter = reflect.ValueOf((*interface{})(nil))

func (m *SubscriptionHandler) HandleEvent(controllerValue reflect.Value, data []byte) error {
	var parameter reflect.Value

	if m.v.Type().NumIn() == 2 {
		in2 := m.v.Type().In(1)
		// if incoming paramter is an empty interface
		if reflect.Interface == in2.Kind() && in2.NumMethod() == 0 {
			parameter = nilParameter
			// if incoming parameter is a slice or a map
		} else if reflect.Slice == in2.Kind() || reflect.Map == in2.Kind() {
			// non-pointer maps/slices require special treatment because
			// json.Unmarshal won't work on a non-pointer destination. We
			// add a level indirection here, then deref it before .Call()
			parameter = reflect.New(in2)
		} else {
			// if it is a struct
			parameter = reflect.New(in2.Elem())
		}
	} else {
		// if handler doesnt have any incoming paramters
		parameter = nilParameter
	}

	// this is where magic happens:)
	// first read incoming []byte data into a io.reader then
	// put this data into a decoder(create a decoder out of it)
	// finally decode this data into given
	decoder := reflect.ValueOf(json.NewDecoder(bytes.NewReader(data)))
	res := decoder.MethodByName("Decode").Call([]reflect.Value{parameter})
	if len(res) > 0 && !res[0].IsNil() {
		return res[0].Interface().(error)
	}

	if reflect.Slice == parameter.Elem().Kind() || reflect.Map == parameter.Elem().Kind() {
		parameter = parameter.Elem()
	}

	var out []reflect.Value
	switch m.v.Type().NumIn() {
	case 2:
		out = m.v.Call([]reflect.Value{
			controllerValue,
			parameter,
		})
	// case 3:
	// 	out = m.v.Call([]reflect.Value{
	// 		controllerValue,
	// 		parameter,
	// 		reflect.ValueOf(logging),
	// 	})
	default:
		return fmt.Errorf("unknown signature %s", m.v.Type())
	}

	if len(out) > 0 && !out[0].IsNil() {
		return out[0].Interface().(error)
	}

	return nil
}
<commit_msg>Go: add debug line \<commit_after>package broker

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/streadway/amqp"
	"labix.org/v2/mgo"
)

type Handler interface {
	HandleEvent(string, []byte) error
	ErrHandler
}

type ErrHandler interface {
	// bool is whether publishing the message to maintenance qeueue or not
	DefaultErrHandler(amqp.Delivery, error) bool
}

func (c *Consumer) withMetrics(handler *SubscriptionHandler, delivery amqp.Delivery) error {
	// if metrics is not enabled just invoke the function
	if c.Metrics == nil {
		return handler.HandleEvent(c.contextValue, delivery.Body)
	}

	c.Metrics.GetCounter("message").Inc(1)

	var err error

	c.Metrics.GetTimer(delivery.Type).Time(func() {
		err = handler.HandleEvent(c.contextValue, delivery.Body)
	})

	return err
}

func (c *Consumer) withCounter(counterName string, fn func()) {
	if c.Metrics == nil {
		fn()
	}

	c.Metrics.GetCounter(counterName).Inc(1)
	fn()
}

func (c *Consumer) Start() func(delivery amqp.Delivery) {
	c.Log.Info("Broker sarted to consume")
	return func(delivery amqp.Delivery) {
		c.Log.Debug("Handling event of %s", delivery.Type)

		if _, ok := c.handlers[delivery.Type]; !ok {
			// if no handler found, just ack message
			c.Log.Debug("No handler for %s", delivery.Type)
			c.withCounter("nohandlerforevent", func() { delivery.Ack(false) })
			return
		}

		go func() {
			var err error
			for _, handler := range c.handlers[delivery.Type] {
				// do not continue, if one of the handler gives error
				if err != nil {
					break
				}

				err = c.withMetrics(handler, delivery)
			}
			c.handleError(err, delivery)
		}()

	}
}

func (c *Consumer) handleError(err error, delivery amqp.Delivery) {
	switch err {
	case nil:
		c.withCounter("success", func() { delivery.Ack(false) })
	case ErrNoHandlerFound:
		c.withCounter("handlernotfound", func() { delivery.Ack(false) })
		c.Log.Debug("unknown event type (%s) recieved, deleting message from RMQ", delivery.Type)
	case gorm.RecordNotFound:
		c.withCounter("gormrecordnotfound", func() { delivery.Ack(false) })
		c.Log.Warning("Record not found in our db (%s) recieved, deleting message from RMQ", string(delivery.Body))
	case mgo.ErrNotFound:
		c.withCounter("mgorecordnotfound", func() { delivery.Ack(false) })
		c.Log.Warning("Record not found in our mongo db (%s) recieved, deleting message from RMQ", string(delivery.Body))
	default:
		c.withCounter("othererror", func() {
			// default err handler should handle the ack process
			if c.context.DefaultErrHandler(delivery, err) {
				if c.MaintenancePublisher == nil {
					return
				}

				data, err := json.Marshal(delivery)
				if err != nil {
					return
				}

				msg := amqp.Publishing{
					Body:  []byte(data),
					AppId: c.WorkerName,
				}

				c.withCounter("publishedtomaintenancequeue", func() {
					c.MaintenancePublisher.Publish(msg)
				})
			}
		})
	}
}

type SubscriptionHandler struct {
	v reflect.Value
}

func NewSubscriptionHandler(i interface{}) (*SubscriptionHandler, error) {
	t := reflect.TypeOf(i)
	if t.Kind() != reflect.Func {
		return nil, fmt.Errorf("kind was %v, not Func", t.Kind())
	}

	// check input parameter count
	if t.NumIn() != 2 {
		return nil, fmt.Errorf("input arity was %v, not 2", t.NumIn())
	}

	// check output parameter count
	if t.NumOut() != 1 {
		return nil, fmt.Errorf("output arity was %v, not 1", t.NumOut())
	}

	// output should be errors
	if t.Out(0).String() != "error" {
		return nil, fmt.Errorf("type of return value was %v, not error", t.Out(0))
	}

	return &SubscriptionHandler{reflect.ValueOf(i)}, nil
}

var nilParameter = reflect.ValueOf((*interface{})(nil))

func (m *SubscriptionHandler) HandleEvent(controllerValue reflect.Value, data []byte) error {
	var parameter reflect.Value

	if m.v.Type().NumIn() == 2 {
		in2 := m.v.Type().In(1)
		// if incoming paramter is an empty interface
		if reflect.Interface == in2.Kind() && in2.NumMethod() == 0 {
			parameter = nilParameter
			// if incoming parameter is a slice or a map
		} else if reflect.Slice == in2.Kind() || reflect.Map == in2.Kind() {
			// non-pointer maps/slices require special treatment because
			// json.Unmarshal won't work on a non-pointer destination. We
			// add a level indirection here, then deref it before .Call()
			parameter = reflect.New(in2)
		} else {
			// if it is a struct
			parameter = reflect.New(in2.Elem())
		}
	} else {
		// if handler doesnt have any incoming paramters
		parameter = nilParameter
	}

	// this is where magic happens:)
	// first read incoming []byte data into a io.reader then
	// put this data into a decoder(create a decoder out of it)
	// finally decode this data into given
	decoder := reflect.ValueOf(json.NewDecoder(bytes.NewReader(data)))
	res := decoder.MethodByName("Decode").Call([]reflect.Value{parameter})
	if len(res) > 0 && !res[0].IsNil() {
		return res[0].Interface().(error)
	}

	if reflect.Slice == parameter.Elem().Kind() || reflect.Map == parameter.Elem().Kind() {
		parameter = parameter.Elem()
	}

	var out []reflect.Value
	switch m.v.Type().NumIn() {
	case 2:
		out = m.v.Call([]reflect.Value{
			controllerValue,
			parameter,
		})
	// case 3:
	// 	out = m.v.Call([]reflect.Value{
	// 		controllerValue,
	// 		parameter,
	// 		reflect.ValueOf(logging),
	// 	})
	default:
		return fmt.Errorf("unknown signature %s", m.v.Type())
	}

	if len(out) > 0 && !out[0].IsNil() {
		return out[0].Interface().(error)
	}

	return nil
}
<|endoftext|>


<commit_before>package discovery

import (
	"reflect"
	"testing"

	"github.com/youtube/vitess/go/vt/topo"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// TestTabletStatsCache tests the functionality of the TabletStatsCache class.
func TestTabletStatsCache(t *testing.T) {
	// We want to unit test TabletStatsCache without a full-blown
	// HealthCheck object, so we can't call NewTabletStatsCache.
	// So we just construct this object here.
	tsc := &TabletStatsCache{
		cell:    "cell",
		entries: make(map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry),
	}

	// empty
	a := tsc.GetTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 0 {
		t.Errorf("wrong result, expected empty list: %v", a)
	}

	// add a tablet
	tablet1 := topo.NewTablet(10, "cell", "host1")
	ts1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 1, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(ts1)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// update stats with a change that won't change health array
	stillHhealthyTs1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 2, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(stillHhealthyTs1)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// update stats with a change that will change arrays
	notHealthyTs1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 35, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(notHealthyTs1)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*notHealthyTs1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*notHealthyTs1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// add a second tablet
	tablet2 := topo.NewTablet(11, "cell", "host2")
	ts2 := &TabletStats{
		Key:     "t2",
		Tablet:  tablet2,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 10, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(ts2)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}

	// one tablet goes unhealthy
	ts2.Serving = false
	tsc.StatsUpdate(ts2)

	// check we only have one left in healthy version
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// second tablet turns into a master, we receive down + up
	ts2.Serving = true
	ts2.Up = false
	tsc.StatsUpdate(ts2)
	ts2.Up = true
	ts2.Target.TabletType = topodatapb.TabletType_MASTER
	ts2.TabletExternallyReparentedTimestamp = 10
	tsc.StatsUpdate(ts2)

	// check we only have one replica left
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// check we have a master now
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts2, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// reparent: old replica goes into master
	ts1.Up = false
	tsc.StatsUpdate(ts1)
	ts1.Up = true
	ts1.Target.TabletType = topodatapb.TabletType_MASTER
	ts1.TabletExternallyReparentedTimestamp = 20
	tsc.StatsUpdate(ts1)

	// check we lost all replicas, and master is new one
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 0 {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// old master sending an old ping should be ignored
	tsc.StatsUpdate(ts2)
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
}
<commit_msg>Fixing comments.<commit_after>package discovery

import (
	"reflect"
	"testing"

	"github.com/youtube/vitess/go/vt/topo"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// TestTabletStatsCache tests the functionality of the TabletStatsCache class.
func TestTabletStatsCache(t *testing.T) {
	// We want to unit test TabletStatsCache without a full-blown
	// HealthCheck object, so we can't call NewTabletStatsCache.
	// So we just construct this object here.
	tsc := &TabletStatsCache{
		cell:    "cell",
		entries: make(map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry),
	}

	// empty
	a := tsc.GetTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 0 {
		t.Errorf("wrong result, expected empty list: %v", a)
	}

	// add a tablet
	tablet1 := topo.NewTablet(10, "cell", "host1")
	ts1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 1, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(ts1)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// update stats with a change that won't change health array
	stillHealthyTs1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 2, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(stillHealthyTs1)

	// check the previous ts1 is still there, as the new one is ignored.
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// update stats with a change that will change arrays
	notHealthyTs1 := &TabletStats{
		Key:     "t1",
		Tablet:  tablet1,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 35, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(notHealthyTs1)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*notHealthyTs1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*notHealthyTs1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// add a second tablet
	tablet2 := topo.NewTablet(11, "cell", "host2")
	ts2 := &TabletStats{
		Key:     "t2",
		Tablet:  tablet2,
		Target:  &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
		Up:      true,
		Serving: true,
		Stats:   &querypb.RealtimeStats{SecondsBehindMaster: 10, CpuUsage: 0.2},
	}
	tsc.StatsUpdate(ts2)

	// check it's there
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}

	// one tablet goes unhealthy
	ts2.Serving = false
	tsc.StatsUpdate(ts2)

	// check we only have one left in healthy version
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 2 {
		t.Errorf("unexpected result: %v", a)
	} else {
		if a[0].Tablet.Alias.Uid == 11 {
			a[0], a[1] = a[1], a[0]
		}
		if !reflect.DeepEqual(*ts1, a[0]) || !reflect.DeepEqual(*ts2, a[1]) {
			t.Errorf("unexpected result: %v", a)
		}
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// second tablet turns into a master, we receive down + up
	ts2.Serving = true
	ts2.Up = false
	tsc.StatsUpdate(ts2)
	ts2.Up = true
	ts2.Target.TabletType = topodatapb.TabletType_MASTER
	ts2.TabletExternallyReparentedTimestamp = 10
	tsc.StatsUpdate(ts2)

	// check we only have one replica left
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// check we have a master now
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts2, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// reparent: old replica goes into master
	ts1.Up = false
	tsc.StatsUpdate(ts1)
	ts1.Up = true
	ts1.Target.TabletType = topodatapb.TabletType_MASTER
	ts1.TabletExternallyReparentedTimestamp = 20
	tsc.StatsUpdate(ts1)

	// check we lost all replicas, and master is new one
	a = tsc.GetTabletStats("k", "s", topodatapb.TabletType_REPLICA)
	if len(a) != 0 {
		t.Errorf("unexpected result: %v", a)
	}
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}

	// old master sending an old ping should be ignored
	tsc.StatsUpdate(ts2)
	a = tsc.GetHealthyTabletStats("k", "s", topodatapb.TabletType_MASTER)
	if len(a) != 1 || !reflect.DeepEqual(*ts1, a[0]) {
		t.Errorf("unexpected result: %v", a)
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos

package tcell

import (
	"errors"
	"os"
	"os/signal"
	"syscall"

	"golang.org/x/term"
)

// engage is used to place the terminal in raw mode and establish screen size, etc.
// Thing of this is as tcell "engaging" the clutch, as it's going to be driving the
// terminal interface.
func (t *tScreen) engage() error {
	t.Lock()
	defer t.Unlock()
	if t.stopQ != nil {
		return errors.New("already engaged")
	}
	if _, err := term.MakeRaw(int(t.in.Fd())); err != nil {
		return err
	}
	if w, h, err := term.GetSize(int(t.in.Fd())); err == nil && w != 0 && h != 0 {
		t.cells.Resize(w, h)
	}
	stopQ := make(chan struct{})
	t.stopQ = stopQ
	t.nonBlocking(false)
	t.enableMouse(t.mouseFlags)
	t.enablePasting(t.pasteEnabled)
	signal.Notify(t.sigwinch, syscall.SIGWINCH)

	ti := t.ti
	t.TPuts(ti.EnterCA)
	t.TPuts(ti.HideCursor)
	t.TPuts(ti.EnableAcs)
	t.TPuts(ti.Clear)

	t.wg.Add(2)
	go t.inputLoop(stopQ)
	go t.mainLoop(stopQ)
	return nil
}

// disengage is used to release the terminal back to support from the caller.
// Think of this as tcell disengaging the clutch, so that another application
// can take over the terminal interface.  This restores the TTY mode that was
// present when the application was first started.
func (t *tScreen) disengage() {

	t.Lock()
	t.nonBlocking(true)
	stopQ := t.stopQ
	t.stopQ = nil
	close(stopQ)
	t.Unlock()

	// wait for everything to shut down
	t.wg.Wait()

	signal.Stop(t.sigwinch)

	// put back normal blocking mode
	t.nonBlocking(false)

	// shutdown the screen and disable special modes (e.g. mouse and bracketed paste)
	ti := t.ti
	t.cells.Resize(0, 0)
	t.TPuts(ti.ShowCursor)
	t.TPuts(ti.AttrOff)
	t.TPuts(ti.Clear)
	t.TPuts(ti.ExitCA)
	t.TPuts(ti.ExitKeypad)
	t.enableMouse(0)
	t.enablePasting(false)

	// restore the termios that we were started with
	_ = term.Restore(int(t.in.Fd()), t.saved)

}

// initialize is used at application startup, and sets up the initial values
// including file descriptors used for terminals and saving the initial state
// so that it can be restored when the application terminates.
func (t *tScreen) initialize() error {
	var err error
	t.out = os.Stdout
	t.in = os.Stdin
	t.saved, err = term.GetState(int(os.Stdin.Fd()))
	if err != nil {
		return err
	}
	return nil
}

// finalize is used to at application shutdown, and restores the terminal
// to it's initial state.  It should not be called more than once.
func (t *tScreen) finalize() {

	t.disengage()
}

// getWinSize is called to obtain the terminal dimensions.
func (t *tScreen) getWinSize() (int, int, error) {
	return term.GetSize(int(t.in.Fd()))
}

// Beep emits a beep to the terminal.
func (t *tScreen) Beep() error {
	t.writeString(string(byte(7)))
	return nil
}
<commit_msg>send enter_keypad during terminal engage<commit_after>// Copyright 2021 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos

package tcell

import (
	"errors"
	"os"
	"os/signal"
	"syscall"

	"golang.org/x/term"
)

// engage is used to place the terminal in raw mode and establish screen size, etc.
// Thing of this is as tcell "engaging" the clutch, as it's going to be driving the
// terminal interface.
func (t *tScreen) engage() error {
	t.Lock()
	defer t.Unlock()
	if t.stopQ != nil {
		return errors.New("already engaged")
	}
	if _, err := term.MakeRaw(int(t.in.Fd())); err != nil {
		return err
	}
	if w, h, err := term.GetSize(int(t.in.Fd())); err == nil && w != 0 && h != 0 {
		t.cells.Resize(w, h)
	}
	stopQ := make(chan struct{})
	t.stopQ = stopQ
	t.nonBlocking(false)
	t.enableMouse(t.mouseFlags)
	t.enablePasting(t.pasteEnabled)
	signal.Notify(t.sigwinch, syscall.SIGWINCH)

	ti := t.ti
	t.TPuts(ti.EnterCA)
	t.TPuts(ti.EnterKeypad)
	t.TPuts(ti.HideCursor)
	t.TPuts(ti.EnableAcs)
	t.TPuts(ti.Clear)

	t.wg.Add(2)
	go t.inputLoop(stopQ)
	go t.mainLoop(stopQ)
	return nil
}

// disengage is used to release the terminal back to support from the caller.
// Think of this as tcell disengaging the clutch, so that another application
// can take over the terminal interface.  This restores the TTY mode that was
// present when the application was first started.
func (t *tScreen) disengage() {

	t.Lock()
	t.nonBlocking(true)
	stopQ := t.stopQ
	t.stopQ = nil
	close(stopQ)
	t.Unlock()

	// wait for everything to shut down
	t.wg.Wait()

	signal.Stop(t.sigwinch)

	// put back normal blocking mode
	t.nonBlocking(false)

	// shutdown the screen and disable special modes (e.g. mouse and bracketed paste)
	ti := t.ti
	t.cells.Resize(0, 0)
	t.TPuts(ti.ShowCursor)
	t.TPuts(ti.AttrOff)
	t.TPuts(ti.Clear)
	t.TPuts(ti.ExitCA)
	t.TPuts(ti.ExitKeypad)
	t.enableMouse(0)
	t.enablePasting(false)

	// restore the termios that we were started with
	_ = term.Restore(int(t.in.Fd()), t.saved)

}

// initialize is used at application startup, and sets up the initial values
// including file descriptors used for terminals and saving the initial state
// so that it can be restored when the application terminates.
func (t *tScreen) initialize() error {
	var err error
	t.out = os.Stdout
	t.in = os.Stdin
	t.saved, err = term.GetState(int(os.Stdin.Fd()))
	if err != nil {
		return err
	}
	return nil
}

// finalize is used to at application shutdown, and restores the terminal
// to it's initial state.  It should not be called more than once.
func (t *tScreen) finalize() {

	t.disengage()
}

// getWinSize is called to obtain the terminal dimensions.
func (t *tScreen) getWinSize() (int, int, error) {
	return term.GetSize(int(t.in.Fd()))
}

// Beep emits a beep to the terminal.
func (t *tScreen) Beep() error {
	t.writeString(string(byte(7)))
	return nil
}
<|endoftext|>


<commit_before>package utils

import (
	"net/url"

	"github.com/eirka/eirka-libs/db"
)

// Redirect to the correct imageboard after post
func Link(id uint, referer string) (host string, err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// Get the url of the imageboard from the database
	err = dbase.QueryRow("SELECT ib_domain FROM imageboards WHERE ib_id = ?", id).Scan(&host)
	if err != nil {
		return
	}

	// Get the scheme from the referer
	refer, err := url.Parse(referer)
	if err != nil {
		return
	}

	// Get the domain from the database
	base, err := url.Parse(host)
	if err != nil {
		return
	}

	// Create url
	redir := &url.URL{
		Scheme: refer.Scheme,
		Host:   base.Host,
		Path:   base.Path,
	}

	// set the link
	host = redir.String()

	return

}
<commit_msg>fix redir for subdirectories<commit_after>package utils

import (
	"fmt"
	"net/url"

	"github.com/eirka/eirka-libs/db"
)

// Redirect to the correct imageboard after post
func Link(id uint, referer string) (host string, err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// Get the url of the imageboard from the database
	err = dbase.QueryRow("SELECT ib_domain FROM imageboards WHERE ib_id = ?", id).Scan(&host)
	if err != nil {
		return
	}

	// Get the scheme from the referer
	refer, err := url.Parse(referer)
	if err != nil {
		return
	}

	// Get the domain from the database
	base, err := url.Parse(host)
	if err != nil {
		return
	}

	// Create url
	redir := &url.URL{
		Scheme: refer.Scheme,
		Host:   base.Host,
		Path:   base.Path,
	}

	// set the link
	host = fmt.Sprintf("%s/", redir)

	return

}
<|endoftext|>


<commit_before>// Copyright © 2014 Daniele Tricoli <eriol@mornie.org>.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package irc // import "eriol.xyz/perpetua/irc"

import (
	"crypto/tls"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/thoj/go-ircevent"

	"eriol.xyz/perpetua/config"
	"eriol.xyz/perpetua/db"
)

const version = "perpetua quote bot " + config.Version

var conf *config.Config
var store *db.Store

// Localizated quote and about tokens used to detect the kind of query for
// the bot.
var i18n = map[string]map[string][]string{
	"en": map[string][]string{
		"quote": []string{"quote", "what does it say"},
		"about": []string{"about"},
	},
	"it": map[string][]string{
		"quote": []string{
			"cita",
			"che dice",
			"cosa dice",
			"che cosa dice"},
		"about": []string{
			"su",
			"sul",
			"sulla",
			"sullo",
			"sui",
			"sugli",
			"sulle"},
	},
}

// Join keys from i18n using "|": used inside the regex to perform an
// OR of all keys.
func i18nKeyJoin(lang, key string) string {
	return strings.Join(i18n[lang][key], "|")
}

func connect() (connection *irc.Connection, err error) {
	connection = irc.IRC(conf.IRC.Nickname, conf.IRC.User)
	connection.Version = version
	connection.UseTLS = conf.Server.UseTLS
	if conf.Server.SkipVerify == true {
		connection.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	}

	if err := connection.Connect(fmt.Sprintf("%s:%d",
		conf.Server.Hostname,
		conf.Server.Port)); err != nil {
		return nil, err
	}

	return connection, nil
}

func doWelcome(event *irc.Event) {
	for _, channel := range conf.IRC.Channels {
		event.Connection.Join(channel)
		event.Connection.Log.Println("Joined to " + channel)
	}
}

func doJoin(event *irc.Event) {
	channel := event.Arguments[0]

	if event.Nick == conf.IRC.Nickname {
		event.Connection.Privmsg(channel, "Hello! I'm "+version)
	} else {
		event.Connection.Privmsg(channel,
			fmt.Sprintf("Hello %s! I'm %s. Do you want a quote?",
				event.Nick,
				version))
	}
}

func doPrivmsg(event *irc.Event) {
	channel := event.Arguments[0]
	var quote string

	// Don't speak in private!
	if channel == conf.IRC.Nickname {
		return
	}
	command, person, extra, argument := parseMessage(event.Message())

	if command != "" && person != "" {

		quote = store.GetQuote(person, channel)

		if extra != "" && argument != "" {
			quote = store.GetQuoteAbout(person, argument, channel)
		}

		event.Connection.Privmsg(channel, quote)
	}
}

func parseMessage(message string) (command, person, extra, argument string) {
	var names []string
	lang := conf.I18N.Lang

	reArgument := regexp.MustCompile(conf.IRC.Nickname +
		`:?` +
		`\s+` +
		`(?P<command>` + i18nKeyJoin(lang, "quote") + `)` +
		`\s+` +
		`(?P<person>[\w\s-'\p{Latin}]+)` +
		`(?:\s+)` +
		`(?P<extra>` + i18nKeyJoin(lang, "about") + `)` +
		`(?:\s+)` +
		`(?P<argument>[\w\s-'\p{Latin}]+)`)

	re := regexp.MustCompile(conf.IRC.Nickname +
		`:?` +
		`\s+` +
		`(?P<command>` + i18nKeyJoin(lang, "quote") + `)` +
		`\s+` +
		`(?P<person>[\w\s-'\p{Latin}]+)`)

	res := reArgument.FindStringSubmatch(message)

	if res == nil {
		res = re.FindStringSubmatch(message)
		names = re.SubexpNames()
	} else {
		names = reArgument.SubexpNames()
	}

	m := map[string]string{}
	for i, n := range res {
		m[names[i]] = n
	}

	return m["command"], m["person"], m["extra"], m["argument"]
}

func Client(c *config.Config, db *db.Store) (err error) {
	conf = c
	store = db

	connection, err := connect()
	if err != nil {
		return errors.New("Can't connect")
	}

	connection.AddCallback("001", doWelcome)
	connection.AddCallback("JOIN", doJoin)
	connection.AddCallback("PRIVMSG", doPrivmsg)

	connection.Loop()

	return nil
}
<commit_msg>Group vars<commit_after>// Copyright © 2014 Daniele Tricoli <eriol@mornie.org>.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package irc // import "eriol.xyz/perpetua/irc"

import (
	"crypto/tls"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/thoj/go-ircevent"

	"eriol.xyz/perpetua/config"
	"eriol.xyz/perpetua/db"
)

const version = "perpetua quote bot " + config.Version

var (
	conf  *config.Config
	store *db.Store
)

// Localizated quote and about tokens used to detect the kind of query for
// the bot.
var i18n = map[string]map[string][]string{
	"en": map[string][]string{
		"quote": []string{"quote", "what does it say"},
		"about": []string{"about"},
	},
	"it": map[string][]string{
		"quote": []string{
			"cita",
			"che dice",
			"cosa dice",
			"che cosa dice"},
		"about": []string{
			"su",
			"sul",
			"sulla",
			"sullo",
			"sui",
			"sugli",
			"sulle"},
	},
}

// Join keys from i18n using "|": used inside the regex to perform an
// OR of all keys.
func i18nKeyJoin(lang, key string) string {
	return strings.Join(i18n[lang][key], "|")
}

func connect() (connection *irc.Connection, err error) {
	connection = irc.IRC(conf.IRC.Nickname, conf.IRC.User)
	connection.Version = version
	connection.UseTLS = conf.Server.UseTLS
	if conf.Server.SkipVerify == true {
		connection.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	}

	if err := connection.Connect(fmt.Sprintf("%s:%d",
		conf.Server.Hostname,
		conf.Server.Port)); err != nil {
		return nil, err
	}

	return connection, nil
}

func doWelcome(event *irc.Event) {
	for _, channel := range conf.IRC.Channels {
		event.Connection.Join(channel)
		event.Connection.Log.Println("Joined to " + channel)
	}
}

func doJoin(event *irc.Event) {
	channel := event.Arguments[0]

	if event.Nick == conf.IRC.Nickname {
		event.Connection.Privmsg(channel, "Hello! I'm "+version)
	} else {
		event.Connection.Privmsg(channel,
			fmt.Sprintf("Hello %s! I'm %s. Do you want a quote?",
				event.Nick,
				version))
	}
}

func doPrivmsg(event *irc.Event) {
	channel := event.Arguments[0]
	var quote string

	// Don't speak in private!
	if channel == conf.IRC.Nickname {
		return
	}
	command, person, extra, argument := parseMessage(event.Message())

	if command != "" && person != "" {

		quote = store.GetQuote(person, channel)

		if extra != "" && argument != "" {
			quote = store.GetQuoteAbout(person, argument, channel)
		}

		event.Connection.Privmsg(channel, quote)
	}
}

func parseMessage(message string) (command, person, extra, argument string) {
	var names []string
	lang := conf.I18N.Lang

	reArgument := regexp.MustCompile(conf.IRC.Nickname +
		`:?` +
		`\s+` +
		`(?P<command>` + i18nKeyJoin(lang, "quote") + `)` +
		`\s+` +
		`(?P<person>[\w\s-'\p{Latin}]+)` +
		`(?:\s+)` +
		`(?P<extra>` + i18nKeyJoin(lang, "about") + `)` +
		`(?:\s+)` +
		`(?P<argument>[\w\s-'\p{Latin}]+)`)

	re := regexp.MustCompile(conf.IRC.Nickname +
		`:?` +
		`\s+` +
		`(?P<command>` + i18nKeyJoin(lang, "quote") + `)` +
		`\s+` +
		`(?P<person>[\w\s-'\p{Latin}]+)`)

	res := reArgument.FindStringSubmatch(message)

	if res == nil {
		res = re.FindStringSubmatch(message)
		names = re.SubexpNames()
	} else {
		names = reArgument.SubexpNames()
	}

	m := map[string]string{}
	for i, n := range res {
		m[names[i]] = n
	}

	return m["command"], m["person"], m["extra"], m["argument"]
}

func Client(c *config.Config, db *db.Store) (err error) {
	conf = c
	store = db

	connection, err := connect()
	if err != nil {
		return errors.New("Can't connect")
	}

	connection.AddCallback("001", doWelcome)
	connection.AddCallback("JOIN", doJoin)
	connection.AddCallback("PRIVMSG", doPrivmsg)

	connection.Loop()

	return nil
}
<|endoftext|>


<commit_before>package report

import (
	"strconv"
	"strings"
)

func uint64SliceToString(sl []uint64) string {
	str := []string{}
	for _, v := range sl {
		str = append(str, strconv.FormatInt(int64(v), 10))
	}
	return strings.Join(str[:],",")
}

func float64SliceToString(sl []float64) string {
	str := []string{}
	for _, v := range sl {
		str = append(str, strconv.FormatFloat(v, 'f', 8, 64))
	}
	return strings.Join(str[:], ",")
}

// Rate calculate difference between current and previous value
func rate(sl []uint64, step float64) []float64 {
	result := make([]float64, len(sl))
	if len(sl) < 2 {
		return result
	}

	result = append(result, 0)
	for i := 1; i < len(sl); i++ {
		curValue := float64(sl[i-1])
		lastValue := float64(sl[i])

		// avoid of unnatural gaps when counter metrics flushed
		if lastValue < curValue{
			lastValue = curValue
		}
		result[i] = (lastValue - curValue) / step
	}

	return result
}<commit_msg>fix rate calculation<commit_after>package report

import (
	"strconv"
	"strings"
)

func uint64SliceToString(sl []uint64) string {
	str := []string{}
	for _, v := range sl {
		str = append(str, strconv.FormatInt(int64(v), 10))
	}
	return strings.Join(str[:], ",")
}

func float64SliceToString(sl []float64) string {
	str := []string{}
	for _, v := range sl {
		str = append(str, strconv.FormatFloat(v, 'f', 8, 64))
	}
	return strings.Join(str[:], ",")
}

// Rate calculate difference between current and previous value
func rate(sl []uint64, step float64) []float64 {
	result := make([]float64, len(sl))
	if len(sl) < 2 {
		return result
	}

	for i := 1; i < len(sl); i++ {
		curValue := float64(sl[i-1])
		lastValue := float64(sl[i])

		// avoid of unnatural gaps when counter metrics flushed
		if lastValue < curValue {
			lastValue = curValue
		}
		result[i] = (lastValue - curValue) / step
	}

	return result
}
<|endoftext|>


<commit_before>// Copyright 2012 The go-config Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Author Nelson

// 	Reading from buffer
// 	Hot relaod
// 	Marshaling parser interface easy to support other format
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"reflect"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
)

type NotifyAction int

const (
	NA_Continue = iota
	NA_Restart
	NA_Stop
)

type NotifyHandler func(Sender *FileConfig, event *fsnotify.FileEvent) NotifyAction

var (
	implError     = errors.New("imtemplment of codec is wrong, cant return nil when not error")
	codecNilError = errors.New("config Codec is nil")
	saveNilError  = errors.New("can not load or save nil configuration value")
)

// Codec interface define encode and decode function
// Encode encodes configuration object to byte slice
// Decode decodes byte slice to configuration object
type Codec interface {
	Encode(v interface{}) ([]byte, error)
	Decode(data []byte, v interface{}) error
}

// A FileConfig which is used for both reading and writing configration file.
// base is Config object which provide storage. Writing and reading simultaneously are safety.
// The codec is Codec interface which encode and decode configration object
type FileConfig struct {
	base          Config
	fileName      string
	codec         Codec
	lk            sync.RWMutex
	done          chan bool
	watcherStared bool
}

// NewFileConfig creates FileConfig object
func NewFileConfig(fileName string, codec Codec) *FileConfig {
	fc := new(FileConfig)
	fc.fileName = fileName
	fc.codec = codec
	fc.done = make(chan bool)
	return fc
}

// WatcherStared is a perperty which shows the file watcher is started or not
func (fc *FileConfig) WatcherStared() bool {
	fc.lk.RLock()
	defer fc.lk.RUnlock()
	return fc.watcherStared
}

// StopWatcher stop the file watcher
// the StopWatcher should be call when you no longer need fc object if WatcherStared
func (fc *FileConfig) StopWatcher() {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if fc.watcherStared == true {
		fc.done <- true
		select {
		case <-fc.done:
		case <-time.After(2 * time.Second):
		}
	}
	return
}

// StartWatcher start a file watcher to notify file changed
// StartWatcher call the handle once the file changed
func (fc *FileConfig) StartWatcher(handler NotifyHandler) error {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	// access instence var directly
	if fc.watcherStared {
		return nil
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	// access instance var directly
	err = watcher.Watch(fc.fileName)
	if err != nil {
		watcher.Close()
		return err
	}

	go func() {
		fc.watcherStared = true

		defer func() {
			if rv := recover(); rv != nil {
				emsg := "FileConfig Watcher go routine error "
				e, OK := rv.(error)
				if OK {
					emsg = emsg + e.Error()
				}
				fmt.Println(emsg)
			}

			watcher.Close()
			fc.watcherStared = false
		}()

		for {
			select {
			case ev := <-watcher.Event:
				if handler != nil {
					action := handler(fc, ev)
					switch action {
					case NA_Stop:
						return
					case NA_Restart:
						watcher.RemoveWatch(fc.FileName())
						watcher.Watch(fc.FileName())
					}
				}
			case <-watcher.Error:
				return
			case <-fc.done:
				fc.watcherStared = false
				fc.done <- true
				return
			}
		}
	}()

	return nil
}

// LoadFromFile load content from file and decodes it to object
// save the decoded object to internal storage
// v: decoded object receiveer, must be a pointer to object
// You should call fc function after file changed to refrash the data;
// otherwise you can call Value to get object from internal storage
func (fc *FileConfig) LoadFromFile(v interface{}) error {
	fc.lk.RLock()
	defer fc.lk.RUnlock()

	if v == nil {
		return saveNilError
	}

	if fc.codec == nil {
		return codecNilError
	}

	data, err := ioutil.ReadFile(fc.fileName)
	if err != nil {
		return err
	}

	err = fc.codec.Decode(data, v)
	if err != nil {
		return err
	}
	if v == nil {
		return implError
	}

	fc.base.Set(reflect.ValueOf(v).Elem().Interface())
	return nil
}

// SaveToFile encode v object to byte slice and save encoded object to file
// encoded object save to internal storage simultaneously.
// writes encoded data to a file named by FileName property.
// If the file does not exist, SaveToFile creates it; otherwise truncates it before writing.
func (fc *FileConfig) SaveToFile(v interface{}) error {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if v == nil {
		return saveNilError
	}

	data, err := fc.codec.Encode(v)
	if err != nil {
		return err
	}
	fc.base.Set(v)

	return ioutil.WriteFile(fc.fileName, data, 0666)
}

// FileName property getter
func (fc *FileConfig) FileName() string {
	fc.lk.RLock()
	defer fc.lk.RUnlock()
	return fc.fileName
}

// SetFileName set config filename
func (fc *FileConfig) SetFileName(name string) {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if fc.fileName != name {
		fc.fileName = name
	}
}

// Value get config value from internal storage
func (fc *FileConfig) Value() interface{} {
	return fc.base.Get()
}
<commit_msg>Change errors type<commit_after>// Copyright 2012 The go-config Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Author Nelson

// Package config Reading from buffer
// Hot relaod
// Marshaling parser interface easy to support other format
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"reflect"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
)

type NotifyAction int

const (
	NA_Continue = iota
	NA_Restart
	NA_Stop
)

type NotifyHandler func(Sender *FileConfig, event *fsnotify.FileEvent) NotifyAction

// Errors Load from configration file
var (
	ErrImpl     = errors.New("imtemplment of codec is wrong, cant return nil when not error")
	ErrCodecNil = errors.New("config Codec is nil")
	ErrSaveNil  = errors.New("can not load or save nil configuration value")
)

// Codec interface define encode and decode function
// Encode encodes configuration object to byte slice
// Decode decodes byte slice to configuration object
type Codec interface {
	Encode(v interface{}) ([]byte, error)
	Decode(data []byte, v interface{}) error
}

// A FileConfig which is used for both reading and writing configration file.
// base is Config object which provide storage. Writing and reading simultaneously are safety.
// The codec is Codec interface which encode and decode configration object
type FileConfig struct {
	base          Config
	fileName      string
	codec         Codec
	lk            sync.RWMutex
	done          chan bool
	watcherStared bool
}

// NewFileConfig creates FileConfig object
func NewFileConfig(fileName string, codec Codec) *FileConfig {
	fc := new(FileConfig)
	fc.fileName = fileName
	fc.codec = codec
	fc.done = make(chan bool)
	return fc
}

// WatcherStared is a perperty which shows the file watcher is started or not
func (fc *FileConfig) WatcherStared() bool {
	fc.lk.RLock()
	defer fc.lk.RUnlock()
	return fc.watcherStared
}

// StopWatcher stop the file watcher
// the StopWatcher should be call when you no longer need fc object if WatcherStared
func (fc *FileConfig) StopWatcher() {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if fc.watcherStared == true {
		fc.done <- true
		select {
		case <-fc.done:
		case <-time.After(2 * time.Second):
		}
	}
	return
}

// StartWatcher start a file watcher to notify file changed
// StartWatcher call the handle once the file changed
func (fc *FileConfig) StartWatcher(handler NotifyHandler) error {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	// access instence var directly
	if fc.watcherStared {
		return nil
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	// access instance var directly
	err = watcher.Watch(fc.fileName)
	if err != nil {
		watcher.Close()
		return err
	}

	go func() {
		fc.watcherStared = true

		defer func() {
			if rv := recover(); rv != nil {
				emsg := "FileConfig Watcher go routine error "
				e, OK := rv.(error)
				if OK {
					emsg = emsg + e.Error()
				}
				fmt.Println(emsg)
			}

			watcher.Close()
			fc.watcherStared = false
		}()

		for {
			select {
			case ev := <-watcher.Event:
				if handler != nil {
					action := handler(fc, ev)
					switch action {
					case NA_Stop:
						return
					case NA_Restart:
						watcher.RemoveWatch(fc.FileName())
						watcher.Watch(fc.FileName())
					}
				}
			case <-watcher.Error:
				return
			case <-fc.done:
				fc.watcherStared = false
				fc.done <- true
				return
			}
		}
	}()

	return nil
}

// LoadFromFile load content from file and decodes it to object
// save the decoded object to internal storage
// v: decoded object receiveer, must be a pointer to object
// You should call fc function after file changed to refrash the data;
// otherwise you can call Value to get object from internal storage
func (fc *FileConfig) LoadFromFile(v interface{}) error {
	fc.lk.RLock()
	defer fc.lk.RUnlock()

	if v == nil {
		return ErrSaveNil
	}

	if fc.codec == nil {
		return ErrCodecNil
	}

	data, err := ioutil.ReadFile(fc.fileName)
	if err != nil {
		return err
	}

	err = fc.codec.Decode(data, v)
	if err != nil {
		return err
	}
	if v == nil {
		return ErrImpl
	}

	fc.base.Set(reflect.ValueOf(v).Elem().Interface())
	return nil
}

// SaveToFile encode v object to byte slice and save encoded object to file
// encoded object save to internal storage simultaneously.
// writes encoded data to a file named by FileName property.
// If the file does not exist, SaveToFile creates it; otherwise truncates it before writing.
func (fc *FileConfig) SaveToFile(v interface{}) error {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if v == nil {
		return ErrSaveNil
	}

	data, err := fc.codec.Encode(v)
	if err != nil {
		return err
	}
	fc.base.Set(v)

	return ioutil.WriteFile(fc.fileName, data, 0666)
}

// FileName property getter
func (fc *FileConfig) FileName() string {
	fc.lk.RLock()
	defer fc.lk.RUnlock()
	return fc.fileName
}

// SetFileName set config filename
func (fc *FileConfig) SetFileName(name string) {
	fc.lk.Lock()
	defer fc.lk.Unlock()

	if fc.fileName != name {
		fc.fileName = name
	}
}

// Value get config value from internal storage
func (fc *FileConfig) Value() interface{} {
	return fc.base.Get()
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

package utils

import (
	l4g "code.google.com/p/log4go"
	"crypto/tls"
	"fmt"
	"github.com/mattermost/platform/model"
	"html"
	"net"
	"net/mail"
	"net/smtp"
  "time"
)

func CheckMailSettings() *model.AppError {
	if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
		return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
	}
	conn, err := connectToSMTPServer()
	if err != nil {
		return err
	}
	defer conn.Close()
	c, err2 := newSMTPClient(conn)
	if err2 != nil {
		return err
	}
	defer c.Quit()
	defer c.Close()

	return nil
}

func connectToSMTPServer() (net.Conn, *model.AppError) {
	host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)

	var conn net.Conn
	var err error

	if Cfg.EmailSettings.UseTLS {
		tlsconfig := &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         host,
		}

		conn, err = tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
		if err != nil {
			return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
		}
	} else {
		conn, err = net.Dial("tcp", Cfg.EmailSettings.SMTPServer)
		if err != nil {
			return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
		}
	}

	return conn, nil
}

func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
	host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
	c, err := smtp.NewClient(conn, host)
	if err != nil {
		l4g.Error("Failed to open a connection to SMTP server %v", err)
		return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
	}
	// GO does not support plain auth over a non encrypted connection.
	// so if not tls then no auth
	auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
	if Cfg.EmailSettings.UseTLS {
		if err = c.Auth(auth); err != nil {
			return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
		}
	} else if Cfg.EmailSettings.UseStartTLS {
		tlsconfig := &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         host,
		}
		c.StartTLS(tlsconfig)
		if err = c.Auth(auth); err != nil {
			return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
		}
	}
	return c, nil
}

func SendMail(to, subject, body string) *model.AppError {

	if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
		return nil
	}

	fromMail := mail.Address{Cfg.EmailSettings.FeedbackName, Cfg.EmailSettings.FeedbackEmail}
	toMail := mail.Address{"", to}

	headers := make(map[string]string)
	headers["From"] = fromMail.String()
	headers["To"] = toMail.String()
	headers["Subject"] = html.UnescapeString(subject)
	headers["MIME-version"] = "1.0"
	headers["Content-Type"] = "text/html"
	headers["Date"] = time.Now().Format(time.RFC822)

	message := ""
	for k, v := range headers {
		message += fmt.Sprintf("%s: %s\r\n", k, v)
	}
	message += "\r\n" + body + ""

	conn, err1 := connectToSMTPServer()
	if err1 != nil {
		return err1
	}
	defer conn.Close()

	c, err2 := newSMTPClient(conn)
	if err2 != nil {
		return err2
	}
	defer c.Quit()
	defer c.Close()

	if err := c.Mail(fromMail.Address); err != nil {
		return model.NewAppError("SendMail", "Failed to add from email address", err.Error())
	}

	if err := c.Rcpt(toMail.Address); err != nil {
		return model.NewAppError("SendMail", "Failed to add to email address", err.Error())
	}

	w, err := c.Data()
	if err != nil {
		return model.NewAppError("SendMail", "Failed to add email messsage data", err.Error())
	}

	_, err = w.Write([]byte(message))
	if err != nil {
		return model.NewAppError("SendMail", "Failed to write email message", err.Error())
	}

	err = w.Close()
	if err != nil {
		return model.NewAppError("SendMail", "Failed to close connection to SMTP server", err.Error())
	}

	return nil
}
<commit_msg>missing tab<commit_after>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

package utils

import (
	l4g "code.google.com/p/log4go"
	"crypto/tls"
	"fmt"
	"github.com/mattermost/platform/model"
	"html"
	"net"
	"net/mail"
	"net/smtp"
	"time"
)

func CheckMailSettings() *model.AppError {
	if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
		return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
	}
	conn, err := connectToSMTPServer()
	if err != nil {
		return err
	}
	defer conn.Close()
	c, err2 := newSMTPClient(conn)
	if err2 != nil {
		return err
	}
	defer c.Quit()
	defer c.Close()

	return nil
}

func connectToSMTPServer() (net.Conn, *model.AppError) {
	host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)

	var conn net.Conn
	var err error

	if Cfg.EmailSettings.UseTLS {
		tlsconfig := &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         host,
		}

		conn, err = tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
		if err != nil {
			return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
		}
	} else {
		conn, err = net.Dial("tcp", Cfg.EmailSettings.SMTPServer)
		if err != nil {
			return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
		}
	}

	return conn, nil
}

func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
	host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
	c, err := smtp.NewClient(conn, host)
	if err != nil {
		l4g.Error("Failed to open a connection to SMTP server %v", err)
		return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
	}
	// GO does not support plain auth over a non encrypted connection.
	// so if not tls then no auth
	auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
	if Cfg.EmailSettings.UseTLS {
		if err = c.Auth(auth); err != nil {
			return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
		}
	} else if Cfg.EmailSettings.UseStartTLS {
		tlsconfig := &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         host,
		}
		c.StartTLS(tlsconfig)
		if err = c.Auth(auth); err != nil {
			return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
		}
	}
	return c, nil
}

func SendMail(to, subject, body string) *model.AppError {

	if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
		return nil
	}

	fromMail := mail.Address{Cfg.EmailSettings.FeedbackName, Cfg.EmailSettings.FeedbackEmail}
	toMail := mail.Address{"", to}

	headers := make(map[string]string)
	headers["From"] = fromMail.String()
	headers["To"] = toMail.String()
	headers["Subject"] = html.UnescapeString(subject)
	headers["MIME-version"] = "1.0"
	headers["Content-Type"] = "text/html"
	headers["Date"] = time.Now().Format(time.RFC822)

	message := ""
	for k, v := range headers {
		message += fmt.Sprintf("%s: %s\r\n", k, v)
	}
	message += "\r\n" + body + ""

	conn, err1 := connectToSMTPServer()
	if err1 != nil {
		return err1
	}
	defer conn.Close()

	c, err2 := newSMTPClient(conn)
	if err2 != nil {
		return err2
	}
	defer c.Quit()
	defer c.Close()

	if err := c.Mail(fromMail.Address); err != nil {
		return model.NewAppError("SendMail", "Failed to add from email address", err.Error())
	}

	if err := c.Rcpt(toMail.Address); err != nil {
		return model.NewAppError("SendMail", "Failed to add to email address", err.Error())
	}

	w, err := c.Data()
	if err != nil {
		return model.NewAppError("SendMail", "Failed to add email messsage data", err.Error())
	}

	_, err = w.Write([]byte(message))
	if err != nil {
		return model.NewAppError("SendMail", "Failed to write email message", err.Error())
	}

	err = w.Close()
	if err != nil {
		return model.NewAppError("SendMail", "Failed to close connection to SMTP server", err.Error())
	}

	return nil
}
<|endoftext|>