<commit_before>package main

import (
	"github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

// return ClowdWatchEvent rule best matched one by yaml descripbed rule.
func fetchCWEventRuleFromDescribedRule(client *cloudwatchevents.CloudWatchEvents, describedRule Rule) (cloudwatchevents.Rule, error) {
	var bestMatchedRule cloudwatchevents.Rule
	var score float64

	resp, err := client.ListRules(nil)
	if err != nil {
		return bestMatchedRule, err
	}

	for _, rule := range resp.Rules {
		var s = MatchScoreForCWEventRuleAndDescribedRule(*rule, describedRule)

		if score < s {
			bestMatchedRule = *rule
			score = s
		}
	}
	return bestMatchedRule, nil
}

// fetch ClowdWatchEvent target by Rule.ActualRule
func fetchActualTargetsByRules(client *cloudwatchevents.CloudWatchEvents, rules []Rule) error {
	for i, rule := range rules {
		if rule.ActualRule.Name == nil {
			continue
		}
		targets, err := client.ListTargetsByRule(&cloudwatchevents.ListTargetsByRuleInput{
			Rule: rule.ActualRule.Name,
		})
		if err != nil {
			return err
		}
		rules[i].ActualTargets = targets.Targets
	}
	return nil
}

// return match score ClowdWatchEvent rule and descripbed rule.
func MatchScoreForCWEventRuleAndDescribedRule(cweRule cloudwatchevents.Rule, describedRule Rule) float64 {
	const Elements = 5.0
	matchCount := 0.0

	if CompareString(cweRule.Name, &describedRule.Name) {
		matchCount++
	}
	if CompareString(cweRule.EventPattern, &describedRule.EventPattern) {
		matchCount++
	}
	if CompareString(cweRule.Description, &describedRule.Description) {
		matchCount++
	}
	if CompareString(cweRule.ScheduleExpression, &describedRule.ScheduleExpression) {
		matchCount++
	}
	if CompareString(cweRule.State, &describedRule.State) {
		matchCount++
	}
	return (matchCount / Elements)
}

// return true when rule is new defined in yaml configration file
// judgemant by name(arn)
func IsNewDefinedRule(cweRule cloudwatchevents.Rule, describedRule Rule) bool {
	return *cweRule.Name != describedRule.Name
}

// compare strings
// nil and empty string are same value
func CompareString(a, b *string) bool {
	if a == nil || *a == "" {
		if b == nil || *b == "" {
			return true
		} else {
			return false
		}
	} else if b == nil || *b == "" {
		if a == nil || *a == "" {
			return true
		} else {
			return false
		}
	}
	return *a == *b
}
<commit_msg>Only fetch targets<commit_after>package main

import (
	"fmt"

	"github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

// return ClowdWatchEvent rule best matched one by yaml descripbed rule.
func fetchCWEventRuleFromDescribedRule(client *cloudwatchevents.CloudWatchEvents, describedRule Rule) (cloudwatchevents.Rule, error) {
	var bestMatchedRule cloudwatchevents.Rule
	var score float64

	resp, err := client.ListRules(nil)
	if err != nil {
		return bestMatchedRule, err
	}

	for _, rule := range resp.Rules {
		var s = MatchScoreForCWEventRuleAndDescribedRule(*rule, describedRule)

		if score < s {
			bestMatchedRule = *rule
			score = s
		}
	}
	return bestMatchedRule, nil
}

// fetch ClowdWatchEvent target by Rule.ActualRule
func fetchActualTargetsByRule(client *cloudwatchevents.CloudWatchEvents, r Rule) ([]*cloudwatchevents.Target, error) {
	if r.ActualRule.Name == nil {
		return nil, fmt.Errorf("Rule.ActualRule.Name is must be present")
	}

	targets, err := client.ListTargetsByRule(&cloudwatchevents.ListTargetsByRuleInput{
		Rule: r.ActualRule.Name,
	})
	if err != nil {
		return nil, err
	}
	return targets.Targets, nil
}

// return match score ClowdWatchEvent rule and descripbed rule.
func MatchScoreForCWEventRuleAndDescribedRule(cweRule cloudwatchevents.Rule, describedRule Rule) float64 {
	const Elements = 5.0
	matchCount := 0.0

	if CompareString(cweRule.Name, &describedRule.Name) {
		matchCount++
	}
	if CompareString(cweRule.EventPattern, &describedRule.EventPattern) {
		matchCount++
	}
	if CompareString(cweRule.Description, &describedRule.Description) {
		matchCount++
	}
	if CompareString(cweRule.ScheduleExpression, &describedRule.ScheduleExpression) {
		matchCount++
	}
	if CompareString(cweRule.State, &describedRule.State) {
		matchCount++
	}
	return (matchCount / Elements)
}

// return true when rule is new defined in yaml configration file
// judgemant by name(arn)
func IsNewDefinedRule(cweRule cloudwatchevents.Rule, describedRule Rule) bool {
	return *cweRule.Name != describedRule.Name
}

// compare strings
// nil and empty string are same value
func CompareString(a, b *string) bool {
	if a == nil || *a == "" {
		if b == nil || *b == "" {
			return true
		} else {
			return false
		}
	} else if b == nil || *b == "" {
		if a == nil || *a == "" {
			return true
		} else {
			return false
		}
	}
	return *a == *b
}
<|endoftext|>


<commit_before>package discordgo

// EventHandler is an interface for Discord events.
type EventHandler interface {
	// Type returns the type of event this handler belongs to.
	Type() string

	// Handle is called whenever an event of Type() happens.
	// It is the receivers responsibility to type assert that the interface
	// is the expected struct.
	Handle(*Session, interface{})
}

// EventInterfaceProvider is an interface for providing empty interfaces for
// Discord events.
type EventInterfaceProvider interface {
	// Type is the type of event this handler belongs to.
	Type() string

	// New returns a new instance of the struct this event handler handles.
	// This is called once per event.
	// The struct is provided to all handlers of the same Type().
	New() interface{}
}

// interfaceEventType is the event handler type for interface{} events.
const interfaceEventType = "__INTERFACE__"

// interfaceEventHandler is an event handler for interface{} events.
type interfaceEventHandler func(*Session, interface{})

// Type returns the event type for interface{} events.
func (eh interfaceEventHandler) Type() string {
	return interfaceEventType
}

// Handle is the handler for an interface{} event.
func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
	eh(s, i)
}

var registeredInterfaceProviders = map[string]EventInterfaceProvider{}

// registerInterfaceProvider registers a provider so that DiscordGo can
// access it's New() method.
func registerInterfaceProvider(eh EventInterfaceProvider) {
	if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
		return
		// XXX:
		// if we should error here, we need to do something with it.
		// fmt.Errorf("event %s already registered", eh.Type())
	}
	registeredInterfaceProviders[eh.Type()] = eh
	return
}

// eventHandlerInstance is a wrapper around an event handler, as functions
// cannot be compared directly.
type eventHandlerInstance struct {
	eventHandler EventHandler
}

// addEventHandler adds an event handler that will be fired anytime
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandler(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.handlers == nil {
		s.handlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// addEventHandler adds an event handler that will be fired the next time
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.onceHandlers == nil {
		s.onceHandlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the function fires.
// The first parameter is a *Session, and the second parameter is a pointer
// to a struct corresponding to the event for which you want to listen.
//
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
//
// List of events can be found at this page, with corresponding names in the
// library for each event: https://discord.com/developers/docs/topics/gateway#event-names
// There are also synthetic events fired by the library internally which are
// available for handling, like Connect, Disconnect, and RateLimit.
// events.go contains all of the Discord WSAPI and synthetic events that can be handled.
//
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandler(eh)
}

// AddHandlerOnce allows you to add an event handler that will be fired the next time
// the Discord WSAPI event that matches the function fires.
// See AddHandler for more details.
func (s *Session) AddHandlerOnce(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandlerOnce(eh)
}

// removeEventHandler instance removes an event handler instance.
func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	handlers := s.handlers[t]
	for i := range handlers {
		if handlers[i] == ehi {
			s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
		}
	}

	onceHandlers := s.onceHandlers[t]
	for i := range onceHandlers {
		if onceHandlers[i] == ehi {
			s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
		}
	}
}

// Handles calling permanent and once handlers for an event type.
func (s *Session) handle(t string, i interface{}) {
	for _, eh := range s.handlers[t] {
		if s.SyncEvents {
			eh.eventHandler.Handle(s, i)
		} else {
			go eh.eventHandler.Handle(s, i)
		}
	}

	if len(s.onceHandlers[t]) > 0 {
		for _, eh := range s.onceHandlers[t] {
			if s.SyncEvents {
				eh.eventHandler.Handle(s, i)
			} else {
				go eh.eventHandler.Handle(s, i)
			}
		}
		s.onceHandlers[t] = nil
	}
}

// Handles an event type by calling internal methods, firing handlers and firing the
// interface{} event.
func (s *Session) handleEvent(t string, i interface{}) {
	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	// All events are dispatched internally first.
	s.onInterface(i)

	// Then they are dispatched to anyone handling interface{} events.
	s.handle(interfaceEventType, i)

	// Finally they are dispatched to any typed handlers.
	s.handle(t, i)
}

// setGuildIds will set the GuildID on all the members of a guild.
// This is done as event data does not have it set.
func setGuildIds(g *Guild) {
	for _, c := range g.Channels {
		c.GuildID = g.ID
	}

	for _, m := range g.Members {
		m.GuildID = g.ID
	}

	for _, vs := range g.VoiceStates {
		vs.GuildID = g.ID
	}
}

// onInterface handles all internal events and routes them to the appropriate internal handler.
func (s *Session) onInterface(i interface{}) {
	switch t := i.(type) {
	case *Ready:
		for _, g := range t.Guilds {
			setGuildIds(g)
		}
		s.onReady(t)
	case *GuildCreate:
		setGuildIds(t.Guild)
	case *GuildUpdate:
		setGuildIds(t.Guild)
	case *VoiceServerUpdate:
		go s.onVoiceServerUpdate(t)
	case *VoiceStateUpdate:
		go s.onVoiceStateUpdate(t)
	}
	err := s.State.OnInterface(s, i)
	if err != nil {
		s.log(LogDebug, "error dispatching internal event, %s", err)
	}
}

// onReady handles the ready event.
func (s *Session) onReady(r *Ready) {

	// Store the SessionID within the Session struct.
	s.sessionID = r.SessionID
}
<commit_msg>fix(event): removal of once-handlers<commit_after>package discordgo

// EventHandler is an interface for Discord events.
type EventHandler interface {
	// Type returns the type of event this handler belongs to.
	Type() string

	// Handle is called whenever an event of Type() happens.
	// It is the receivers responsibility to type assert that the interface
	// is the expected struct.
	Handle(*Session, interface{})
}

// EventInterfaceProvider is an interface for providing empty interfaces for
// Discord events.
type EventInterfaceProvider interface {
	// Type is the type of event this handler belongs to.
	Type() string

	// New returns a new instance of the struct this event handler handles.
	// This is called once per event.
	// The struct is provided to all handlers of the same Type().
	New() interface{}
}

// interfaceEventType is the event handler type for interface{} events.
const interfaceEventType = "__INTERFACE__"

// interfaceEventHandler is an event handler for interface{} events.
type interfaceEventHandler func(*Session, interface{})

// Type returns the event type for interface{} events.
func (eh interfaceEventHandler) Type() string {
	return interfaceEventType
}

// Handle is the handler for an interface{} event.
func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
	eh(s, i)
}

var registeredInterfaceProviders = map[string]EventInterfaceProvider{}

// registerInterfaceProvider registers a provider so that DiscordGo can
// access it's New() method.
func registerInterfaceProvider(eh EventInterfaceProvider) {
	if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
		return
		// XXX:
		// if we should error here, we need to do something with it.
		// fmt.Errorf("event %s already registered", eh.Type())
	}
	registeredInterfaceProviders[eh.Type()] = eh
	return
}

// eventHandlerInstance is a wrapper around an event handler, as functions
// cannot be compared directly.
type eventHandlerInstance struct {
	eventHandler EventHandler
}

// addEventHandler adds an event handler that will be fired anytime
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandler(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.handlers == nil {
		s.handlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// addEventHandler adds an event handler that will be fired the next time
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.onceHandlers == nil {
		s.onceHandlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the function fires.
// The first parameter is a *Session, and the second parameter is a pointer
// to a struct corresponding to the event for which you want to listen.
//
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
//
// List of events can be found at this page, with corresponding names in the
// library for each event: https://discord.com/developers/docs/topics/gateway#event-names
// There are also synthetic events fired by the library internally which are
// available for handling, like Connect, Disconnect, and RateLimit.
// events.go contains all of the Discord WSAPI and synthetic events that can be handled.
//
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandler(eh)
}

// AddHandlerOnce allows you to add an event handler that will be fired the next time
// the Discord WSAPI event that matches the function fires.
// See AddHandler for more details.
func (s *Session) AddHandlerOnce(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandlerOnce(eh)
}

// removeEventHandler instance removes an event handler instance.
func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	handlers := s.handlers[t]
	for i := range handlers {
		if handlers[i] == ehi {
			s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
		}
	}

	onceHandlers := s.onceHandlers[t]
	for i := range onceHandlers {
		if onceHandlers[i] == ehi {
			s.onceHandlers[t] = append(onceHandlers[:i], onceHandlers[i+1:]...)
		}
	}
}

// Handles calling permanent and once handlers for an event type.
func (s *Session) handle(t string, i interface{}) {
	for _, eh := range s.handlers[t] {
		if s.SyncEvents {
			eh.eventHandler.Handle(s, i)
		} else {
			go eh.eventHandler.Handle(s, i)
		}
	}

	if len(s.onceHandlers[t]) > 0 {
		for _, eh := range s.onceHandlers[t] {
			if s.SyncEvents {
				eh.eventHandler.Handle(s, i)
			} else {
				go eh.eventHandler.Handle(s, i)
			}
		}
		s.onceHandlers[t] = nil
	}
}

// Handles an event type by calling internal methods, firing handlers and firing the
// interface{} event.
func (s *Session) handleEvent(t string, i interface{}) {
	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	// All events are dispatched internally first.
	s.onInterface(i)

	// Then they are dispatched to anyone handling interface{} events.
	s.handle(interfaceEventType, i)

	// Finally they are dispatched to any typed handlers.
	s.handle(t, i)
}

// setGuildIds will set the GuildID on all the members of a guild.
// This is done as event data does not have it set.
func setGuildIds(g *Guild) {
	for _, c := range g.Channels {
		c.GuildID = g.ID
	}

	for _, m := range g.Members {
		m.GuildID = g.ID
	}

	for _, vs := range g.VoiceStates {
		vs.GuildID = g.ID
	}
}

// onInterface handles all internal events and routes them to the appropriate internal handler.
func (s *Session) onInterface(i interface{}) {
	switch t := i.(type) {
	case *Ready:
		for _, g := range t.Guilds {
			setGuildIds(g)
		}
		s.onReady(t)
	case *GuildCreate:
		setGuildIds(t.Guild)
	case *GuildUpdate:
		setGuildIds(t.Guild)
	case *VoiceServerUpdate:
		go s.onVoiceServerUpdate(t)
	case *VoiceStateUpdate:
		go s.onVoiceStateUpdate(t)
	}
	err := s.State.OnInterface(s, i)
	if err != nil {
		s.log(LogDebug, "error dispatching internal event, %s", err)
	}
}

// onReady handles the ready event.
func (s *Session) onReady(r *Ready) {

	// Store the SessionID within the Session struct.
	s.sessionID = r.SessionID
}
<|endoftext|>


<commit_before>package faidx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/biogo/biogo/io/seqio/fai"
	"github.com/edsrzf/mmap-go"
)

// Faidx is used to provide random access to the sequence data.
type Faidx struct {
	rdr   io.ReadSeeker
	Index fai.Index
	mmap  mmap.MMap
}

// ErrorNoFai is returned if the fasta doesn't have an associated .fai
var ErrorNoFai = errors.New("no fai for fasta")

func notExists(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return err
	}
	return nil
}

// New returns a faidx object from a fasta file that has an existing index.
func New(fasta string) (*Faidx, error) {
	err := notExists(fasta + ".fai")
	if err != nil {
		return nil, ErrorNoFai
	}
	fh, err := os.Open(fasta + ".fai")
	if err != nil {
		return nil, err
	}
	idx, err := fai.ReadFrom(fh)
	if err != nil {
		return nil, err
	}
	rdr, err := os.Open(fasta)
	if err != nil {
		return nil, err
	}

	smap, err := mmap.Map(rdr, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &Faidx{rdr, idx, smap}, nil
}

func position(r fai.Record, p int) int64 {
	if p < 0 || r.Length < p {
		panic(fmt.Sprintf("fai: index [%d] out of range", p))
	}
	return r.Start + int64(p/r.BasesPerLine*r.BytesPerLine+p%r.BasesPerLine)
}

// Get takes a position and returns the string sequence. Start and end are 0-based.
func (f *Faidx) Get(chrom string, start int, end int) (string, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return "", fmt.Errorf("unknown sequence %s", chrom)
	}

	pstart := position(idx, start)
	pend := position(idx, end)
	buf := f.mmap[pstart:pend]
	buf = bytes.Replace(buf, []byte{'\n'}, []byte{}, -1)
	return string(buf), nil
}

// Stats hold sequenc information.
type Stats struct {
	// GC content fraction
	GC float64
	// CpG content fraction
	CpG float64
	// masked (lower-case fraction
	Masked float64
}

func min(a, b float64) float64 {
	if b < a {
		return b
	}
	return a
}

// Stats returns the proportion of GC's (GgCc), the CpG content (Cc follow by Gg)
// and the proportion of lower-case bases (masked).
// CpG will be 1.0 if the requested sequence is CGC and the base that follows is G
func (f *Faidx) Stats(chrom string, start int, end int) (Stats, error) {
	// copied from cnvkit.
	idx, ok := f.Index[chrom]
	if !ok {
		return Stats{}, fmt.Errorf("unknown sequence %s", chrom)
	}
	pstart := position(idx, start)
	pend := position(idx, end)
	oend := pend
	if pend < int64(len(f.mmap)) {
		oend++
	}

	var gcUp, gcLo, atUp, atLo, cpg int
	buf := f.mmap[pstart:oend]
	for i, v := range buf {
		// we added 1 to do the GC content...
		if i == len(buf)-1 {
			break
		}
		if v == 'G' || v == 'C' {
			if v == 'C' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcUp++
		} else if v == 'A' || v == 'T' {
			atUp++
		} else if v == 'g' || v == 'c' {
			if v == 'c' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcLo++
		} else if v == 'a' || v == 't' {
			atLo++
		}
	}
	tot := float64(gcUp + gcLo + atUp + atLo)
	if tot == 0.0 {
		return Stats{}, nil
	}
	return Stats{
		GC:     float64(gcLo+gcUp) / tot,
		Masked: float64(atLo+gcLo) / tot,
		CpG:    min(1.0, float64(2*cpg)/tot)}, nil
}

// At takes a single point and returns the single base.
func (f *Faidx) At(chrom string, pos int) (byte, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return '*', fmt.Errorf("unknown sequence %s", chrom)
	}

	ppos := position(idx, pos)
	return f.mmap[ppos], nil
}

// Close the associated Reader.
func (f *Faidx) Close() {
	f.rdr.(io.Closer).Close()
	f.mmap.Unmap()
}
<commit_msg>more informative message in panic<commit_after>package faidx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/biogo/biogo/io/seqio/fai"
	"github.com/edsrzf/mmap-go"
)

// Faidx is used to provide random access to the sequence data.
type Faidx struct {
	rdr   io.ReadSeeker
	Index fai.Index
	mmap  mmap.MMap
}

// ErrorNoFai is returned if the fasta doesn't have an associated .fai
var ErrorNoFai = errors.New("no fai for fasta")

func notExists(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return err
	}
	return nil
}

// New returns a faidx object from a fasta file that has an existing index.
func New(fasta string) (*Faidx, error) {
	err := notExists(fasta + ".fai")
	if err != nil {
		return nil, ErrorNoFai
	}
	fh, err := os.Open(fasta + ".fai")
	if err != nil {
		return nil, err
	}
	idx, err := fai.ReadFrom(fh)
	if err != nil {
		return nil, err
	}
	rdr, err := os.Open(fasta)
	if err != nil {
		return nil, err
	}

	smap, err := mmap.Map(rdr, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &Faidx{rdr, idx, smap}, nil
}

func position(r fai.Record, p int) int64 {
	if p < 0 || r.Length < p {
		panic(fmt.Sprintf("fai: index [%d] out of range in %s which has length: %d", p, r.Name, r.Length))
	}
	return r.Start + int64(p/r.BasesPerLine*r.BytesPerLine+p%r.BasesPerLine)
}

// Get takes a position and returns the string sequence. Start and end are 0-based.
func (f *Faidx) Get(chrom string, start int, end int) (string, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return "", fmt.Errorf("unknown sequence %s", chrom)
	}

	pstart := position(idx, start)
	pend := position(idx, end)
	buf := f.mmap[pstart:pend]
	buf = bytes.Replace(buf, []byte{'\n'}, []byte{}, -1)
	return string(buf), nil
}

// Stats hold sequenc information.
type Stats struct {
	// GC content fraction
	GC float64
	// CpG content fraction
	CpG float64
	// masked (lower-case fraction
	Masked float64
}

func min(a, b float64) float64 {
	if b < a {
		return b
	}
	return a
}

// Stats returns the proportion of GC's (GgCc), the CpG content (Cc follow by Gg)
// and the proportion of lower-case bases (masked).
// CpG will be 1.0 if the requested sequence is CGC and the base that follows is G
func (f *Faidx) Stats(chrom string, start int, end int) (Stats, error) {
	// copied from cnvkit.
	idx, ok := f.Index[chrom]
	if !ok {
		return Stats{}, fmt.Errorf("unknown sequence %s", chrom)
	}
	pstart := position(idx, start)
	pend := position(idx, end)
	oend := pend
	if pend < int64(len(f.mmap)) {
		oend++
	}

	var gcUp, gcLo, atUp, atLo, cpg int
	buf := f.mmap[pstart:oend]
	for i, v := range buf {
		// we added 1 to do the GC content...
		if i == len(buf)-1 {
			break
		}
		if v == 'G' || v == 'C' {
			if v == 'C' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcUp++
		} else if v == 'A' || v == 'T' {
			atUp++
		} else if v == 'g' || v == 'c' {
			if v == 'c' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcLo++
		} else if v == 'a' || v == 't' {
			atLo++
		}
	}
	tot := float64(gcUp + gcLo + atUp + atLo)
	if tot == 0.0 {
		return Stats{}, nil
	}
	return Stats{
		GC:     float64(gcLo+gcUp) / tot,
		Masked: float64(atLo+gcLo) / tot,
		CpG:    min(1.0, float64(2*cpg)/tot)}, nil
}

// At takes a single point and returns the single base.
func (f *Faidx) At(chrom string, pos int) (byte, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return '*', fmt.Errorf("unknown sequence %s", chrom)
	}

	ppos := position(idx, pos)
	return f.mmap[ppos], nil
}

// Close the associated Reader.
func (f *Faidx) Close() {
	f.rdr.(io.Closer).Close()
	f.mmap.Unmap()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"os/exec"

	"github.com/coreos/go-systemd/unit"
)

const (
	networkBase       = "/etc/systemd/network"
	ethernetService   = "fconf-wired.network"
	wirelessService   = "fconf-wireless.network"
	accessPointConfig = "create_ap.conf"
	enableFlag        = "enable"
	disableFlag       = "disable"
	removeFlag        = "remove"
	configFlag        = "config"
	fconfConfigDir    = "/etc/fconf"
)

//Ethernet is the ehternet configuration.
type Ethernet struct {
	Network
}

//ToSystemdUnit implement UnitFile interface
func (e Ethernet) ToSystemdUnit() ([]*unit.UnitOption, error) {
	if e.Interface == "" {
		e.Interface = "eth0"
	}
	return e.Network.ToSystemdUnit()
}

//Wifi is the wifi configuration.
type Wifi struct {
	Network
	Username string `json:"ssid"`
	Password string `json:"password"`
}

//UnitFile is an interface for systemd uni file
type UnitFile interface {
	ToSystemdUnit() ([]*unit.UnitOption, error)
}

//ToSystemdUnit implement UnitFile interface
func (w Wifi) ToSystemdUnit() ([]*unit.UnitOption, error) {
	if w.Interface == "" {
		w.Interface = "wlan0"
	}
	return w.Network.ToSystemdUnit()
}

//CreateSystemdFile creates a file that has systemd unit file content.
func CreateSystemdFile(u UnitFile, filename string, mode os.FileMode, out ...io.Writer) error {
	x, err := u.ToSystemdUnit()
	if err != nil {
		return err
	}
	r := unit.Serialize(x)
	if len(out) > 0 {
		_, err := io.Copy(out[0], r)
		return err
	}
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return err
	}
	defer func() {
		_ = f.Close()
	}()
	_, err = io.Copy(f, r)
	return err
}

// Checks if the directory exists. If the directory doesnt exist, this function
// will create the directory with permission 0755.
//
// The directory created will recursively create subdirectory. It will behave
// something like mkdir -p /dir/subdir.
func checkDir(dir string) error {
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		err = os.MkdirAll(dir, 07755)
		if err != nil {
			return err
		}
	}
	return nil
}

func restartService(name string) error {
	fmt.Print("restarting ", name, "...")
	_, err := exec.Command("systemctl", "restart", name).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}

func startService(name string) error {
	fmt.Print("starting ", name, "...")
	_, err := exec.Command("systemctl", "start", name).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}

func enableService(name string) error {
	fmt.Print("enabling ", name, "...")
	_, err := exec.Command("systemctl", "enable", name).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}
func disableService(name string) error {
	fmt.Print("disabling ", name, "...")
	_, err := exec.Command("systemctl", "disable", name).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}

func stopService(name string) error {
	fmt.Print("disabling ", name, "...")
	_, err := exec.Command("systemctl", "stop", name).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}
<commit_msg>Re factor systemd commands<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"os/exec"

	"github.com/coreos/go-systemd/unit"
)

const (
	networkBase       = "/etc/systemd/network"
	ethernetService   = "fconf-wired.network"
	wirelessService   = "fconf-wireless.network"
	accessPointConfig = "create_ap.conf"
	enableFlag        = "enable"
	disableFlag       = "disable"
	removeFlag        = "remove"
	configFlag        = "config"
	fconfConfigDir    = "/etc/fconf"
)

//Ethernet is the ehternet configuration.
type Ethernet struct {
	Network
}

//ToSystemdUnit implement UnitFile interface
func (e Ethernet) ToSystemdUnit() ([]*unit.UnitOption, error) {
	if e.Interface == "" {
		e.Interface = "eth0"
	}
	return e.Network.ToSystemdUnit()
}

//Wifi is the wifi configuration.
type Wifi struct {
	Network
	Username string `json:"ssid"`
	Password string `json:"password"`
}

//UnitFile is an interface for systemd uni file
type UnitFile interface {
	ToSystemdUnit() ([]*unit.UnitOption, error)
}

//ToSystemdUnit implement UnitFile interface
func (w Wifi) ToSystemdUnit() ([]*unit.UnitOption, error) {
	if w.Interface == "" {
		w.Interface = "wlan0"
	}
	return w.Network.ToSystemdUnit()
}

//CreateSystemdFile creates a file that has systemd unit file content.
func CreateSystemdFile(u UnitFile, filename string, mode os.FileMode, out ...io.Writer) error {
	x, err := u.ToSystemdUnit()
	if err != nil {
		return err
	}
	r := unit.Serialize(x)
	if len(out) > 0 {
		_, err := io.Copy(out[0], r)
		return err
	}
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return err
	}
	defer func() {
		_ = f.Close()
	}()
	_, err = io.Copy(f, r)
	return err
}

// Checks if the directory exists. If the directory doesnt exist, this function
// will create the directory with permission 0755.
//
// The directory created will recursively create subdirectory. It will behave
// something like mkdir -p /dir/subdir.
func checkDir(dir string) error {
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		err = os.MkdirAll(dir, 07755)
		if err != nil {
			return err
		}
	}
	return nil
}

func restartService(name string) error {
	return systemdCMD("restart", name)
}

func startService(name string) error {
	return systemdCMD("start", name)
}

func enableService(name string) error {
	return systemdCMD("enable", name)
}
func disableService(name string) error {
	return systemdCMD("disable", name)
}

func stopService(name string) error {
	return systemdCMD("stop", name)
}

func systemdCMD(name, service string) error {
	fmt.Printf("%s %s ...", name, service)
	_, err := exec.Command("systemctl", name, service).Output()
	if err != nil {
		fmt.Println("done with error")
		return err
	}
	fmt.Println("done without error")
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package priorityclass

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"

	v1 "k8s.io/api/scheduling/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/tools/cache"
	"k8s.io/klog"

	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/conversion"
	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/metrics"
)

var numMissMatchedPriorityClasses uint64

func (c *controller) StartPatrol(stopCh <-chan struct{}) error {
	if !cache.WaitForCacheSync(stopCh, c.priorityclassSynced) {
		return fmt.Errorf("failed to wait for caches to sync before starting Service checker")
	}
	c.priorityClassPatroller.Start(stopCh)
	return nil
}

// ParollerDo check if PriorityClass keeps consistency between super master and tenant masters.
func (c *controller) PatrollerDo() {
	clusterNames := c.multiClusterPriorityClassController.GetClusterNames()
	if len(clusterNames) == 0 {
		klog.Infof("tenant masters has no clusters, give up priority class period checker")
		return
	}

	wg := sync.WaitGroup{}
	numMissMatchedPriorityClasses = 0

	for _, clusterName := range clusterNames {
		wg.Add(1)
		go func(clusterName string) {
			defer wg.Done()
			c.checkPriorityClassOfTenantCluster(clusterName)
		}(clusterName)
	}
	wg.Wait()

	pPriorityClassList, err := c.priorityclassLister.List(labels.Everything())
	if err != nil {
		klog.Errorf("error listing priorityclass from super master informer cache: %v", err)
		return
	}

	for _, pPriorityClass := range pPriorityClassList {
		if !publicPriorityClass(pPriorityClass) {
			klog.V(4).Infof("%v is not public priority class", pPriorityClass.Name)
			continue
		}
		for _, clusterName := range clusterNames {
			_, err := c.multiClusterPriorityClassController.Get(clusterName, "", pPriorityClass.Name)
			if err != nil {
				if errors.IsNotFound(err) {
					klog.Infof("will add to upward controller queue +++++++++++")
					metrics.CheckerRemedyStats.WithLabelValues("RequeuedSuperMasterPriorityClasses").Inc()
					c.upwardPriorityClassController.AddToQueue(clusterName + "/" + pPriorityClass.Name)
				}
				klog.Errorf("fail to get priorityclass from cluster %s: %v", clusterName, err)
			}
		}
	}

	metrics.CheckerMissMatchStats.WithLabelValues("MissMatchedPriorityClasses").Set(float64(numMissMatchedPriorityClasses))
}

func (c *controller) checkPriorityClassOfTenantCluster(clusterName string) {
	listObj, err := c.multiClusterPriorityClassController.List(clusterName)
	if err != nil {
		klog.Errorf("error listing priorityclass from cluster %s informer cache: %v", clusterName, err)
		return
	}
	klog.V(4).Infof("check priorityclass consistency in cluster %s", clusterName)
	scList := listObj.(*v1.PriorityClassList)
	for i, vPriorityClass := range scList.Items {
		pPriorityClass, err := c.priorityclassLister.Get(vPriorityClass.Name)
		klog.V(4).Infof("get priority class %v from super cluster, virtual priority class%v", pPriorityClass.Name, pPriorityClass.Name)
		if errors.IsNotFound(err) {
			// super master is the source of the truth for sc object, delete tenant master obj
			tenantClient, err := c.multiClusterPriorityClassController.GetClusterClient(clusterName)
			if err != nil {
				klog.Errorf("error getting cluster %s clientset: %v", clusterName, err)
				continue
			}
			opts := &metav1.DeleteOptions{
				PropagationPolicy: &constants.DefaultDeletionPolicy,
			}
			if err := tenantClient.SchedulingV1().PriorityClasses().Delete(context.TODO(), vPriorityClass.Name, *opts); err != nil {
				klog.Errorf("error deleting priorityclass %v in cluster %s: %v", vPriorityClass.Name, clusterName, err)
			} else {
				metrics.CheckerRemedyStats.WithLabelValues("DeletedOrphanTenantPriorityClasses").Inc()
			}
			continue
		}

		if err != nil {
			klog.Errorf("failed to get pPriorityClass %s from super master cache: %v", vPriorityClass.Name, err)
			continue
		}

		updatedPriorityClass := conversion.Equality(nil, nil).CheckPriorityClassEquality(pPriorityClass, &scList.Items[i])
		if updatedPriorityClass != nil {
			atomic.AddUint64(&numMissMatchedPriorityClasses, 1)
			klog.Warningf("spec of priorityClass %v diff in super&tenant master", vPriorityClass.Name)
			if publicPriorityClass(pPriorityClass) {
				c.upwardPriorityClassController.AddToQueue(clusterName + "/" + pPriorityClass.Name)
			}
		}
	}
}
<commit_msg>Add priority class syncer (priority class is an extra resource, needs to be activated using --extra-syncing-resources flag)<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package priorityclass

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"

	v1 "k8s.io/api/scheduling/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/tools/cache"
	"k8s.io/klog"

	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/conversion"
	"sigs.k8s.io/multi-tenancy/incubator/virtualcluster/pkg/syncer/metrics"
)

var numMissMatchedPriorityClasses uint64

func (c *controller) StartPatrol(stopCh <-chan struct{}) error {
	if !cache.WaitForCacheSync(stopCh, c.priorityclassSynced) {
		return fmt.Errorf("failed to wait for caches to sync before starting Service checker")
	}
	c.priorityClassPatroller.Start(stopCh)
	return nil
}

// ParollerDo check if PriorityClass keeps consistency between super master and tenant masters.
func (c *controller) PatrollerDo() {
	clusterNames := c.multiClusterPriorityClassController.GetClusterNames()
	if len(clusterNames) == 0 {
		klog.Infof("tenant masters has no clusters, give up priority class period checker")
		return
	}

	wg := sync.WaitGroup{}
	numMissMatchedPriorityClasses = 0

	for _, clusterName := range clusterNames {
		wg.Add(1)
		go func(clusterName string) {
			defer wg.Done()
			c.checkPriorityClassOfTenantCluster(clusterName)
		}(clusterName)
	}
	wg.Wait()
	pPriorityClassList, err := c.priorityclassLister.List(labels.Everything())
	if err != nil {
		klog.Errorf("error listing priorityclass from super master informer cache: %v", err)
		return
	}

	for _, pPriorityClass := range pPriorityClassList {
		if !publicPriorityClass(pPriorityClass) {
			klog.V(4).Infof("%v is not public priority class", pPriorityClass.Name)
			continue
		}
		for _, clusterName := range clusterNames {
			_, err := c.multiClusterPriorityClassController.Get(clusterName, "", pPriorityClass.Name)
			if err != nil {
				if errors.IsNotFound(err) {
					klog.Infof("will add to upward controller queue +++++++++++")
					metrics.CheckerRemedyStats.WithLabelValues("RequeuedSuperMasterPriorityClasses").Inc()
					c.upwardPriorityClassController.AddToQueue(clusterName + "/" + pPriorityClass.Name)
				}
				klog.Errorf("fail to get priorityclass from cluster %s: %v", clusterName, err)
			}
		}
	}
	metrics.CheckerMissMatchStats.WithLabelValues("MissMatchedPriorityClasses").Set(float64(numMissMatchedPriorityClasses))
}

func (c *controller) checkPriorityClassOfTenantCluster(clusterName string) {
	listObj, err := c.multiClusterPriorityClassController.List(clusterName)
	if err != nil {
		klog.Errorf("error listing priorityclass from cluster %s informer cache: %v", clusterName, err)
		return
	}
	klog.V(4).Infof("check priorityclass consistency in cluster %s", clusterName)
	scList := listObj.(*v1.PriorityClassList)
	for i, vPriorityClass := range scList.Items {
		pPriorityClass, err := c.priorityclassLister.Get(vPriorityClass.Name)
		klog.V(4).Infof("get priority class %v from super cluster, virtual priority class%v", pPriorityClass.Name, pPriorityClass.Name)
		if errors.IsNotFound(err) {
			// super master is the source of the truth for sc object, delete tenant master obj
			tenantClient, err := c.multiClusterPriorityClassController.GetClusterClient(clusterName)
			if err != nil {
				klog.Errorf("error getting cluster %s clientset: %v", clusterName, err)
				continue
			}
			opts := &metav1.DeleteOptions{
				PropagationPolicy: &constants.DefaultDeletionPolicy,
			}
			if err := tenantClient.SchedulingV1().PriorityClasses().Delete(context.TODO(), vPriorityClass.Name, *opts); err != nil {
				klog.Errorf("error deleting priorityclass %v in cluster %s: %v", vPriorityClass.Name, clusterName, err)
			} else {
				metrics.CheckerRemedyStats.WithLabelValues("DeletedOrphanTenantPriorityClasses").Inc()
			}
			continue
		}

		if err != nil {
			klog.Errorf("failed to get pPriorityClass %s from super master cache: %v", vPriorityClass.Name, err)
			continue
		}

		updatedPriorityClass := conversion.Equality(nil, nil).CheckPriorityClassEquality(pPriorityClass, &scList.Items[i])
		if updatedPriorityClass != nil {
			atomic.AddUint64(&numMissMatchedPriorityClasses, 1)
			klog.Warningf("spec of priorityClass %v diff in super&tenant master", vPriorityClass.Name)
			if publicPriorityClass(pPriorityClass) {
				c.upwardPriorityClassController.AddToQueue(clusterName + "/" + pPriorityClass.Name)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Eleme Inc. All rights reserved.

// Package alerter implements an alerter to send sms/email messages
// on anomalies found.
package alerter

import (
	"encoding/json"
	"os/exec"
	"sync/atomic"
	"time"

	"github.com/eleme/banshee/config"
	"github.com/eleme/banshee/models"
	"github.com/eleme/banshee/storage"
	"github.com/eleme/banshee/util/log"
	"github.com/eleme/banshee/util/safemap"
)

// Limit for buffered detected metric results, further results will be dropped
// if this limit is reached.
const bufferedMetricResultsLimit = 10 * 1024

// Alerter alerts on anomalies detected.
type Alerter struct {
	// Storage
	db *storage.DB
	// Config
	cfg *config.Config
	// Input
	In chan *models.Metric
	// Alertings stamps
	m *safemap.SafeMap
	// Alertings counters
	c *safemap.SafeMap
}

// Alerting message.
type msg struct {
	Project *models.Project `json:"project"`
	Metric  *models.Metric  `json:"metric"`
	User    *models.User    `json:"user"`
}

// New creates a alerter.
func New(cfg *config.Config, db *storage.DB) *Alerter {
	al := new(Alerter)
	al.cfg = cfg
	al.db = db
	al.In = make(chan *models.Metric, bufferedMetricResultsLimit)
	al.m = safemap.New()
	al.c = safemap.New()
	return al
}

// Start several goroutines to wait for detected metrics, then check each
// metric with all the rules, the configured shell command will be executed
// once a rule is hit.
func (al *Alerter) Start() {
	log.Info("start %d alerter workers..", al.cfg.Alerter.Workers)
	for i := 0; i < al.cfg.Alerter.Workers; i++ {
		go al.work()
	}
	go func() {
		ticker := time.NewTicker(time.Hour * 24)
		for _ = range ticker.C {
			al.c.Clear()
		}
	}()
}

// work waits for detected metrics, then check each metric with all the
// rules, the configured shell command will be executed once a rule is hit.
func (al *Alerter) work() {
	for {
		metric := <-al.In
		// Check interval.
		v, ok := al.m.Get(metric.Name)
		if ok && metric.Stamp-v.(uint32) < al.cfg.Alerter.Interval {
			return
		}
		// Check alert times in one day
		v, ok = al.c.Get(metric.Name)
		if ok && atomic.LoadUint32(v.(*uint32)) > al.cfg.Alerter.OneDayLimit {
			return
		}
		if !ok {
			var newCounter uint32
			newCounter = 1
			al.c.Set(metric.Name, &newCounter)
		} else {
			atomic.AddUint32(v.(*uint32), 1)
		}
		// Project
		var proj *models.Project
		if err := al.db.Admin.DB().Model(&models.Rule{}).Related(proj); err != nil {
			log.Error("project not found, %v, skiping..", err)
			continue
		}
		// Users
		var users []models.User
		if err := al.db.Admin.DB().Model(proj).Related(&users, "Users"); err != nil {
			log.Error("get users: %v, skiping..", err)
			continue
		}
		// Universals
		var univs []models.User
		if err := al.db.Admin.DB().Where("universal = ?", true).Find(&univs); err != nil {
			log.Error("get universal users: %v, skiping..", err)
			continue
		}
		users = append(users, univs...)
		// Send
		for _, user := range users {
			d := &msg{
				Project: proj,
				Metric:  metric,
				User:    &user,
			}
			// Exec
			if len(al.cfg.Alerter.Command) == 0 {
				log.Warn("alert command not configured")
				continue
			}
			b, _ := json.Marshal(d)
			cmd := exec.Command(al.cfg.Alerter.Command, string(b))
			if err := cmd.Run(); err != nil {
				log.Error("exec %s: %v", al.cfg.Alerter.Command, err)
			}
		}
		if len(users) != 0 {
			al.m.Set(metric.Name, metric.Stamp)
		}
	}
}
<commit_msg>Fix call of reflect.Value.Type on zero Value<commit_after>// Copyright 2015 Eleme Inc. All rights reserved.

// Package alerter implements an alerter to send sms/email messages
// on anomalies found.
package alerter

import (
	"encoding/json"
	"os/exec"
	"sync/atomic"
	"time"

	"github.com/eleme/banshee/config"
	"github.com/eleme/banshee/models"
	"github.com/eleme/banshee/storage"
	"github.com/eleme/banshee/util/log"
	"github.com/eleme/banshee/util/safemap"
)

// Limit for buffered detected metric results, further results will be dropped
// if this limit is reached.
const bufferedMetricResultsLimit = 10 * 1024

// Alerter alerts on anomalies detected.
type Alerter struct {
	// Storage
	db *storage.DB
	// Config
	cfg *config.Config
	// Input
	In chan *models.Metric
	// Alertings stamps
	m *safemap.SafeMap
	// Alertings counters
	c *safemap.SafeMap
}

// Alerting message.
type msg struct {
	Project *models.Project `json:"project"`
	Metric  *models.Metric  `json:"metric"`
	User    *models.User    `json:"user"`
}

// New creates a alerter.
func New(cfg *config.Config, db *storage.DB) *Alerter {
	al := new(Alerter)
	al.cfg = cfg
	al.db = db
	al.In = make(chan *models.Metric, bufferedMetricResultsLimit)
	al.m = safemap.New()
	al.c = safemap.New()
	return al
}

// Start several goroutines to wait for detected metrics, then check each
// metric with all the rules, the configured shell command will be executed
// once a rule is hit.
func (al *Alerter) Start() {
	log.Info("start %d alerter workers..", al.cfg.Alerter.Workers)
	for i := 0; i < al.cfg.Alerter.Workers; i++ {
		go al.work()
	}
	go func() {
		ticker := time.NewTicker(time.Hour * 24)
		for _ = range ticker.C {
			al.c.Clear()
		}
	}()
}

// work waits for detected metrics, then check each metric with all the
// rules, the configured shell command will be executed once a rule is hit.
func (al *Alerter) work() {
	for {
		metric := <-al.In
		// Check interval.
		v, ok := al.m.Get(metric.Name)
		if ok && metric.Stamp-v.(uint32) < al.cfg.Alerter.Interval {
			return
		}
		// Check alert times in one day
		v, ok = al.c.Get(metric.Name)
		if ok && atomic.LoadUint32(v.(*uint32)) > al.cfg.Alerter.OneDayLimit {
			return
		}
		if !ok {
			var newCounter uint32
			newCounter = 1
			al.c.Set(metric.Name, &newCounter)
		} else {
			atomic.AddUint32(v.(*uint32), 1)
		}
		// Project
		proj := &models.Project{}
		if err := al.db.Admin.DB().Model(&models.Rule{}).Related(proj); err != nil {
			log.Error("project not found, %v, skiping..", err)
			continue
		}
		// Users
		var users []models.User
		if err := al.db.Admin.DB().Model(proj).Related(&users, "Users"); err != nil {
			log.Error("get users: %v, skiping..", err)
			continue
		}
		// Universals
		var univs []models.User
		if err := al.db.Admin.DB().Where("universal = ?", true).Find(&univs); err != nil {
			log.Error("get universal users: %v, skiping..", err)
			continue
		}
		users = append(users, univs...)
		// Send
		for _, user := range users {
			d := &msg{
				Project: proj,
				Metric:  metric,
				User:    &user,
			}
			// Exec
			if len(al.cfg.Alerter.Command) == 0 {
				log.Warn("alert command not configured")
				continue
			}
			b, _ := json.Marshal(d)
			cmd := exec.Command(al.cfg.Alerter.Command, string(b))
			if err := cmd.Run(); err != nil {
				log.Error("exec %s: %v", al.cfg.Alerter.Command, err)
			}
		}
		if len(users) != 0 {
			al.m.Set(metric.Name, metric.Stamp)
		}
	}
}
<|endoftext|>


<commit_before>package algorithm

//Stack
//author:Xiong Chuan Liang
//date:2015-1-30

import (
	"errors"
	"fmt"
)

type Stack struct {
	Element []interface{} //Element
}

func NewStack() *Stack {
	return &Stack{}
}

func (stack *Stack)Push(value ...interface{}){
	stack.Element = append(stack.Element,value...)
}

//从Stack移除元素
func (stack *Stack)Pop()(err error){
	if stack.Size()> 0 {
		stack.Element = stack.Element[:stack.Size() - 1]
		return nil
	}
	return errors.New("Stack为空.") //read empty stack
}

//返回下一个元素
func (stack *Stack)Top()(value interface{}){
	if stack.Size() > 0 {
		return stack.Element[stack.Size() - 1]
	}
	return nil //read empty stack
}

//交换值
func (stack *Stack)Swap(other *Stack){
	switch{
	case stack.Size() == 0 && other.Size() == 0:
		return
	case other.Size() == 0 :
		other.Element = stack.Element[:stack.Size()]
		stack.Element = nil
	case stack.Size()== 0 :
		stack.Element = other.Element
		other.Element = nil
	default:
		stack.Element,other.Element = other.Element,stack.Element
	}
	return
}

//修改指定索引的值
func (stack *Stack)Set(idx int,value interface{})(err error){
	if idx >= 0 && stack.Size() > 0 && stack.Size() > idx{
		stack.Element[idx] = value
		return nil
	}
	return errors.New("Set失败!")
}

//Stack的size
func (stack *Stack)Size()(int){
	return len(stack.Element)
}

//是否为空
func (stack *Stack)Empty()(bool){
	if stack.Element == nil || stack.Size() == 0 {
		return true
	}
	return false
}

//打印
func (stack *Stack)Print(){
	for i := len(stack.Element) - 1; i >= 0; i--{
		fmt.Println(i,"=>",stack.Element[i])
	}
}
<commit_msg>Update stack.go<commit_after>package algorithm

//Stack
//author:Xiong Chuan Liang
//date:2015-1-30

import (
	"errors"
	"fmt"
)

type Stack struct {
	Element []interface{} //Element
}

func NewStack() *Stack {
	return &Stack{}
}

func (stack *Stack)Push(value ...interface{}){
	stack.Element = append(stack.Element,value...)
}

//返回下一个元素
func (stack *Stack)Top()(value interface{}){
	if stack.Size() > 0 {
		return stack.Element[stack.Size() - 1]
	}
	return nil //read empty stack
}

//返回下一个元素,并从Stack移除元素
func (stack *Stack)Pop()(err error){
	if stack.Size()> 0 {
		stack.Element = stack.Element[:stack.Size() - 1]
		return nil
	}
	return errors.New("Stack为空.") //read empty stack
}

//交换值
func (stack *Stack)Swap(other *Stack){
	switch{
	case stack.Size() == 0 && other.Size() == 0:
		return
	case other.Size() == 0 :
		other.Element = stack.Element[:stack.Size()]
		stack.Element = nil
	case stack.Size()== 0 :
		stack.Element = other.Element
		other.Element = nil
	default:
		stack.Element,other.Element = other.Element,stack.Element
	}
	return
}

//修改指定索引的元素
func (stack *Stack)Set(idx int,value interface{})(err error){
	if idx >= 0 && stack.Size() > 0 && stack.Size() > idx{
		stack.Element[idx] = value
		return nil
	}
	return errors.New("Set失败!")
}

//返回指定索引的元素
func (stack *Stack)Peek(idx int)(value interface{}){
	if idx >= 0 && stack.Size() > 0 && stack.Size() > idx {
		return stack.Element[idx]
	}
	return nil //read empty stack
}

//Stack的size
func (stack *Stack)Size()(int){
	return len(stack.Element)
}

//是否为空
func (stack *Stack)Empty()(bool){
	if stack.Element == nil || stack.Size() == 0 {
		return true
	}
	return false
}

//打印
func (stack *Stack)Print(){
	for i := len(stack.Element) - 1; i >= 0; i--{
		fmt.Println(i,"=>",stack.Element[i])
	}
}
<|endoftext|>


<commit_before>// +build !js

package webrtc

import (
	"encoding/json"
	"fmt"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestStatsTimestampTime(t *testing.T) {
	for _, test := range []struct {
		Timestamp StatsTimestamp
		WantTime  time.Time
	}{
		{
			Timestamp: 0,
			WantTime:  time.Unix(0, 0),
		},
		{
			Timestamp: 1,
			WantTime:  time.Unix(0, 1e6),
		},
		{
			Timestamp: 0.001,
			WantTime:  time.Unix(0, 1e3),
		},
	} {
		if got, want := test.Timestamp.Time(), test.WantTime.UTC(); got != want {
			t.Fatalf("StatsTimestamp(%v).Time() = %v, want %v", test.Timestamp, got, want)
		}
	}
}

// TODO(maxhawkins): replace with a more meaningful test
func TestStatsMarshal(t *testing.T) {
	for _, test := range []Stats{
		AudioReceiverStats{},
		AudioSenderStats{},
		CertificateStats{},
		CodecStats{},
		DataChannelStats{},
		ICECandidatePairStats{},
		ICECandidateStats{},
		InboundRTPStreamStats{},
		MediaStreamStats{},
		OutboundRTPStreamStats{},
		PeerConnectionStats{},
		RemoteInboundRTPStreamStats{},
		RemoteOutboundRTPStreamStats{},
		RTPContributingSourceStats{},
		SenderAudioTrackAttachmentStats{},
		SenderAudioTrackAttachmentStats{},
		SenderVideoTrackAttachmentStats{},
		TransportStats{},
		VideoReceiverStats{},
		VideoReceiverStats{},
		VideoSenderStats{},
	} {
		_, err := json.Marshal(test)
		if err != nil {
			t.Fatal(err)
		}
	}
}

func waitWithTimeout(t *testing.T, wg *sync.WaitGroup) {
	// Wait for all of the event handlers to be triggered.
	done := make(chan struct{})
	go func() {
		wg.Wait()
		done <- struct{}{}
	}()
	timeout := time.After(5 * time.Second)
	select {
	case <-done:
		break
	case <-timeout:
		t.Fatal("timed out waiting for waitgroup")
	}
}

func getConnectionStats(t *testing.T, report StatsReport, pc *PeerConnection) PeerConnectionStats {
	stats, ok := report.GetConnectionStats(pc)
	assert.True(t, ok)
	assert.Equal(t, stats.Type, StatsTypePeerConnection)
	return stats
}

func getDataChannelStats(t *testing.T, report StatsReport, dc *DataChannel) DataChannelStats {
	stats, ok := report.GetDataChannelStats(dc)
	assert.True(t, ok)
	assert.Equal(t, stats.Type, StatsTypeDataChannel)
	return stats
}

func getTransportStats(t *testing.T, report StatsReport, statsID string) TransportStats {
	stats, ok := report[statsID]
	assert.True(t, ok)
	transportStats, ok := stats.(TransportStats)
	assert.True(t, ok)
	assert.Equal(t, transportStats.Type, StatsTypeTransport)
	return transportStats
}

func findLocalCandidateStats(report StatsReport) []ICECandidateStats {
	result := []ICECandidateStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidateStats)
		if ok && stats.Type == StatsTypeLocalCandidate {
			result = append(result, stats)
		}
	}
	return result
}

func findRemoteCandidateStats(report StatsReport) []ICECandidateStats {
	result := []ICECandidateStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidateStats)
		if ok && stats.Type == StatsTypeRemoteCandidate {
			result = append(result, stats)
		}
	}
	return result
}

func findCandidatePairStats(t *testing.T, report StatsReport) []ICECandidatePairStats {
	result := []ICECandidatePairStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidatePairStats)
		if ok {
			assert.Equal(t, StatsTypeCandidatePair, stats.Type)
			result = append(result, stats)
		}
	}
	return result
}

func signalPairForStats(pcOffer *PeerConnection, pcAnswer *PeerConnection) error {
	offerChan := make(chan SessionDescription)
	pcOffer.OnICECandidate(func(candidate *ICECandidate) {
		if candidate == nil {
			offerChan <- *pcOffer.PendingLocalDescription()
		}
	})

	offer, err := pcOffer.CreateOffer(nil)
	if err != nil {
		return err
	}
	if err := pcOffer.SetLocalDescription(offer); err != nil {
		return err
	}

	timeout := time.After(3 * time.Second)
	select {
	case <-timeout:
		return fmt.Errorf("timed out waiting to receive offer")
	case offer := <-offerChan:
		if err := pcAnswer.SetRemoteDescription(offer); err != nil {
			return err
		}

		answer, err := pcAnswer.CreateAnswer(nil)
		if err != nil {
			return err
		}

		if err = pcAnswer.SetLocalDescription(answer); err != nil {
			return err
		}

		err = pcOffer.SetRemoteDescription(answer)
		if err != nil {
			return err
		}
		return nil
	}
}

func TestPeerConnection_GetStats(t *testing.T) {
	offerPC, answerPC, err := newPair()
	assert.NoError(t, err)

	baseLineReportPCOffer := offerPC.GetStats()
	baseLineReportPCAnswer := answerPC.GetStats()

	connStatsOffer := getConnectionStats(t, baseLineReportPCOffer, offerPC)
	connStatsAnswer := getConnectionStats(t, baseLineReportPCAnswer, answerPC)

	for _, connStats := range []PeerConnectionStats{connStatsOffer, connStatsAnswer} {
		assert.Equal(t, uint32(0), connStats.DataChannelsOpened)
		assert.Equal(t, uint32(0), connStats.DataChannelsClosed)
		assert.Equal(t, uint32(0), connStats.DataChannelsRequested)
		assert.Equal(t, uint32(0), connStats.DataChannelsAccepted)
	}

	// Create a DC, open it and send a message
	offerDC, err := offerPC.CreateDataChannel("offerDC", nil)
	assert.NoError(t, err)

	msg := []byte("a classic test message")
	offerDC.OnOpen(func() {
		assert.NoError(t, offerDC.Send(msg))
	})

	dcWait := sync.WaitGroup{}
	dcWait.Add(1)

	answerDCChan := make(chan *DataChannel)
	answerPC.OnDataChannel(func(d *DataChannel) {
		d.OnOpen(func() {
			answerDCChan <- d
		})
		d.OnMessage(func(m DataChannelMessage) {
			dcWait.Done()
		})
	})

	assert.NoError(t, signalPairForStats(offerPC, answerPC))
	waitWithTimeout(t, &dcWait)

	answerDC := <-answerDCChan

	reportPCOffer := offerPC.GetStats()
	reportPCAnswer := answerPC.GetStats()

	connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsClosed)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
	dcStatsOffer := getDataChannelStats(t, reportPCOffer, offerDC)
	assert.Equal(t, DataChannelStateOpen, dcStatsOffer.State)
	assert.Equal(t, uint32(1), dcStatsOffer.MessagesSent)
	assert.Equal(t, uint64(len(msg)), dcStatsOffer.BytesSent)
	assert.NotEmpty(t, findLocalCandidateStats(reportPCOffer))
	assert.NotEmpty(t, findRemoteCandidateStats(reportPCOffer))
	assert.NotEmpty(t, findCandidatePairStats(t, reportPCOffer))

	connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsClosed)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
	dcStatsAnswer := getDataChannelStats(t, reportPCAnswer, answerDC)
	assert.Equal(t, DataChannelStateOpen, dcStatsAnswer.State)
	assert.Equal(t, uint32(1), dcStatsAnswer.MessagesReceived)
	assert.Equal(t, uint64(len(msg)), dcStatsAnswer.BytesReceived)
	assert.NotEmpty(t, findLocalCandidateStats(reportPCAnswer))
	assert.NotEmpty(t, findRemoteCandidateStats(reportPCAnswer))
	assert.NotEmpty(t, findCandidatePairStats(t, reportPCAnswer))

	// Close answer DC now
	dcWait = sync.WaitGroup{}
	dcWait.Add(1)
	offerDC.OnClose(func() {
		dcWait.Done()
	})
	assert.NoError(t, answerDC.Close())
	waitWithTimeout(t, &dcWait)

	reportPCOffer = offerPC.GetStats()
	reportPCAnswer = answerPC.GetStats()

	connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsClosed)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
	dcStatsOffer = getDataChannelStats(t, reportPCOffer, offerDC)
	assert.Equal(t, DataChannelStateClosed, dcStatsOffer.State)

	connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsClosed)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
	dcStatsAnswer = getDataChannelStats(t, reportPCAnswer, answerDC)
	assert.Equal(t, DataChannelStateClosed, dcStatsAnswer.State)

	answerICETransportStats := getTransportStats(t, reportPCAnswer, "iceTransport")
	offerICETransportStats := getTransportStats(t, reportPCOffer, "iceTransport")
	assert.GreaterOrEqual(t, offerICETransportStats.BytesSent, answerICETransportStats.BytesReceived)
	assert.GreaterOrEqual(t, answerICETransportStats.BytesSent, offerICETransportStats.BytesReceived)

	answerSCTPTransportStats := getTransportStats(t, reportPCAnswer, "sctpTransport")
	offerSCTPTransportStats := getTransportStats(t, reportPCOffer, "sctpTransport")
	assert.GreaterOrEqual(t, offerSCTPTransportStats.BytesSent, answerSCTPTransportStats.BytesReceived)
	assert.GreaterOrEqual(t, answerSCTPTransportStats.BytesSent, offerSCTPTransportStats.BytesReceived)

	assert.NoError(t, offerPC.Close())
	assert.NoError(t, answerPC.Close())
}

func TestPeerConnection_GetStats_Closed(t *testing.T) {
	pc, err := NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	assert.NoError(t, pc.Close())

	pc.GetStats()
}
<commit_msg>Fix TestPeerConnection_GetStats stability<commit_after>// +build !js

package webrtc

import (
	"encoding/json"
	"fmt"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestStatsTimestampTime(t *testing.T) {
	for _, test := range []struct {
		Timestamp StatsTimestamp
		WantTime  time.Time
	}{
		{
			Timestamp: 0,
			WantTime:  time.Unix(0, 0),
		},
		{
			Timestamp: 1,
			WantTime:  time.Unix(0, 1e6),
		},
		{
			Timestamp: 0.001,
			WantTime:  time.Unix(0, 1e3),
		},
	} {
		if got, want := test.Timestamp.Time(), test.WantTime.UTC(); got != want {
			t.Fatalf("StatsTimestamp(%v).Time() = %v, want %v", test.Timestamp, got, want)
		}
	}
}

// TODO(maxhawkins): replace with a more meaningful test
func TestStatsMarshal(t *testing.T) {
	for _, test := range []Stats{
		AudioReceiverStats{},
		AudioSenderStats{},
		CertificateStats{},
		CodecStats{},
		DataChannelStats{},
		ICECandidatePairStats{},
		ICECandidateStats{},
		InboundRTPStreamStats{},
		MediaStreamStats{},
		OutboundRTPStreamStats{},
		PeerConnectionStats{},
		RemoteInboundRTPStreamStats{},
		RemoteOutboundRTPStreamStats{},
		RTPContributingSourceStats{},
		SenderAudioTrackAttachmentStats{},
		SenderAudioTrackAttachmentStats{},
		SenderVideoTrackAttachmentStats{},
		TransportStats{},
		VideoReceiverStats{},
		VideoReceiverStats{},
		VideoSenderStats{},
	} {
		_, err := json.Marshal(test)
		if err != nil {
			t.Fatal(err)
		}
	}
}

func waitWithTimeout(t *testing.T, wg *sync.WaitGroup) {
	// Wait for all of the event handlers to be triggered.
	done := make(chan struct{})
	go func() {
		wg.Wait()
		done <- struct{}{}
	}()
	timeout := time.After(5 * time.Second)
	select {
	case <-done:
		break
	case <-timeout:
		t.Fatal("timed out waiting for waitgroup")
	}
}

func getConnectionStats(t *testing.T, report StatsReport, pc *PeerConnection) PeerConnectionStats {
	stats, ok := report.GetConnectionStats(pc)
	assert.True(t, ok)
	assert.Equal(t, stats.Type, StatsTypePeerConnection)
	return stats
}

func getDataChannelStats(t *testing.T, report StatsReport, dc *DataChannel) DataChannelStats {
	stats, ok := report.GetDataChannelStats(dc)
	assert.True(t, ok)
	assert.Equal(t, stats.Type, StatsTypeDataChannel)
	return stats
}

func getTransportStats(t *testing.T, report StatsReport, statsID string) TransportStats {
	stats, ok := report[statsID]
	assert.True(t, ok)
	transportStats, ok := stats.(TransportStats)
	assert.True(t, ok)
	assert.Equal(t, transportStats.Type, StatsTypeTransport)
	return transportStats
}

func findLocalCandidateStats(report StatsReport) []ICECandidateStats {
	result := []ICECandidateStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidateStats)
		if ok && stats.Type == StatsTypeLocalCandidate {
			result = append(result, stats)
		}
	}
	return result
}

func findRemoteCandidateStats(report StatsReport) []ICECandidateStats {
	result := []ICECandidateStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidateStats)
		if ok && stats.Type == StatsTypeRemoteCandidate {
			result = append(result, stats)
		}
	}
	return result
}

func findCandidatePairStats(t *testing.T, report StatsReport) []ICECandidatePairStats {
	result := []ICECandidatePairStats{}
	for _, s := range report {
		stats, ok := s.(ICECandidatePairStats)
		if ok {
			assert.Equal(t, StatsTypeCandidatePair, stats.Type)
			result = append(result, stats)
		}
	}
	return result
}

func signalPairForStats(pcOffer *PeerConnection, pcAnswer *PeerConnection) error {
	offerChan := make(chan SessionDescription)
	pcOffer.OnICECandidate(func(candidate *ICECandidate) {
		if candidate == nil {
			offerChan <- *pcOffer.PendingLocalDescription()
		}
	})

	offer, err := pcOffer.CreateOffer(nil)
	if err != nil {
		return err
	}
	if err := pcOffer.SetLocalDescription(offer); err != nil {
		return err
	}

	timeout := time.After(3 * time.Second)
	select {
	case <-timeout:
		return fmt.Errorf("timed out waiting to receive offer")
	case offer := <-offerChan:
		if err := pcAnswer.SetRemoteDescription(offer); err != nil {
			return err
		}

		answer, err := pcAnswer.CreateAnswer(nil)
		if err != nil {
			return err
		}

		if err = pcAnswer.SetLocalDescription(answer); err != nil {
			return err
		}

		err = pcOffer.SetRemoteDescription(answer)
		if err != nil {
			return err
		}
		return nil
	}
}

func TestPeerConnection_GetStats(t *testing.T) {
	offerPC, answerPC, err := newPair()
	assert.NoError(t, err)

	baseLineReportPCOffer := offerPC.GetStats()
	baseLineReportPCAnswer := answerPC.GetStats()

	connStatsOffer := getConnectionStats(t, baseLineReportPCOffer, offerPC)
	connStatsAnswer := getConnectionStats(t, baseLineReportPCAnswer, answerPC)

	for _, connStats := range []PeerConnectionStats{connStatsOffer, connStatsAnswer} {
		assert.Equal(t, uint32(0), connStats.DataChannelsOpened)
		assert.Equal(t, uint32(0), connStats.DataChannelsClosed)
		assert.Equal(t, uint32(0), connStats.DataChannelsRequested)
		assert.Equal(t, uint32(0), connStats.DataChannelsAccepted)
	}

	// Create a DC, open it and send a message
	offerDC, err := offerPC.CreateDataChannel("offerDC", nil)
	assert.NoError(t, err)

	msg := []byte("a classic test message")
	offerDC.OnOpen(func() {
		assert.NoError(t, offerDC.Send(msg))
	})

	dcWait := sync.WaitGroup{}
	dcWait.Add(1)

	answerDCChan := make(chan *DataChannel)
	answerPC.OnDataChannel(func(d *DataChannel) {
		d.OnOpen(func() {
			answerDCChan <- d
		})
		d.OnMessage(func(m DataChannelMessage) {
			dcWait.Done()
		})
	})

	assert.NoError(t, signalPairForStats(offerPC, answerPC))
	waitWithTimeout(t, &dcWait)

	answerDC := <-answerDCChan

	reportPCOffer := offerPC.GetStats()
	reportPCAnswer := answerPC.GetStats()

	connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsClosed)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
	dcStatsOffer := getDataChannelStats(t, reportPCOffer, offerDC)
	assert.Equal(t, DataChannelStateOpen, dcStatsOffer.State)
	assert.Equal(t, uint32(1), dcStatsOffer.MessagesSent)
	assert.Equal(t, uint64(len(msg)), dcStatsOffer.BytesSent)
	assert.NotEmpty(t, findLocalCandidateStats(reportPCOffer))
	assert.NotEmpty(t, findRemoteCandidateStats(reportPCOffer))
	assert.NotEmpty(t, findCandidatePairStats(t, reportPCOffer))

	connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsClosed)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
	dcStatsAnswer := getDataChannelStats(t, reportPCAnswer, answerDC)
	assert.Equal(t, DataChannelStateOpen, dcStatsAnswer.State)
	assert.Equal(t, uint32(1), dcStatsAnswer.MessagesReceived)
	assert.Equal(t, uint64(len(msg)), dcStatsAnswer.BytesReceived)
	assert.NotEmpty(t, findLocalCandidateStats(reportPCAnswer))
	assert.NotEmpty(t, findRemoteCandidateStats(reportPCAnswer))
	assert.NotEmpty(t, findCandidatePairStats(t, reportPCAnswer))

	// Close answer DC now
	dcWait = sync.WaitGroup{}
	dcWait.Add(1)
	offerDC.OnClose(func() {
		dcWait.Done()
	})
	assert.NoError(t, answerDC.Close())
	waitWithTimeout(t, &dcWait)
	time.Sleep(10 * time.Millisecond)

	reportPCOffer = offerPC.GetStats()
	reportPCAnswer = answerPC.GetStats()

	connStatsOffer = getConnectionStats(t, reportPCOffer, offerPC)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsOpened)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsClosed)
	assert.Equal(t, uint32(1), connStatsOffer.DataChannelsRequested)
	assert.Equal(t, uint32(0), connStatsOffer.DataChannelsAccepted)
	dcStatsOffer = getDataChannelStats(t, reportPCOffer, offerDC)
	assert.Equal(t, DataChannelStateClosed, dcStatsOffer.State)

	connStatsAnswer = getConnectionStats(t, reportPCAnswer, answerPC)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsOpened)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsClosed)
	assert.Equal(t, uint32(0), connStatsAnswer.DataChannelsRequested)
	assert.Equal(t, uint32(1), connStatsAnswer.DataChannelsAccepted)
	dcStatsAnswer = getDataChannelStats(t, reportPCAnswer, answerDC)
	assert.Equal(t, DataChannelStateClosed, dcStatsAnswer.State)

	answerICETransportStats := getTransportStats(t, reportPCAnswer, "iceTransport")
	offerICETransportStats := getTransportStats(t, reportPCOffer, "iceTransport")
	assert.GreaterOrEqual(t, offerICETransportStats.BytesSent, answerICETransportStats.BytesReceived)
	assert.GreaterOrEqual(t, answerICETransportStats.BytesSent, offerICETransportStats.BytesReceived)

	answerSCTPTransportStats := getTransportStats(t, reportPCAnswer, "sctpTransport")
	offerSCTPTransportStats := getTransportStats(t, reportPCOffer, "sctpTransport")
	assert.GreaterOrEqual(t, offerSCTPTransportStats.BytesSent, answerSCTPTransportStats.BytesReceived)
	assert.GreaterOrEqual(t, answerSCTPTransportStats.BytesSent, offerSCTPTransportStats.BytesReceived)

	assert.NoError(t, offerPC.Close())
	assert.NoError(t, answerPC.Close())
}

func TestPeerConnection_GetStats_Closed(t *testing.T) {
	pc, err := NewPeerConnection(Configuration{})
	assert.NoError(t, err)

	assert.NoError(t, pc.Close())

	pc.GetStats()
}
<|endoftext|>


<commit_before>package conn

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"syscall"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
	reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"

	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {

	maconn, err := d.rawConnDial(ctx, raddr, remote)
	if err != nil {
		return nil, err
	}

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() { done <- struct{}{} }()

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			errOut = err
			return
		}

		if d.PrivateKey == nil {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}
		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		maconn.Close()
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	return connOut, errOut
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (manet.Conn, error) {

	// before doing anything, check we're going to be able to dial.
	// we may not support the given address.
	if _, _, err := manet.DialArgs(raddr); err != nil {
		return nil, err
	}

	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	// get local addr to use.
	laddr := pickLocalAddr(d.LocalAddrs, raddr)
	log.Debugf("%s dialing %s -- %s --> %s", d.LocalPeer, remote, laddr, raddr)

	if laddr != nil && reuseport.Available() {
		// dial using reuseport.Dialer, because we're probably reusing addrs.
		// this is optimistic, as the reuseDial may fail to bind the port.
		if nconn, retry, reuseErr := d.reuseDial(laddr, raddr); reuseErr == nil {
			// if it worked, wrap the raw net.Conn with our manet.Conn
			log.Debugf("%s reuse worked! %s %s %s", d.LocalPeer, laddr, nconn.RemoteAddr(), nconn)
			return manet.WrapNetConn(nconn)
		} else if !retry {
			// reuseDial is sure this is a legitimate dial failure, not a reuseport failure.
			return nil, reuseErr
		} else {
			// this is a failure to reuse port. log it.
			log.Debugf("%s port reuse failed: %s --> %s -- %s", d.LocalPeer, laddr, raddr, reuseErr)
		}
	}

	// no local addr, or reuseport failed. just dial straight with a new port.
	return d.Dialer.Dial(raddr)
}

func (d *Dialer) reuseDial(laddr, raddr ma.Multiaddr) (conn net.Conn, retry bool, err error) {
	if laddr == nil {
		// if we're given no local address no sense in using reuseport to dial, dial out as usual.
		return nil, true, reuseport.ErrReuseFailed
	}

	// half the timeout so we can retry regularly if this fails.
	d.Dialer.Dialer.Timeout = (d.Dialer.Dialer.Timeout / 2)

	// give reuse.Dialer the manet.Dialer's Dialer.
	// (wow, Dialer should've so been an interface...)
	rd := reuseport.Dialer{d.Dialer.Dialer}

	// get the local net.Addr manually
	rd.D.LocalAddr, err = manet.ToNetAddr(laddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// get the raddr dial args for rd.dial
	network, netraddr, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
	conn, err = rd.Dial(network, netraddr)
	return conn, reuseErrShouldRetry(err), err // hey! it worked!
}

// reuseErrShouldRetry diagnoses whether to retry after a reuse error.
// if we failed to bind, we should retry. if bind worked and this is a
// real dial error (remote end didnt answer) then we should not retry.
func reuseErrShouldRetry(err error) bool {
	if err == nil {
		return false // hey, it worked! no need to retry.
	}

	errno, ok := err.(syscall.Errno)
	if !ok { // not an errno? who knows what this is. retry.
		return true
	}

	switch errno {
	case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
		return true // failure to bind. retry.
	case syscall.ECONNREFUSED:
		return false // real dial error
	default:
		return true // optimistically default to retry.
	}
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<commit_msg>p2p/net/conn: timeouts are real failures.<commit_after>package conn

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"syscall"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
	reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"

	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {

	maconn, err := d.rawConnDial(ctx, raddr, remote)
	if err != nil {
		return nil, err
	}

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() { done <- struct{}{} }()

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			errOut = err
			return
		}

		if d.PrivateKey == nil {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}
		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		maconn.Close()
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	return connOut, errOut
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (manet.Conn, error) {

	// before doing anything, check we're going to be able to dial.
	// we may not support the given address.
	if _, _, err := manet.DialArgs(raddr); err != nil {
		return nil, err
	}

	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	// get local addr to use.
	laddr := pickLocalAddr(d.LocalAddrs, raddr)
	log.Debugf("%s dialing %s -- %s --> %s", d.LocalPeer, remote, laddr, raddr)

	if laddr != nil && reuseport.Available() {
		// dial using reuseport.Dialer, because we're probably reusing addrs.
		// this is optimistic, as the reuseDial may fail to bind the port.
		if nconn, retry, reuseErr := d.reuseDial(laddr, raddr); reuseErr == nil {
			// if it worked, wrap the raw net.Conn with our manet.Conn
			log.Debugf("%s reuse worked! %s %s %s", d.LocalPeer, laddr, nconn.RemoteAddr(), nconn)
			return manet.WrapNetConn(nconn)
		} else if !retry {
			// reuseDial is sure this is a legitimate dial failure, not a reuseport failure.
			return nil, reuseErr
		} else {
			// this is a failure to reuse port. log it.
			log.Debugf("%s port reuse failed: %s --> %s -- %s", d.LocalPeer, laddr, raddr, reuseErr)
		}
	}

	// no local addr, or reuseport failed. just dial straight with a new port.
	return d.Dialer.Dial(raddr)
}

func (d *Dialer) reuseDial(laddr, raddr ma.Multiaddr) (conn net.Conn, retry bool, err error) {
	if laddr == nil {
		// if we're given no local address no sense in using reuseport to dial, dial out as usual.
		return nil, true, reuseport.ErrReuseFailed
	}

	// half the timeout so we can retry regularly if this fails.
	d.Dialer.Dialer.Timeout = (d.Dialer.Dialer.Timeout / 2)

	// give reuse.Dialer the manet.Dialer's Dialer.
	// (wow, Dialer should've so been an interface...)
	rd := reuseport.Dialer{d.Dialer.Dialer}

	// get the local net.Addr manually
	rd.D.LocalAddr, err = manet.ToNetAddr(laddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// get the raddr dial args for rd.dial
	network, netraddr, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
	conn, err = rd.Dial(network, netraddr)
	return conn, reuseErrShouldRetry(err), err // hey! it worked!
}

// reuseErrShouldRetry diagnoses whether to retry after a reuse error.
// if we failed to bind, we should retry. if bind worked and this is a
// real dial error (remote end didnt answer) then we should not retry.
func reuseErrShouldRetry(err error) bool {
	if err == nil {
		return false // hey, it worked! no need to retry.
	}

	// if it's a network timeout error, it's a legitimate failure.
	if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
		return true
	}

	errno, ok := err.(syscall.Errno)
	if !ok { // not an errno? who knows what this is. retry.
		return true
	}

	switch errno {
	case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
		return true // failure to bind. retry.
	case syscall.ECONNREFUSED:
		return false // real dial error
	default:
		return true // optimistically default to retry.
	}
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<|endoftext|>