<commit_before>package filestore_util

import (
	errs "errors"
	"fmt"
	"io"

	. "github.com/ipfs/go-ipfs/filestore"

	cmds "github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	//"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	k "github.com/ipfs/go-ipfs/blocks/key"
	//ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
	b "github.com/ipfs/go-ipfs/blocks/blockstore"
	node "github.com/ipfs/go-ipfs/merkledag"
	"github.com/ipfs/go-ipfs/pin"
)

type DeleteOpts struct {
	Direct     bool
	Force      bool
	IgnorePins bool
}

func Delete(req cmds.Request, out io.Writer, node *core.IpfsNode, fs *Datastore, opts DeleteOpts, keyList ...k.Key) error {
	keys := make(map[k.Key]struct{})
	for _, k := range keyList {
		keys[k] = struct{}{}
	}

	//
	// First check files
	//
	errors := false
	for _, k := range keyList {
		dagNode, dataObj, err := fsGetNode(k.DsKey(), fs)
		if err != nil {
			fmt.Fprintf(out, "%s: %s\n", k, err.Error())
			delete(keys, k)
			errors = true
			continue
		}
		if !opts.Direct && !dataObj.WholeFile() {
			fmt.Fprintf(out, "%s: part of another file, use --direct to delete\n", k)
			delete(keys, k)
			errors = true
			continue
		}
		if dagNode != nil && !opts.Direct {
			err = getChildren(out, dagNode, fs, node.Blockstore, keys)
			if err != nil {
				errors = true
			}
		}
	}
	if !opts.Force && errors {
		return errs.New("Errors during precheck.")
	}

	//
	// Now check pins
	//
	pinned := make(map[k.Key]pin.PinMode)
	if !opts.IgnorePins {
		walkPins(node.Pinning, fs, node.Blockstore, func(key k.Key, mode pin.PinMode) bool {
			_, ok := keys[key]
			if !ok {
				// Hack to make sure mangled hashes are unpinned
				// (see issue #2601)
				_, ok = keys[k.KeyFromDsKey(key.DsKey())]
			}
			if ok {
				if mode == pin.NotPinned {
					// an indirect pin
					fmt.Fprintf(out, "%s: indirectly pinned\n", key)
					if !opts.Force {
						errors = true
					}
					return true
				} else {
					pinned[key] = mode
					return false
				}
			} else {
				return true
			}
		})
		if !opts.Force && errors {
			return errs.New("Errors during pin-check.")
		}
	}

	//
	//
	//
	for key, _ := range keys {
		err := fs.DeleteDirect(key.DsKey())
		if err != nil {
			fmt.Fprintf(out, "%s: %s\n", key, err.Error())
		}
		fmt.Fprintf(out, "deleted %s\n", key)
	}

	for key, mode := range pinned {
		stillExists, err := node.Blockstore.Has(key)
		if err != nil {
			fmt.Fprintf(out, "skipping pin %s: %s\n", err.Error())
			continue
		} else if stillExists {
			fmt.Fprintf(out, "skipping pin %s: object still exists outside filestore\n", key)
			continue
		}
		node.Pinning.RemovePinWithMode(key, mode)
		fmt.Fprintf(out, "unpinned %s\n", key)
	}
	if len(pinned) > 0 {
		err := node.Pinning.Flush()
		if err != nil {
			return err
		}
	}

	if errors {
		return errs.New("Errors deleting some keys.")
	}
	return nil
}

func getChildren(out io.Writer, node *node.Node, fs *Datastore, bs b.Blockstore, keys map[k.Key]struct{}) error {
	errors := false
	for _, link := range node.Links {
		key := k.Key(link.Hash)
		if _, ok := keys[key]; ok {
			continue
		}
		n, _, status := getNode(key.DsKey(), key, fs, bs)
		if AnError(status) {
			fmt.Fprintf(out, "%s: error retrieving key", key)
			errors = true
		}
		keys[key] = struct{}{}
		if n != nil {
			err := getChildren(out, n, fs, bs, keys)
			if err != nil {
				errors = true
			}
		}
	}
	if errors {
		return errs.New("Could net get all children.")
	}
	return nil
}
<commit_msg>"filestore rm": Avoid checking for indirect pins when "--force" is used.<commit_after>package filestore_util

import (
	errs "errors"
	"fmt"
	"io"

	. "github.com/ipfs/go-ipfs/filestore"

	cmds "github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	//"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	k "github.com/ipfs/go-ipfs/blocks/key"
	//ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
	b "github.com/ipfs/go-ipfs/blocks/blockstore"
	node "github.com/ipfs/go-ipfs/merkledag"
	"github.com/ipfs/go-ipfs/pin"
)

type DeleteOpts struct {
	Direct     bool
	Force      bool
	IgnorePins bool
}

func Delete(req cmds.Request, out io.Writer, node *core.IpfsNode, fs *Datastore, opts DeleteOpts, keyList ...k.Key) error {
	keys := make(map[k.Key]struct{})
	for _, k := range keyList {
		keys[k] = struct{}{}
	}

	//
	// First check files
	//
	errors := false
	for _, k := range keyList {
		dagNode, dataObj, err := fsGetNode(k.DsKey(), fs)
		if err != nil {
			fmt.Fprintf(out, "%s: %s\n", k, err.Error())
			delete(keys, k)
			errors = true
			continue
		}
		if !opts.Direct && !dataObj.WholeFile() {
			fmt.Fprintf(out, "%s: part of another file, use --direct to delete\n", k)
			delete(keys, k)
			errors = true
			continue
		}
		if dagNode != nil && !opts.Direct {
			err = getChildren(out, dagNode, fs, node.Blockstore, keys)
			if err != nil {
				errors = true
			}
		}
	}
	if !opts.Force && errors {
		return errs.New("Errors during precheck.")
	}

	//
	// Now check pins
	//
	pinned := make(map[k.Key]pin.PinMode)
	if !opts.IgnorePins {
		walkPins(node.Pinning, fs, node.Blockstore, func(key k.Key, mode pin.PinMode) bool {
			_, ok := keys[key]
			if !ok {
				// Hack to make sure mangled hashes are unpinned
				// (see issue #2601)
				_, ok = keys[k.KeyFromDsKey(key.DsKey())]
			}
			if ok {
				if mode == pin.NotPinned {
					// an indirect pin
					fmt.Fprintf(out, "%s: indirectly pinned\n", key)
					errors = true
					return true
				} else {
					pinned[key] = mode
					return false
				}
			} else {
				if opts.Force {
					// do not recurse and thus do not check indirect pins
					return false
				} else {
					return true
				}
			}
		})
		if !opts.Force && errors {
			return errs.New("Errors during pin-check.")
		}
	}

	//
	//
	//
	for key, _ := range keys {
		err := fs.DeleteDirect(key.DsKey())
		if err != nil {
			fmt.Fprintf(out, "%s: %s\n", key, err.Error())
		}
		fmt.Fprintf(out, "deleted %s\n", key)
	}

	for key, mode := range pinned {
		stillExists, err := node.Blockstore.Has(key)
		if err != nil {
			fmt.Fprintf(out, "skipping pin %s: %s\n", err.Error())
			continue
		} else if stillExists {
			fmt.Fprintf(out, "skipping pin %s: object still exists outside filestore\n", key)
			continue
		}
		node.Pinning.RemovePinWithMode(key, mode)
		fmt.Fprintf(out, "unpinned %s\n", key)
	}
	if len(pinned) > 0 {
		err := node.Pinning.Flush()
		if err != nil {
			return err
		}
	}

	if errors {
		return errs.New("Errors deleting some keys.")
	}
	return nil
}

func getChildren(out io.Writer, node *node.Node, fs *Datastore, bs b.Blockstore, keys map[k.Key]struct{}) error {
	errors := false
	for _, link := range node.Links {
		key := k.Key(link.Hash)
		if _, ok := keys[key]; ok {
			continue
		}
		n, _, status := getNode(key.DsKey(), key, fs, bs)
		if AnError(status) {
			fmt.Fprintf(out, "%s: error retrieving key", key)
			errors = true
		}
		keys[key] = struct{}{}
		if n != nil {
			err := getChildren(out, n, fs, bs, keys)
			if err != nil {
				errors = true
			}
		}
	}
	if errors {
		return errs.New("Could net get all children.")
	}
	return nil
}
<|endoftext|>


<commit_before>package service

import (
	"github.com/boivie/lovebeat-go/alert"
	"github.com/boivie/lovebeat-go/backend"
	"github.com/op/go-logging"
	"math"
	"regexp"
	"sort"
	"time"
)

const (
	MAX_UNPROCESSED_PACKETS = 1000
	EXPIRY_INTERVAL         = 1

	// Number of samples (diffs) we require to be able to
	// properly calculate an "auto" timeout
	AUTO_MIN_SAMPLES = 5
)

var (
	log          = logging.MustGetLogger("lovebeat")
	EMPTY_REGEXP = regexp.MustCompile("^$")
)

type Services struct {
	be                   backend.Backend
	alerters             []alert.Alerter
	services             map[string]*Service
	views                map[string]*View
	beatCmdChan          chan string
	upsertServiceCmdChan chan *upsertServiceCmd
	deleteServiceCmdChan chan string
	deleteViewCmdChan    chan string
	upsertViewCmdChan    chan *upsertViewCmd
	getServicesChan      chan *getServicesCmd
	getServiceChan       chan *getServiceCmd
	getViewsChan         chan *getViewsCmd
	getViewChan          chan *getViewCmd
}

type Service struct {
	svcs *Services
	data backend.StoredService
}

type View struct {
	svcs *Services
	data backend.StoredView
	ree  *regexp.Regexp
}

func now() int64 { return time.Now().Unix() }

func (s *Service) getExpiry(timeout int64) int64 {
	if timeout <= 0 {
		return 0
	}
	return s.data.LastBeat + timeout
}

func (s *Service) name() string { return s.data.Name }
func (v *View) name() string    { return v.data.Name }

func calcTimeout(values []int64) int64 {
	diffs := calcDiffs(values)
	if len(diffs) < AUTO_MIN_SAMPLES {
		log.Debug("AUTO-TIMEOUT: Not enough samples to calculate")
		return TIMEOUT_AUTO
	}

	ret := int64(math.Ceil(float64(median(diffs)) * 1.5))
	log.Debug("AUTO-TIMEOUT: vale calculated as %d", ret)
	return ret
}

func calcDiffs(values []int64) []int64 {
	var p []int64
	for i := 1; i < len(values); i++ {
		if values[i-1] != 0 && values[i] != 0 {
			p = append(p, values[i]-values[i-1])
		}
	}
	return p
}

type int64arr []int64

func (a int64arr) Len() int           { return len(a) }
func (a int64arr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a int64arr) Less(i, j int) bool { return a[i] < a[j] }

func median(numbers []int64) int64 {
	sort.Sort(int64arr(numbers))
	middle := len(numbers) / 2
	result := numbers[middle]
	if len(numbers)%2 == 0 {
		result = (result + numbers[middle-1]) / 2
	}
	return result
}

// Called before saving - to update internal states
func (s *Service) update(ts int64) {
	s.data.State = s.stateAt(ts)

	if s.data.WarningTimeout == TIMEOUT_AUTO {
		s.data.WarningTimeout = calcTimeout(s.data.PreviousBeats)
	}
	if s.data.ErrorTimeout == TIMEOUT_AUTO {
		s.data.ErrorTimeout = calcTimeout(s.data.PreviousBeats)
	}
}

func (s *Service) stateAt(ts int64) string {
	var state = backend.STATE_OK
	var warningExpiry = s.getExpiry(s.data.WarningTimeout)
	var errorExpiry = s.getExpiry(s.data.ErrorTimeout)
	if warningExpiry > 0 && ts >= warningExpiry {
		state = backend.STATE_WARNING
	}
	if errorExpiry > 0 && ts >= errorExpiry {
		state = backend.STATE_ERROR
	}
	return state
}

func (s *Service) registerBeat(ts int64) {
	s.data.LastBeat = ts
	s.data.PreviousBeats = append(s.data.PreviousBeats[1:], ts)
}

func (s *Service) save(ref *Service, ts int64) {
	if s.data.State != ref.data.State {
		log.Info("SERVICE '%s', state %s -> %s",
			s.name(), ref.data.State, s.data.State)
	}
	if s.data.WarningTimeout != ref.data.WarningTimeout {
		log.Info("SERVICE '%s', warn %d -> %d",
			s.name(), ref.data.WarningTimeout,
			s.data.WarningTimeout)
	}
	if s.data.ErrorTimeout != ref.data.ErrorTimeout {
		log.Info("SERVICE '%s', err %d -> %d",
			s.name(), ref.data.ErrorTimeout,
			s.data.ErrorTimeout)
	}
	s.data.LastUpdated = ts
	s.svcs.be.SaveService(&s.data)
}

func (v *View) refresh(ts int64) {
	v.data.State = backend.STATE_OK
	for _, s := range v.svcs.services {
		if v.ree.Match([]byte(s.name())) {
			if s.data.State == backend.STATE_WARNING && v.data.State == backend.STATE_OK {
				v.data.State = backend.STATE_WARNING
			} else if s.data.State == backend.STATE_ERROR {
				v.data.State = backend.STATE_ERROR
			}
		}
	}
}

func (v *View) contains(serviceName string) bool {
	return v.ree.Match([]byte(serviceName))
}

func (v *View) save(ref *View, ts int64) {
	if v.data.State != ref.data.State {
		if ref.data.State == backend.STATE_OK {
			v.data.IncidentNbr += 1
		}
	}
	v.data.LastUpdated = ts
	v.svcs.be.SaveView(&v.data)
}

func (v *View) sendAlerts(ref *View, ts int64) {
	if v.data.State != ref.data.State {
		log.Info("VIEW '%s', %d: state %s -> %s",
			v.name(), v.data.IncidentNbr, ref.data.State,
			v.data.State)

		var services = make([]backend.StoredService, 0, 10)
		for _, s := range v.svcs.services {
			if (s.data.State == backend.STATE_WARNING ||
				s.data.State == backend.STATE_ERROR) &&
				v.contains(s.name()) {
				services = append(services, s.data)
				if len(services) == 10 {
					break
				}
			}
		}

		for _, a := range v.svcs.alerters {
			a.Notify(ref.data, v.data, services)
		}
	}
}

func (svcs *Services) updateViews(ts int64, serviceName string) {
	for _, view := range svcs.views {
		if view.ree.Match([]byte(serviceName)) {
			var ref = *view
			view.refresh(ts)
			view.save(&ref, ts)
			view.sendAlerts(&ref, ts)
		}
	}
}

func (svcs *Services) getService(name string) *Service {
	var s, ok = svcs.services[name]
	if !ok {
		log.Debug("Asked for unknown service %s", name)
		s = &Service{
			svcs: svcs,
			data: backend.StoredService{
				Name:           name,
				LastValue:      -1,
				LastBeat:       -1,
				PreviousBeats:  make([]int64, backend.PREVIOUS_BEATS_COUNT),
				LastUpdated:    -1,
				WarningTimeout: -1,
				ErrorTimeout:   -1,
				State:          backend.STATE_PAUSED,
			},
		}
		svcs.services[name] = s
	}
	return s
}

func (svcs *Services) getView(name string) *View {
	var s, ok = svcs.views[name]
	if !ok {
		log.Debug("Asked for unknown view %s", name)
		s = &View{
			svcs: svcs,
			data: backend.StoredView{
				Name:        name,
				State:       backend.STATE_OK,
				LastUpdated: -1,
				Regexp:      "^$",
			},
			ree: EMPTY_REGEXP}
		svcs.views[name] = s
	}
	return s
}

func (svcs *Services) createView(name string, expr string, alertMail string,
	webhooks string, ts int64) {
	var ree, err = regexp.Compile(expr)
	if err != nil {
		log.Error("Invalid regexp: %s", err)
		return
	}

	var view = svcs.getView(name)
	var ref = *view
	view.data.Regexp = expr
	view.ree = ree
	view.data.AlertMail = alertMail
	view.data.Webhooks = webhooks
	view.refresh(ts)
	view.save(&ref, ts)

	log.Info("VIEW '%s' created or updated.", name)
}

func (svcs *Services) Monitor() {
	period := time.Duration(EXPIRY_INTERVAL) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case <-ticker.C:
			var ts = now()
			for _, s := range svcs.services {
				if s.data.State == backend.STATE_PAUSED || s.data.State == s.stateAt(ts) {
					continue
				}
				var ref = *s
				s.update(ts)
				s.save(&ref, ts)
				svcs.updateViews(ts, s.name())
			}
		case c := <-svcs.upsertViewCmdChan:
			log.Debug("Create or update view %s", c.View)
			svcs.createView(c.View, c.Regexp, c.AlertMail,
				c.Webhooks, now())
		case c := <-svcs.deleteViewCmdChan:
			log.Debug("Delete view %s", c)
			delete(svcs.views, c)
			svcs.be.DeleteView(c)
		case c := <-svcs.getServicesChan:
			var ret []backend.StoredService
			var view, ok = svcs.views[c.View]
			if ok {
				for _, s := range svcs.services {
					if view.contains(s.name()) {
						ret = append(ret, s.data)
					}
				}
			}
			c.Reply <- ret
		case c := <-svcs.getServiceChan:
			var ret = svcs.services[c.Name]
			c.Reply <- ret.data
		case c := <-svcs.getViewsChan:
			var ret []backend.StoredView
			for _, v := range svcs.views {
				ret = append(ret, v.data)
			}
			c.Reply <- ret
		case c := <-svcs.getViewChan:
			var ret = svcs.views[c.Name]
			c.Reply <- ret.data
		case c := <-svcs.beatCmdChan:
			var ts = now()
			var s = svcs.getService(c)
			var ref = *s
			s.registerBeat(ts)
			log.Debug("Beat from %s", s.name())
			s.update(ts)
			s.save(&ref, ts)
			svcs.updateViews(ts, s.name())
		case c := <-svcs.deleteServiceCmdChan:
			var ts = now()
			var s = svcs.getService(c)
			delete(svcs.services, s.name())
			svcs.be.DeleteService(s.name())
			svcs.updateViews(ts, s.name())
		case c := <-svcs.upsertServiceCmdChan:
			var ts = now()
			var s = svcs.getService(c.Service)
			var ref = *s
			// Don't re-calculate 'auto' if we already have values
			if c.WarningTimeout == TIMEOUT_AUTO &&
				s.data.WarningTimeout == -1 {
				s.data.WarningTimeout = TIMEOUT_AUTO
				s.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
			} else if c.WarningTimeout == TIMEOUT_CLEAR {
				s.data.WarningTimeout = TIMEOUT_CLEAR
			} else if c.WarningTimeout > 0 {
				s.data.WarningTimeout = c.WarningTimeout
			}
			if c.ErrorTimeout == TIMEOUT_AUTO &&
				s.data.ErrorTimeout == -1 {
				s.data.ErrorTimeout = TIMEOUT_AUTO
				s.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
			} else if c.ErrorTimeout == TIMEOUT_CLEAR {
				s.data.ErrorTimeout = TIMEOUT_CLEAR
			} else if c.ErrorTimeout > 0 {
				s.data.ErrorTimeout = c.ErrorTimeout
			}
			s.update(ts)
			s.save(&ref, ts)
			svcs.updateViews(ts, s.name())
		}
	}
}

func NewServices(beiface backend.Backend, alerters []alert.Alerter) *Services {
	svcs := new(Services)
	svcs.be = beiface
	svcs.alerters = alerters
	svcs.beatCmdChan = make(chan string, MAX_UNPROCESSED_PACKETS)
	svcs.deleteServiceCmdChan = make(chan string, 5)
	svcs.upsertServiceCmdChan = make(chan *upsertServiceCmd, 5)
	svcs.deleteViewCmdChan = make(chan string, 5)
	svcs.upsertViewCmdChan = make(chan *upsertViewCmd, 5)
	svcs.getServicesChan = make(chan *getServicesCmd, 5)
	svcs.getServiceChan = make(chan *getServiceCmd, 5)
	svcs.getViewsChan = make(chan *getViewsCmd, 5)
	svcs.getViewChan = make(chan *getViewCmd, 5)
	svcs.services = make(map[string]*Service)
	svcs.views = make(map[string]*View)

	for _, s := range svcs.be.LoadServices() {
		var svc = &Service{svcs: svcs, data: *s}
		if svc.data.PreviousBeats == nil || len(svc.data.PreviousBeats) != backend.PREVIOUS_BEATS_COUNT {
			svc.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
		}
		svcs.services[s.Name] = svc
	}

	for _, v := range svcs.be.LoadViews() {
		var ree, _ = regexp.Compile(v.Regexp)
		svcs.views[v.Name] = &View{svcs: svcs, data: *v, ree: ree}
	}

	return svcs
}
<commit_msg>Refactoring (4/10)<commit_after>package service

import (
	"github.com/boivie/lovebeat-go/alert"
	"github.com/boivie/lovebeat-go/backend"
	"github.com/op/go-logging"
	"math"
	"regexp"
	"sort"
	"time"
)

const (
	MAX_UNPROCESSED_PACKETS = 1000
	EXPIRY_INTERVAL         = 1

	// Number of samples (diffs) we require to be able to
	// properly calculate an "auto" timeout
	AUTO_MIN_SAMPLES = 5
)

var (
	log          = logging.MustGetLogger("lovebeat")
	EMPTY_REGEXP = regexp.MustCompile("^$")
)

type Services struct {
	be                   backend.Backend
	alerters             []alert.Alerter
	services             map[string]*Service
	views                map[string]*View
	beatCmdChan          chan string
	upsertServiceCmdChan chan *upsertServiceCmd
	deleteServiceCmdChan chan string
	deleteViewCmdChan    chan string
	upsertViewCmdChan    chan *upsertViewCmd
	getServicesChan      chan *getServicesCmd
	getServiceChan       chan *getServiceCmd
	getViewsChan         chan *getViewsCmd
	getViewChan          chan *getViewCmd
}

type Service struct {
	data backend.StoredService
}

type View struct {
	svcs *Services
	data backend.StoredView
	ree  *regexp.Regexp
}

func now() int64 { return time.Now().Unix() }

func (s *Service) getExpiry(timeout int64) int64 {
	if timeout <= 0 {
		return 0
	}
	return s.data.LastBeat + timeout
}

func (s *Service) name() string { return s.data.Name }
func (v *View) name() string    { return v.data.Name }

func calcTimeout(values []int64) int64 {
	diffs := calcDiffs(values)
	if len(diffs) < AUTO_MIN_SAMPLES {
		log.Debug("AUTO-TIMEOUT: Not enough samples to calculate")
		return TIMEOUT_AUTO
	}

	ret := int64(math.Ceil(float64(median(diffs)) * 1.5))
	log.Debug("AUTO-TIMEOUT: vale calculated as %d", ret)
	return ret
}

func calcDiffs(values []int64) []int64 {
	var p []int64
	for i := 1; i < len(values); i++ {
		if values[i-1] != 0 && values[i] != 0 {
			p = append(p, values[i]-values[i-1])
		}
	}
	return p
}

type int64arr []int64

func (a int64arr) Len() int           { return len(a) }
func (a int64arr) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a int64arr) Less(i, j int) bool { return a[i] < a[j] }

func median(numbers []int64) int64 {
	sort.Sort(int64arr(numbers))
	middle := len(numbers) / 2
	result := numbers[middle]
	if len(numbers)%2 == 0 {
		result = (result + numbers[middle-1]) / 2
	}
	return result
}

// Called before saving - to update internal states
func (s *Service) update(ts int64) {
	s.data.State = s.stateAt(ts)

	if s.data.WarningTimeout == TIMEOUT_AUTO {
		s.data.WarningTimeout = calcTimeout(s.data.PreviousBeats)
	}
	if s.data.ErrorTimeout == TIMEOUT_AUTO {
		s.data.ErrorTimeout = calcTimeout(s.data.PreviousBeats)
	}
	s.data.LastUpdated = ts
}

func (s *Service) stateAt(ts int64) string {
	var state = backend.STATE_OK
	var warningExpiry = s.getExpiry(s.data.WarningTimeout)
	var errorExpiry = s.getExpiry(s.data.ErrorTimeout)
	if warningExpiry > 0 && ts >= warningExpiry {
		state = backend.STATE_WARNING
	}
	if errorExpiry > 0 && ts >= errorExpiry {
		state = backend.STATE_ERROR
	}
	return state
}

func (s *Service) registerBeat(ts int64) {
	s.data.LastBeat = ts
	s.data.PreviousBeats = append(s.data.PreviousBeats[1:], ts)
}

func (s *Service) save(be backend.Backend, ref *Service, ts int64) {
	if s.data.State != ref.data.State {
		log.Info("SERVICE '%s', state %s -> %s",
			s.name(), ref.data.State, s.data.State)
	}
	if s.data.WarningTimeout != ref.data.WarningTimeout {
		log.Info("SERVICE '%s', warn %d -> %d",
			s.name(), ref.data.WarningTimeout,
			s.data.WarningTimeout)
	}
	if s.data.ErrorTimeout != ref.data.ErrorTimeout {
		log.Info("SERVICE '%s', err %d -> %d",
			s.name(), ref.data.ErrorTimeout,
			s.data.ErrorTimeout)
	}
	be.SaveService(&s.data)
}

func (v *View) refresh(ts int64) {
	v.data.State = backend.STATE_OK
	for _, s := range v.svcs.services {
		if v.ree.Match([]byte(s.name())) {
			if s.data.State == backend.STATE_WARNING && v.data.State == backend.STATE_OK {
				v.data.State = backend.STATE_WARNING
			} else if s.data.State == backend.STATE_ERROR {
				v.data.State = backend.STATE_ERROR
			}
		}
	}
}

func (v *View) contains(serviceName string) bool {
	return v.ree.Match([]byte(serviceName))
}

func (v *View) save(ref *View, ts int64) {
	if v.data.State != ref.data.State {
		if ref.data.State == backend.STATE_OK {
			v.data.IncidentNbr += 1
		}
	}
	v.data.LastUpdated = ts
	v.svcs.be.SaveView(&v.data)
}

func (v *View) sendAlerts(ref *View, ts int64) {
	if v.data.State != ref.data.State {
		log.Info("VIEW '%s', %d: state %s -> %s",
			v.name(), v.data.IncidentNbr, ref.data.State,
			v.data.State)

		var services = make([]backend.StoredService, 0, 10)
		for _, s := range v.svcs.services {
			if (s.data.State == backend.STATE_WARNING ||
				s.data.State == backend.STATE_ERROR) &&
				v.contains(s.name()) {
				services = append(services, s.data)
				if len(services) == 10 {
					break
				}
			}
		}

		for _, a := range v.svcs.alerters {
			a.Notify(ref.data, v.data, services)
		}
	}
}

func (svcs *Services) updateViews(ts int64, serviceName string) {
	for _, view := range svcs.views {
		if view.ree.Match([]byte(serviceName)) {
			var ref = *view
			view.refresh(ts)
			view.save(&ref, ts)
			view.sendAlerts(&ref, ts)
		}
	}
}

func (svcs *Services) getService(name string) *Service {
	var s, ok = svcs.services[name]
	if !ok {
		log.Debug("Asked for unknown service %s", name)
		s = &Service{
			data: backend.StoredService{
				Name:           name,
				LastValue:      -1,
				LastBeat:       -1,
				PreviousBeats:  make([]int64, backend.PREVIOUS_BEATS_COUNT),
				LastUpdated:    -1,
				WarningTimeout: -1,
				ErrorTimeout:   -1,
				State:          backend.STATE_PAUSED,
			},
		}
		svcs.services[name] = s
	}
	return s
}

func (svcs *Services) getView(name string) *View {
	var s, ok = svcs.views[name]
	if !ok {
		log.Debug("Asked for unknown view %s", name)
		s = &View{
			svcs: svcs,
			data: backend.StoredView{
				Name:        name,
				State:       backend.STATE_OK,
				LastUpdated: -1,
				Regexp:      "^$",
			},
			ree: EMPTY_REGEXP}
		svcs.views[name] = s
	}
	return s
}

func (svcs *Services) createView(name string, expr string, alertMail string,
	webhooks string, ts int64) {
	var ree, err = regexp.Compile(expr)
	if err != nil {
		log.Error("Invalid regexp: %s", err)
		return
	}

	var view = svcs.getView(name)
	var ref = *view
	view.data.Regexp = expr
	view.ree = ree
	view.data.AlertMail = alertMail
	view.data.Webhooks = webhooks
	view.refresh(ts)
	view.save(&ref, ts)

	log.Info("VIEW '%s' created or updated.", name)
}

func (svcs *Services) Monitor() {
	period := time.Duration(EXPIRY_INTERVAL) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case <-ticker.C:
			var ts = now()
			for _, s := range svcs.services {
				if s.data.State == backend.STATE_PAUSED || s.data.State == s.stateAt(ts) {
					continue
				}
				var ref = *s
				s.update(ts)
				s.save(svcs.be, &ref, ts)
				svcs.updateViews(ts, s.name())
			}
		case c := <-svcs.upsertViewCmdChan:
			log.Debug("Create or update view %s", c.View)
			svcs.createView(c.View, c.Regexp, c.AlertMail,
				c.Webhooks, now())
		case c := <-svcs.deleteViewCmdChan:
			log.Debug("Delete view %s", c)
			delete(svcs.views, c)
			svcs.be.DeleteView(c)
		case c := <-svcs.getServicesChan:
			var ret []backend.StoredService
			var view, ok = svcs.views[c.View]
			if ok {
				for _, s := range svcs.services {
					if view.contains(s.name()) {
						ret = append(ret, s.data)
					}
				}
			}
			c.Reply <- ret
		case c := <-svcs.getServiceChan:
			var ret = svcs.services[c.Name]
			c.Reply <- ret.data
		case c := <-svcs.getViewsChan:
			var ret []backend.StoredView
			for _, v := range svcs.views {
				ret = append(ret, v.data)
			}
			c.Reply <- ret
		case c := <-svcs.getViewChan:
			var ret = svcs.views[c.Name]
			c.Reply <- ret.data
		case c := <-svcs.beatCmdChan:
			var ts = now()
			var s = svcs.getService(c)
			var ref = *s
			s.registerBeat(ts)
			log.Debug("Beat from %s", s.name())
			s.update(ts)
			s.save(svcs.be, &ref, ts)
			svcs.updateViews(ts, s.name())
		case c := <-svcs.deleteServiceCmdChan:
			var ts = now()
			var s = svcs.getService(c)
			delete(svcs.services, s.name())
			svcs.be.DeleteService(s.name())
			svcs.updateViews(ts, s.name())
		case c := <-svcs.upsertServiceCmdChan:
			var ts = now()
			var s = svcs.getService(c.Service)
			var ref = *s
			// Don't re-calculate 'auto' if we already have values
			if c.WarningTimeout == TIMEOUT_AUTO &&
				s.data.WarningTimeout == -1 {
				s.data.WarningTimeout = TIMEOUT_AUTO
				s.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
			} else if c.WarningTimeout == TIMEOUT_CLEAR {
				s.data.WarningTimeout = TIMEOUT_CLEAR
			} else if c.WarningTimeout > 0 {
				s.data.WarningTimeout = c.WarningTimeout
			}
			if c.ErrorTimeout == TIMEOUT_AUTO &&
				s.data.ErrorTimeout == -1 {
				s.data.ErrorTimeout = TIMEOUT_AUTO
				s.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
			} else if c.ErrorTimeout == TIMEOUT_CLEAR {
				s.data.ErrorTimeout = TIMEOUT_CLEAR
			} else if c.ErrorTimeout > 0 {
				s.data.ErrorTimeout = c.ErrorTimeout
			}
			s.update(ts)
			s.save(svcs.be, &ref, ts)
			svcs.updateViews(ts, s.name())
		}
	}
}

func NewServices(beiface backend.Backend, alerters []alert.Alerter) *Services {
	svcs := new(Services)
	svcs.be = beiface
	svcs.alerters = alerters
	svcs.beatCmdChan = make(chan string, MAX_UNPROCESSED_PACKETS)
	svcs.deleteServiceCmdChan = make(chan string, 5)
	svcs.upsertServiceCmdChan = make(chan *upsertServiceCmd, 5)
	svcs.deleteViewCmdChan = make(chan string, 5)
	svcs.upsertViewCmdChan = make(chan *upsertViewCmd, 5)
	svcs.getServicesChan = make(chan *getServicesCmd, 5)
	svcs.getServiceChan = make(chan *getServiceCmd, 5)
	svcs.getViewsChan = make(chan *getViewsCmd, 5)
	svcs.getViewChan = make(chan *getViewCmd, 5)
	svcs.services = make(map[string]*Service)
	svcs.views = make(map[string]*View)

	for _, s := range svcs.be.LoadServices() {
		var svc = &Service{data: *s}
		if svc.data.PreviousBeats == nil || len(svc.data.PreviousBeats) != backend.PREVIOUS_BEATS_COUNT {
			svc.data.PreviousBeats = make([]int64, backend.PREVIOUS_BEATS_COUNT)
		}
		svcs.services[s.Name] = svc
	}

	for _, v := range svcs.be.LoadViews() {
		var ree, _ = regexp.Compile(v.Regexp)
		svcs.views[v.Name] = &View{svcs: svcs, data: *v, ree: ree}
	}

	return svcs
}
<|endoftext|>


<commit_before>package service

import (
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/utils"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var (
	logger = loggo.GetLogger("juju.service")
)

// These are the names of the init systems regognized by juju.
const (
	InitSystemSystemd = "systemd"
	InitSystemUpstart = "upstart"
	InitSystemWindows = "windows"
)

// linuxInitSystems lists the names of the init systems that juju might
// find on a linux host.
var linuxInitSystems = []string{
	InitSystemSystemd,
	InitSystemUpstart,
}

// ServiceActions represents the actions that may be requested for
// an init system service.
type ServiceActions interface {
	// Start will try to start the service.
	Start() error

	// Stop will try to stop the service.
	Stop() error

	// Install installs a service.
	Install() error

	// Remove will remove the service.
	Remove() error
}

// Service represents a service in the init system running on a host.
type Service interface {
	ServiceActions

	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// UpdateConfig adds a config to the service, overwriting the current one.
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running.
	Running() (bool, error)

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() (bool, error)

	// Installed will return a boolean value that denotes
	// whether or not the service is installed.
	Installed() (bool, error)

	// TODO(ericsnow) Move all the commands into a separate interface.

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)

	// StartCommands returns the list of commands to run on a
	// (remote) host to start the service.
	StartCommands() ([]string, error)
}

// RestartableService is a service that directly supports restarting.
type RestartableService interface {
	// Restart restarts the service.
	Restart() error
}

// TODO(ericsnow) bug #1426458
// Eliminate the need to pass an empty conf for most service methods
// and several helper functions.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	if name == "" {
		return nil, errors.New("missing name")
	}

	switch initSystem {
	case InitSystemWindows:
		return windows.NewService(name, conf), nil
	case InitSystemUpstart:
		return upstart.NewService(name, conf), nil
	case InitSystemSystemd:
		svc, err := systemd.NewService(name, conf)
		if err != nil {
			return nil, errors.Annotatef(err, "failed to wrap service %q", name)
		}
		return svc, nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// ListServices lists all installed services on the running system
func ListServices() ([]string, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case InitSystemWindows:
		services, err := windows.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	case InitSystemUpstart:
		services, err := upstart.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	case InitSystemSystemd:
		services, err := systemd.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

// ListServicesScript returns the commands that should be run to get
// a list of service names on a host.
func ListServicesScript() string {
	filename := "/tmp/discover_init_system.sh"
	commands := writeDiscoverInitSystemScript(filename)
	commands = append(commands, newShellSelectCommand(filename, listServicesCommand))
	return strings.Join(commands, "\n")
}

func listServicesCommand(initSystem string) (string, bool) {
	switch initSystem {
	case InitSystemWindows:
		return windows.ListCommand(), true
	case InitSystemUpstart:
		return upstart.ListCommand(), true
	case InitSystemSystemd:
		return systemd.ListCommand(), true
	default:
		return "", false
	}
}

// installStartRetryAttempts defines how much InstallAndStart retries
// upon Start failures.
var installStartRetryAttempts = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 250 * time.Millisecond,
}

// InstallAndStart installs the provided service and tries starting it.
// The first few Start failures are ignored.
func InstallAndStart(svc ServiceActions) error {
	if err := svc.Install(); err != nil {
		return errors.Trace(err)
	}

	// For various reasons the init system may take a short time to
	// realise that the service has been installed.
	var err error
	for attempt := installStartRetryAttempts.Start(); attempt.Next(); {
		if err != nil {
			logger.Errorf("retrying start request (%v)", errors.Cause(err))
		}

		if err = svc.Start(); err == nil {
			break
		}
	}
	return errors.Trace(err)
}

// discoverService is patched out during some tests.
var discoverService = func(name string) (Service, error) {
	return DiscoverService(name, common.Conf{})
}

// TODO(ericsnow) Add one-off helpers for Start and Stop too?

// Restart restarts the named service.
func Restart(name string) error {
	svc, err := discoverService(name)
	if err != nil {
		return errors.Annotatef(err, "failed to find service %q", name)
	}
	if err := restart(svc); err != nil {
		return errors.Annotatef(err, "failed to restart service %q", name)
	}
	return nil
}

func restart(svc Service) error {
	// Use the Restart method, if there is one.
	if svc, ok := svc.(RestartableService); ok {
		if err := svc.Restart(); err != nil {
			return errors.Trace(err)
		}
		return nil
	}

	// Otherwise explicitly stop and start the service.
	if err := svc.Stop(); err != nil {
		return errors.Trace(err)
	}
	if err := svc.Start(); err != nil {
		return errors.Trace(err)
	}
	return nil
}
<commit_msg>Use a const.<commit_after>package service

import (
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/utils"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var (
	logger = loggo.GetLogger("juju.service")
)

// These are the names of the init systems regognized by juju.
const (
	InitSystemSystemd = "systemd"
	InitSystemUpstart = "upstart"
	InitSystemWindows = "windows"
)

// linuxInitSystems lists the names of the init systems that juju might
// find on a linux host.
var linuxInitSystems = []string{
	InitSystemSystemd,
	InitSystemUpstart,
}

// ServiceActions represents the actions that may be requested for
// an init system service.
type ServiceActions interface {
	// Start will try to start the service.
	Start() error

	// Stop will try to stop the service.
	Stop() error

	// Install installs a service.
	Install() error

	// Remove will remove the service.
	Remove() error
}

// Service represents a service in the init system running on a host.
type Service interface {
	ServiceActions

	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// UpdateConfig adds a config to the service, overwriting the current one.
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running.
	Running() (bool, error)

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() (bool, error)

	// Installed will return a boolean value that denotes
	// whether or not the service is installed.
	Installed() (bool, error)

	// TODO(ericsnow) Move all the commands into a separate interface.

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)

	// StartCommands returns the list of commands to run on a
	// (remote) host to start the service.
	StartCommands() ([]string, error)
}

// RestartableService is a service that directly supports restarting.
type RestartableService interface {
	// Restart restarts the service.
	Restart() error
}

// TODO(ericsnow) bug #1426458
// Eliminate the need to pass an empty conf for most service methods
// and several helper functions.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	if name == "" {
		return nil, errors.New("missing name")
	}

	switch initSystem {
	case InitSystemWindows:
		return windows.NewService(name, conf), nil
	case InitSystemUpstart:
		return upstart.NewService(name, conf), nil
	case InitSystemSystemd:
		svc, err := systemd.NewService(name, conf)
		if err != nil {
			return nil, errors.Annotatef(err, "failed to wrap service %q", name)
		}
		return svc, nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// ListServices lists all installed services on the running system
func ListServices() ([]string, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case InitSystemWindows:
		services, err := windows.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	case InitSystemUpstart:
		services, err := upstart.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	case InitSystemSystemd:
		services, err := systemd.ListServices()
		if err != nil {
			return nil, errors.Annotatef(err, "failed to list %s services", initName)
		}
		return services, nil
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

// ListServicesScript returns the commands that should be run to get
// a list of service names on a host.
func ListServicesScript() string {
	const filename = "/tmp/discover_init_system.sh"
	commands := writeDiscoverInitSystemScript(filename)
	commands = append(commands, newShellSelectCommand(filename, listServicesCommand))
	return strings.Join(commands, "\n")
}

func listServicesCommand(initSystem string) (string, bool) {
	switch initSystem {
	case InitSystemWindows:
		return windows.ListCommand(), true
	case InitSystemUpstart:
		return upstart.ListCommand(), true
	case InitSystemSystemd:
		return systemd.ListCommand(), true
	default:
		return "", false
	}
}

// installStartRetryAttempts defines how much InstallAndStart retries
// upon Start failures.
var installStartRetryAttempts = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 250 * time.Millisecond,
}

// InstallAndStart installs the provided service and tries starting it.
// The first few Start failures are ignored.
func InstallAndStart(svc ServiceActions) error {
	if err := svc.Install(); err != nil {
		return errors.Trace(err)
	}

	// For various reasons the init system may take a short time to
	// realise that the service has been installed.
	var err error
	for attempt := installStartRetryAttempts.Start(); attempt.Next(); {
		if err != nil {
			logger.Errorf("retrying start request (%v)", errors.Cause(err))
		}

		if err = svc.Start(); err == nil {
			break
		}
	}
	return errors.Trace(err)
}

// discoverService is patched out during some tests.
var discoverService = func(name string) (Service, error) {
	return DiscoverService(name, common.Conf{})
}

// TODO(ericsnow) Add one-off helpers for Start and Stop too?

// Restart restarts the named service.
func Restart(name string) error {
	svc, err := discoverService(name)
	if err != nil {
		return errors.Annotatef(err, "failed to find service %q", name)
	}
	if err := restart(svc); err != nil {
		return errors.Annotatef(err, "failed to restart service %q", name)
	}
	return nil
}

func restart(svc Service) error {
	// Use the Restart method, if there is one.
	if svc, ok := svc.(RestartableService); ok {
		if err := svc.Restart(); err != nil {
			return errors.Trace(err)
		}
		return nil
	}

	// Otherwise explicitly stop and start the service.
	if err := svc.Stop(); err != nil {
		return errors.Trace(err)
	}
	if err := svc.Start(); err != nil {
		return errors.Trace(err)
	}
	return nil
}
<|endoftext|>


<commit_before>package service

import (
	"c4m/aop"
	"fmt"

	"reflect"

	"github.com/jennal/goplay/defaults"
	"github.com/jennal/goplay/encode"
	"github.com/jennal/goplay/filter"
	"github.com/jennal/goplay/filter/heartbeat"
	"github.com/jennal/goplay/handler"
	"github.com/jennal/goplay/helpers"
	"github.com/jennal/goplay/log"
	"github.com/jennal/goplay/pkg"
	"github.com/jennal/goplay/router"
	"github.com/jennal/goplay/session"
	"github.com/jennal/goplay/transfer"
)

type Service struct {
	transfer.IServer
	router *router.Router

	Name     string
	Encoding pkg.EncodingType

	handlers []handler.IHandler
	filters  []filter.IFilter
}

func NewService(name string, serv transfer.IServer) *Service {
	instance := &Service{
		Name:     name,
		Encoding: defaults.Encoding,
		IServer:  serv,
		router:   router.NewRouter(name),
	}

	serv.RegistDelegate(instance)
	instance.RegistFilter(heartbeat.NewHeartBeatManager())

	return instance
}

func (self *Service) SetEncoding(e pkg.EncodingType) error {
	if encoder := encode.GetEncodeDecoder(e); encoder != nil {
		self.Encoding = e
		return nil
	}

	return log.NewErrorf("can't find encoder with: %v", e)
}

func (self *Service) RegistHanlder(obj handler.IHandler) {
	self.router.Add(obj)
	self.handlers = append(self.handlers, obj)
}

func (self *Service) RegistFilter(obj filter.IFilter) {
	self.filters = append(self.filters, obj)
}

func (self *Service) OnStarted() {
	fmt.Printf("OnStarted %p\n", self)
	for _, handler := range self.handlers {
		handler.OnStarted()
	}
}
func (self *Service) OnError(err error) {
	fmt.Println("OnError", err)
}
func (self *Service) OnStopped() {
	fmt.Println("OnStopped")
	for _, handler := range self.handlers {
		handler.OnStopped()
	}
}
func (self *Service) OnNewClient(client transfer.IClient) {
	fmt.Println("OnNewClient", client)
	sess := session.NewSession(client)
	sess.SetEncoding(self.Encoding)

	for _, filter := range self.filters {
		if !filter.OnNewClient(sess) {
			return
		}
	}

	for _, handler := range self.handlers {
		handler.OnNewClient(sess)
	}

	go func() {
		for {
		NextLoop:
			header, bodyBuf, err := client.Recv()
			if header.Type != pkg.PKG_HEARTBEAT && header.Type != pkg.PKG_HEARTBEAT_RESPONSE {
				log.Logf("Recv:\n\theader => %#v\n\tbody => %#v | %v\n\terr => %v\n", header, bodyBuf, string(bodyBuf), err)
			}

			if err != nil {
				log.Errorf("Recv:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
				sess.Disconnect()
				break
			}

			//filters
			for _, filter := range self.filters {
				if !filter.OnRecv(sess, header, bodyBuf) {
					goto NextLoop
				}
			}

			//map to handler
			switch header.Type {
			case pkg.PKG_NOTIFY:
				_, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
			case pkg.PKG_REQUEST:
				results, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
				// fmt.Printf(" => Loop result: %#v\n", results)
				err = self.response(sess, header, results)
				if err != nil {
					log.Errorf("Response:\n\terr => %v\n\theader => %#v\n\tresults => %#v", err, header, results)
					sess.Disconnect()
					break
				}
			case pkg.PKG_HEARTBEAT: /* Can not come to here */
				fallthrough
			case pkg.PKG_HEARTBEAT_RESPONSE: /* Can not come to here */
				fallthrough
			default:
				log.Errorf("Can't reach here!!\n\terr => %v\n\theader => %#v\n\tbody => %#v", err, header, bodyBuf)
			}
		}
	}()
}

func (self *Service) callRouteFunc(sess *session.Session, header *pkg.Header, bodyBuf []byte) ([]interface{}, error) {
	/*
	 * 1. find route func
	 * 2. unmarshal data
	 * 3. call route func
	 */
	method := self.router.Get(header.Route)
	if method == nil {
		return nil, log.NewErrorf("Can't find method with route: %s", header.Route)
	}
	val := method.NewArg(2)
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))
	decoder := encode.GetEncodeDecoder(header.Encoding)
	err := decoder.Unmarshal(bodyBuf, val)
	if err != nil {
		return nil, log.NewErrorf("Service.callRouteFunc decoder.Unmarshal failed: %v", err)
	}
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))

	var result []interface{}
	aop.Recover(func() {
		result = method.Call(sess, helpers.GetValueFromPtr(val))
	}, func(e interface{}) {
		err = e.(error)
	})

	return result, err
}

func (self *Service) response(sess *session.Session, header *pkg.Header, results []interface{}) error {
	respHeader := *header
	respHeader.Type = pkg.PKG_RESPONSE

	if results == nil || len(results) <= 0 {
		return sess.Send(&respHeader, []byte{})
	}

	result := results[0]
	/* check error != nil */
	if len(results) == 2 && !reflect.ValueOf(results[1]).IsNil() {
		result = results[1]
	}

	// fmt.Println("result:", result)

	encoder := encode.GetEncodeDecoder(header.Encoding)
	body, err := encoder.Marshal(result)
	if err != nil {
		return err
	}

	return sess.Send(&respHeader, body)
}
<commit_msg>fix aop import issue<commit_after>package service

import (
	"fmt"
	"reflect"

	"github.com/jennal/goplay/aop"
	"github.com/jennal/goplay/defaults"
	"github.com/jennal/goplay/encode"
	"github.com/jennal/goplay/filter"
	"github.com/jennal/goplay/filter/heartbeat"
	"github.com/jennal/goplay/handler"
	"github.com/jennal/goplay/helpers"
	"github.com/jennal/goplay/log"
	"github.com/jennal/goplay/pkg"
	"github.com/jennal/goplay/router"
	"github.com/jennal/goplay/session"
	"github.com/jennal/goplay/transfer"
)

type Service struct {
	transfer.IServer
	router *router.Router

	Name     string
	Encoding pkg.EncodingType

	handlers []handler.IHandler
	filters  []filter.IFilter
}

func NewService(name string, serv transfer.IServer) *Service {
	instance := &Service{
		Name:     name,
		Encoding: defaults.Encoding,
		IServer:  serv,
		router:   router.NewRouter(name),
	}

	serv.RegistDelegate(instance)
	instance.RegistFilter(heartbeat.NewHeartBeatManager())

	return instance
}

func (self *Service) SetEncoding(e pkg.EncodingType) error {
	if encoder := encode.GetEncodeDecoder(e); encoder != nil {
		self.Encoding = e
		return nil
	}

	return log.NewErrorf("can't find encoder with: %v", e)
}

func (self *Service) RegistHanlder(obj handler.IHandler) {
	self.router.Add(obj)
	self.handlers = append(self.handlers, obj)
}

func (self *Service) RegistFilter(obj filter.IFilter) {
	self.filters = append(self.filters, obj)
}

func (self *Service) OnStarted() {
	fmt.Printf("OnStarted %p\n", self)
	for _, handler := range self.handlers {
		handler.OnStarted()
	}
}
func (self *Service) OnError(err error) {
	fmt.Println("OnError", err)
}
func (self *Service) OnStopped() {
	fmt.Println("OnStopped")
	for _, handler := range self.handlers {
		handler.OnStopped()
	}
}
func (self *Service) OnNewClient(client transfer.IClient) {
	fmt.Println("OnNewClient", client)
	sess := session.NewSession(client)
	sess.SetEncoding(self.Encoding)

	for _, filter := range self.filters {
		if !filter.OnNewClient(sess) {
			return
		}
	}

	for _, handler := range self.handlers {
		handler.OnNewClient(sess)
	}

	go func() {
		for {
		NextLoop:
			header, bodyBuf, err := client.Recv()
			if header.Type != pkg.PKG_HEARTBEAT && header.Type != pkg.PKG_HEARTBEAT_RESPONSE {
				log.Logf("Recv:\n\theader => %#v\n\tbody => %#v | %v\n\terr => %v\n", header, bodyBuf, string(bodyBuf), err)
			}

			if err != nil {
				log.Errorf("Recv:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
				sess.Disconnect()
				break
			}

			//filters
			for _, filter := range self.filters {
				if !filter.OnRecv(sess, header, bodyBuf) {
					goto NextLoop
				}
			}

			//map to handler
			switch header.Type {
			case pkg.PKG_NOTIFY:
				_, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
			case pkg.PKG_REQUEST:
				results, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
				// fmt.Printf(" => Loop result: %#v\n", results)
				err = self.response(sess, header, results)
				if err != nil {
					log.Errorf("Response:\n\terr => %v\n\theader => %#v\n\tresults => %#v", err, header, results)
					sess.Disconnect()
					break
				}
			case pkg.PKG_HEARTBEAT: /* Can not come to here */
				fallthrough
			case pkg.PKG_HEARTBEAT_RESPONSE: /* Can not come to here */
				fallthrough
			default:
				log.Errorf("Can't reach here!!\n\terr => %v\n\theader => %#v\n\tbody => %#v", err, header, bodyBuf)
			}
		}
	}()
}

func (self *Service) callRouteFunc(sess *session.Session, header *pkg.Header, bodyBuf []byte) ([]interface{}, error) {
	/*
	 * 1. find route func
	 * 2. unmarshal data
	 * 3. call route func
	 */
	method := self.router.Get(header.Route)
	if method == nil {
		return nil, log.NewErrorf("Can't find method with route: %s", header.Route)
	}
	val := method.NewArg(2)
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))
	decoder := encode.GetEncodeDecoder(header.Encoding)
	err := decoder.Unmarshal(bodyBuf, val)
	if err != nil {
		return nil, log.NewErrorf("Service.callRouteFunc decoder.Unmarshal failed: %v", err)
	}
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))

	var result []interface{}
	aop.Recover(func() {
		result = method.Call(sess, helpers.GetValueFromPtr(val))
	}, func(e interface{}) {
		err = e.(error)
	})

	return result, err
}

func (self *Service) response(sess *session.Session, header *pkg.Header, results []interface{}) error {
	respHeader := *header
	respHeader.Type = pkg.PKG_RESPONSE

	if results == nil || len(results) <= 0 {
		return sess.Send(&respHeader, []byte{})
	}

	result := results[0]
	/* check error != nil */
	if len(results) == 2 && !reflect.ValueOf(results[1]).IsNil() {
		result = results[1]
	}

	// fmt.Println("result:", result)

	encoder := encode.GetEncodeDecoder(header.Encoding)
	body, err := encoder.Marshal(result)
	if err != nil {
		return err
	}

	return sess.Send(&respHeader, body)
}
<|endoftext|>


<commit_before>package plugins

import (
    "github.com/bwmarrin/discordgo"
    "strings"
    "github.com/Seklfreak/Robyul2/helpers"
    "fmt"
    "github.com/getsentry/raven-go"
)

type AutoRoles struct{}

func (a *AutoRoles) Commands() []string {
    return []string{
        "autorole",
        "autoroles",
    }
}

func (a *AutoRoles) Init(session *discordgo.Session) {
}

func (a *AutoRoles) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
    args := strings.Fields(content)
    if len(args) >= 1 {
        switch args[0] {
        case "add":
            session.ChannelTyping(msg.ChannelID)
            helpers.RequireAdmin(msg, func() {
                if len(args) < 2 {
                    _, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
                    helpers.Relax(err)
                    return
                }
                channel, err := helpers.GetChannel(msg.ChannelID)
                helpers.Relax(err)

                serverRoles, err := session.GuildRoles(channel.GuildID)
                helpers.Relax(err)

                var targetRole *discordgo.Role
                for _, role := range serverRoles {
                    if role.Name == args[1] || role.ID == args[1] {
                        targetRole = role
                    }
                }
                if targetRole.ID == "" {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
                    helpers.Relax(err)
                    return
                }

                settings := helpers.GuildSettingsGetCached(channel.GuildID)

                for _, role := range settings.AutoRoleIDs {
                    if role == targetRole.ID {
                        _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-add-error-duplicate"))
                        helpers.Relax(err)
                        return
                    }
                }

                settings.AutoRoleIDs = append(settings.AutoRoleIDs, targetRole.ID)

                err = helpers.GuildSettingsSet(channel.GuildID, settings)
                helpers.Relax(err)

                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetTextF("plugins.autorole.role-add-success",
                    targetRole.Name))
                helpers.Relax(err)
                return
            })
            return
        case "list":
            session.ChannelTyping(msg.ChannelID)
            channel, err := helpers.GetChannel(msg.ChannelID)
            helpers.Relax(err)
            settings := helpers.GuildSettingsGetCached(channel.GuildID)

            if len(settings.AutoRoleIDs) <= 0 {
                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-list-none"))
                helpers.Relax(err)
                return
            }

            result := "AutoRoles on this server: "

            for _, roleID := range settings.AutoRoleIDs {
                role, err := session.State.Role(channel.GuildID, roleID)
                if err == nil {
                    result += fmt.Sprintf("`%s (#%s)` ", role.Name, role.ID)
                } else {
                    result += fmt.Sprintf("`N/A (#%s)` ", roleID)
                }
            }

            result += fmt.Sprintf("(%d role(s))", len(settings.AutoRoleIDs))

            _, err = session.ChannelMessageSend(msg.ChannelID, result)
            helpers.Relax(err)
            return
        case "delete", "remove":
            session.ChannelTyping(msg.ChannelID)
            helpers.RequireAdmin(msg, func() {
                if len(args) < 2 {
                    _, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
                    helpers.Relax(err)
                    return
                }
                channel, err := helpers.GetChannel(msg.ChannelID)
                helpers.Relax(err)

                serverRoles, err := session.GuildRoles(channel.GuildID)
                helpers.Relax(err)

                var targetRole *discordgo.Role
                for _, role := range serverRoles {
                    if role.Name == args[1] || role.ID == args[1] {
                        targetRole = role
                    }
                }
                if targetRole == nil || targetRole.ID == "" {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
                    helpers.Relax(err)
                    return
                }

                settings := helpers.GuildSettingsGetCached(channel.GuildID)

                roleWasInList := false
                newRoleIDs := make([]string, 0)

                for _, role := range settings.AutoRoleIDs {
                    if role == targetRole.ID {
                        roleWasInList = true
                    } else {
                        newRoleIDs = append(newRoleIDs, role)
                    }
                }

                if roleWasInList == false {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-remove-error-not-found"))
                    helpers.Relax(err)
                    return
                }

                settings.AutoRoleIDs = newRoleIDs

                err = helpers.GuildSettingsSet(channel.GuildID, settings)
                helpers.Relax(err)

                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-remove-success"))
                helpers.Relax(err)
                return
            })
            return
        }
    }
}

func (a *AutoRoles) OnMessage(content string, msg *discordgo.Message, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildMemberAdd(member *discordgo.Member, session *discordgo.Session) {
    settings := helpers.GuildSettingsGetCached(member.GuildID)
    for _, roleID := range settings.AutoRoleIDs {
        err := session.GuildMemberRoleAdd(member.GuildID, member.User.ID, roleID)
        if err != nil {
            raven.CaptureError(fmt.Errorf("%#v", err), map[string]string{})
            continue
        }
    }

}

func (a *AutoRoles) OnGuildMemberRemove(member *discordgo.Member, session *discordgo.Session) {

}

func (a *AutoRoles) OnReactionAdd(reaction *discordgo.MessageReactionAdd, session *discordgo.Session) {

}

func (a *AutoRoles) OnReactionRemove(reaction *discordgo.MessageReactionRemove, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildBanAdd(user *discordgo.GuildBanAdd, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildBanRemove(user *discordgo.GuildBanRemove, session *discordgo.Session) {

}
<commit_msg>[AutoRole] put assigning in a coroutine<commit_after>package plugins

import (
    "github.com/bwmarrin/discordgo"
    "strings"
    "github.com/Seklfreak/Robyul2/helpers"
    "fmt"
    "github.com/getsentry/raven-go"
)

type AutoRoles struct{}

func (a *AutoRoles) Commands() []string {
    return []string{
        "autorole",
        "autoroles",
    }
}

func (a *AutoRoles) Init(session *discordgo.Session) {
}

func (a *AutoRoles) Action(command string, content string, msg *discordgo.Message, session *discordgo.Session) {
    args := strings.Fields(content)
    if len(args) >= 1 {
        switch args[0] {
        case "add":
            session.ChannelTyping(msg.ChannelID)
            helpers.RequireAdmin(msg, func() {
                if len(args) < 2 {
                    _, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
                    helpers.Relax(err)
                    return
                }
                channel, err := helpers.GetChannel(msg.ChannelID)
                helpers.Relax(err)

                serverRoles, err := session.GuildRoles(channel.GuildID)
                helpers.Relax(err)

                var targetRole *discordgo.Role
                for _, role := range serverRoles {
                    if role.Name == args[1] || role.ID == args[1] {
                        targetRole = role
                    }
                }
                if targetRole.ID == "" {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
                    helpers.Relax(err)
                    return
                }

                settings := helpers.GuildSettingsGetCached(channel.GuildID)

                for _, role := range settings.AutoRoleIDs {
                    if role == targetRole.ID {
                        _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-add-error-duplicate"))
                        helpers.Relax(err)
                        return
                    }
                }

                settings.AutoRoleIDs = append(settings.AutoRoleIDs, targetRole.ID)

                err = helpers.GuildSettingsSet(channel.GuildID, settings)
                helpers.Relax(err)

                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetTextF("plugins.autorole.role-add-success",
                    targetRole.Name))
                helpers.Relax(err)
                return
            })
            return
        case "list":
            session.ChannelTyping(msg.ChannelID)
            channel, err := helpers.GetChannel(msg.ChannelID)
            helpers.Relax(err)
            settings := helpers.GuildSettingsGetCached(channel.GuildID)

            if len(settings.AutoRoleIDs) <= 0 {
                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-list-none"))
                helpers.Relax(err)
                return
            }

            result := "AutoRoles on this server: "

            for _, roleID := range settings.AutoRoleIDs {
                role, err := session.State.Role(channel.GuildID, roleID)
                if err == nil {
                    result += fmt.Sprintf("`%s (#%s)` ", role.Name, role.ID)
                } else {
                    result += fmt.Sprintf("`N/A (#%s)` ", roleID)
                }
            }

            result += fmt.Sprintf("(%d role(s))", len(settings.AutoRoleIDs))

            _, err = session.ChannelMessageSend(msg.ChannelID, result)
            helpers.Relax(err)
            return
        case "delete", "remove":
            session.ChannelTyping(msg.ChannelID)
            helpers.RequireAdmin(msg, func() {
                if len(args) < 2 {
                    _, err := session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.too-few"))
                    helpers.Relax(err)
                    return
                }
                channel, err := helpers.GetChannel(msg.ChannelID)
                helpers.Relax(err)

                serverRoles, err := session.GuildRoles(channel.GuildID)
                helpers.Relax(err)

                var targetRole *discordgo.Role
                for _, role := range serverRoles {
                    if role.Name == args[1] || role.ID == args[1] {
                        targetRole = role
                    }
                }
                if targetRole == nil || targetRole.ID == "" {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
                    helpers.Relax(err)
                    return
                }

                settings := helpers.GuildSettingsGetCached(channel.GuildID)

                roleWasInList := false
                newRoleIDs := make([]string, 0)

                for _, role := range settings.AutoRoleIDs {
                    if role == targetRole.ID {
                        roleWasInList = true
                    } else {
                        newRoleIDs = append(newRoleIDs, role)
                    }
                }

                if roleWasInList == false {
                    _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-remove-error-not-found"))
                    helpers.Relax(err)
                    return
                }

                settings.AutoRoleIDs = newRoleIDs

                err = helpers.GuildSettingsSet(channel.GuildID, settings)
                helpers.Relax(err)

                _, err = session.ChannelMessageSend(msg.ChannelID, helpers.GetText("plugins.autorole.role-remove-success"))
                helpers.Relax(err)
                return
            })
            return
        }
    }
}

func (a *AutoRoles) OnMessage(content string, msg *discordgo.Message, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildMemberAdd(member *discordgo.Member, session *discordgo.Session) {
    go func() {
        settings := helpers.GuildSettingsGetCached(member.GuildID)
        for _, roleID := range settings.AutoRoleIDs {
            err := session.GuildMemberRoleAdd(member.GuildID, member.User.ID, roleID)
            if err != nil {
                raven.CaptureError(fmt.Errorf("%#v", err), map[string]string{})
                continue
            }
        }
    }()
}

func (a *AutoRoles) OnGuildMemberRemove(member *discordgo.Member, session *discordgo.Session) {

}

func (a *AutoRoles) OnReactionAdd(reaction *discordgo.MessageReactionAdd, session *discordgo.Session) {

}

func (a *AutoRoles) OnReactionRemove(reaction *discordgo.MessageReactionRemove, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildBanAdd(user *discordgo.GuildBanAdd, session *discordgo.Session) {

}

func (a *AutoRoles) OnGuildBanRemove(user *discordgo.GuildBanRemove, session *discordgo.Session) {

}
<|endoftext|>


<commit_before>package flotilla

import "github.com/simulatedsimian/flotilla-go/dock"

type Matrix struct {
	ModuleCommon

	buffer     [8]byte
	brightness byte
	dirty      bool
}

func (m *Matrix) Construct() {
	m.brightness = 64
	m.dirty = true
}

func (m *Matrix) Set(d *dock.Dock) error {
	if m.dirty && m.address != nil {
		m.dirty = false
		return d.SetModuleData(m.address.channel, m.Type(),
			int(m.buffer[0]), int(m.buffer[1]), int(m.buffer[2]), int(m.buffer[3]),
			int(m.buffer[4]), int(m.buffer[5]), int(m.buffer[6]), int(m.buffer[7]),
			int(m.brightness))
	}
	return nil
}

func (m *Matrix) Type() dock.ModuleType {
	return dock.Matrix
}

func (m *Matrix) SetBrightness(b int) {
	m.brightness = byte(b)
	m.dirty = true
}

func (m *Matrix) Plot(x, y, v int) {
	x = 7 - x&7
	y = y & 7

	if v == 0 {
		m.buffer[x] = m.buffer[x] & ^(1 << uint(y))
	} else {
		m.buffer[x] = m.buffer[x] | (1 << uint(y))
	}

	m.dirty = true
}

func (m *Matrix) DrawBarGraph(values []int, min, max int) {
	m.Clear()

	bars := MinInt(8, len(values))

	for i := 0; i < bars; i++ {
		y := Map(values[i], min, max, 0, 7)
		for n := 0; n <= y; n++ {
			m.Plot(i, 7-n, 1)
		}
	}
}

func (m *Matrix) Clear() {
	m.buffer = [8]byte{}
}

func (m *Matrix) Scroll(dir Direction, fill int) {
	if dir&DirLeft != 0 {
		m.ScrollLeft(fill)
	}
	if dir&DirRight != 0 {
		m.ScrollRight(fill)
	}
	if dir&DirUp != 0 {
		m.ScrollUp(fill)
	}
	if dir&DirDown != 0 {
		m.ScrollDown(fill)
	}
}

func (m *Matrix) ScrollRight(fill int) {
	copy(m.buffer[:], m.buffer[1:])
	m.buffer[7] = byte(fill)
	m.dirty = true
}

func (m *Matrix) ScrollLeft(fill int) {
	copy(m.buffer[1:], m.buffer[:])
	m.buffer[0] = byte(fill)
	m.dirty = true
}

func (m *Matrix) ScrollDown(fill int) {
	for i := range m.buffer {
		m.buffer[i] = (m.buffer[i] << 1) | (byte(fill)>>byte(7-i))&1
	}
	m.dirty = true
}

func (m *Matrix) ScrollUp(fill int) {
	for i := range m.buffer {
		m.buffer[i] = (m.buffer[i] >> 1) | ((byte(fill)>>byte(7-i))&1)<<7
	}
	m.dirty = true
}

func (m *Matrix) Roll(dir Direction) {
	if dir&DirLeft != 0 {
		m.RollLeft()
	}
	if dir&DirRight != 0 {
		m.RollRight()
	}
	if dir&DirUp != 0 {
		m.RollUp()
	}
	if dir&DirDown != 0 {
		m.RollDown()
	}
}

func (m *Matrix) RollUp() {
	m.dirty = true
}

func (m *Matrix) RollDown() {
	m.dirty = true
}

func (m *Matrix) RollLeft() {
	m.dirty = true
}

func (m *Matrix) RollRight() {
	m.dirty = true
}
<commit_msg>unfinished update to scolling function<commit_after>package flotilla

import "github.com/simulatedsimian/flotilla-go/dock"

type Matrix struct {
	ModuleCommon

	buffer     [8]byte
	brightness byte
	dirty      bool
}

func (m *Matrix) Construct() {
	m.brightness = 64
	m.dirty = true
}

func (m *Matrix) Set(d *dock.Dock) error {
	if m.dirty && m.address != nil {
		m.dirty = false
		return d.SetModuleData(m.address.channel, m.Type(),
			int(m.buffer[0]), int(m.buffer[1]), int(m.buffer[2]), int(m.buffer[3]),
			int(m.buffer[4]), int(m.buffer[5]), int(m.buffer[6]), int(m.buffer[7]),
			int(m.brightness))
	}
	return nil
}

func (m *Matrix) Type() dock.ModuleType {
	return dock.Matrix
}

func (m *Matrix) SetBrightness(b int) {
	m.brightness = byte(b)
	m.dirty = true
}

func (m *Matrix) Plot(x, y, v int) {
	x = 7 - x&7
	y = y & 7

	if v == 0 {
		m.buffer[x] = m.buffer[x] & ^(1 << uint(y))
	} else {
		m.buffer[x] = m.buffer[x] | (1 << uint(y))
	}

	m.dirty = true
}

func (m *Matrix) DrawBarGraph(values []int, min, max int) {
	m.Clear()

	bars := MinInt(8, len(values))

	for i := 0; i < bars; i++ {
		y := Map(values[i], min, max, 0, 7)
		for n := 0; n <= y; n++ {
			m.Plot(i, 7-n, 1)
		}
	}
}

func (m *Matrix) Clear() {
	m.buffer = [8]byte{}
}

func (m *Matrix) GetRow(i int) byte {

}

func (m *Matrix) SetRow(i int, v byte) {

}

func (m *Matrix) GetCol(i int) byte {

}

func (m *Matrix) SetCol(i int, v byte) {

}

func (m *Matrix) Scroll(dir Direction, fill int) {
	if dir&DirLeft != 0 {
		m.ScrollLeft(fill)
	}
	if dir&DirRight != 0 {
		m.ScrollRight(fill)
	}
	if dir&DirUp != 0 {
		m.ScrollUp(fill)
	}
	if dir&DirDown != 0 {
		m.ScrollDown(fill)
	}
}

func (m *Matrix) ScrollRight(fill int) {
	copy(m.buffer[:], m.buffer[1:])
	m.buffer[7] = byte(fill)
	m.dirty = true
}

func (m *Matrix) ScrollLeft(fill int) {
	copy(m.buffer[1:], m.buffer[:])
	m.buffer[0] = byte(fill)
	m.dirty = true
}

func (m *Matrix) ScrollDown(fill int) {
	for i := range m.buffer {
		m.buffer[i] = (m.buffer[i] << 1) | (byte(fill)>>byte(7-i))&1
	}
	m.dirty = true
}

func (m *Matrix) ScrollUp(fill int) {
	for i := range m.buffer {
		m.buffer[i] = (m.buffer[i] >> 1) | ((byte(fill)>>byte(7-i))&1)<<7
	}
	m.dirty = true
}

func (m *Matrix) Roll(dir Direction) {
	if dir&DirLeft != 0 {
		m.RollLeft()
	}
	if dir&DirRight != 0 {
		m.RollRight()
	}
	if dir&DirUp != 0 {
		m.RollUp()
	}
	if dir&DirDown != 0 {
		m.RollDown()
	}
}

func (m *Matrix) RollUp() {
	m.dirty = true
}

func (m *Matrix) RollDown() {
	m.dirty = true
}

func (m *Matrix) RollLeft() {
	m.dirty = true
}

func (m *Matrix) RollRight() {
	m.dirty = true
}
<|endoftext|>


<commit_before>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"sync"
	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"gopkg.in/mgo.v2/bson"
    "strings"
)

var conn dbox.IConnection
var count int
var wg *sync.WaitGroup
var mtx *sync.Mutex

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

type alloc struct {
	Total  float64
	Ratios []*gdrj.SalesRatio
}

var (
	//ledgers = toolkit.M{}
	plmodels = toolkit.M{}
	pcs      = toolkit.M{}
	ccs      = toolkit.M{}
	prods    = toolkit.M{}
	custs    = toolkit.M{}
	ratios   = map[string]*alloc{}
)

func getCursor(obj orm.IModel) dbox.ICursor {
	c, e := gdrj.Find(obj, nil, nil)
	if e != nil {
		return nil
	}
	return c
}
//var cogss = map[string]*cogs{}
func main() {
	setinitialconnection()
	defer gdrj.CloseDb()

    conn.NewQuery().From(new(gdrj.RawDataPL).TableName()).
        Where(dbox.Eq("year",2015)).
        Delete().Exec(nil)

	toolkit.Println("START...")
	t0 := time.Now()
	/*
    crx, err := conn.NewQuery().
        From(new(gdrj.RawDataPL).TableName()).
        //Where(dbox.In("src","31052016SAP_DISC-RDJKT","30052016SAP_EXPORT")).
		Cursor(nil)
	if err != nil {
		toolkit.Println("Error Found : ", err.Error())
		os.Exit(1)
	}
	defer crx.Close()

	count := crx.Count()
	jobs := make(chan *gdrj.RawDataPL, count)
	result := make(chan string, count)

	for wi := 1; wi < 10; wi++ {
		go worker(wi, jobs, result)
	}

	i := 0
	step := count / 100
	limit := step
	for {
		//datas := []gdrj.RawDataPL{}
		data := new(gdrj.RawDataPL)
        err = crx.Fetch(data,1, false)
		if err != nil {
			toolkit.Printfn("Exit loop: %s", err.Error())
			break
		}

        i++
        jobs <- data

        if i >= limit {
            toolkit.Printfn("Calc %d of %d (%dpct) in %s", i, count, i*100/count,
                time.Since(t0).String())
            limit += step
        }
	}
	close(jobs)

	toolkit.Println("Saving")
	limit = step
	for ri := 0; ri < count; ri++ {
		<-result
		if ri >= limit {
			toolkit.Printfn("Saving %d of %d (%dpct) in %s", ri, count, ri*100/count,
				time.Since(t0).String())
			limit += step
		}
	}
    */

    saveOtherTable("tmpapintra2016","APROMO")
    saveOtherTable("tmpfreight2016","FREIGHT")
    saveOtherTable("tmpmegasari2016","APROMO")
    //saveOtherTable("tmpsusemi2016","APROMO")
    saveOtherTable("tmproyalti201516","ROYALTI")
    saveOtherTable("tmpsga2016","SGAPL")

    toolkit.Printfn("Done %s", time.Since(t0).String())
}

func saveOtherTable(tablename string, src string){
    toolkit.Printfn("START PROCESSING %s", tablename)

    qdata, _ := conn.NewQuery().From(tablename).Cursor(nil)
    defer qdata.Close()

    objCount := qdata.Count()
    jobs := make(chan toolkit.M, objCount)
    outs := make(chan string, objCount)

    for wi:=0;wi<10;wi++{
        go workerSave(src, jobs, outs)
    }

    i:=0
    for{

        m := toolkit.M{}
        e := qdata.Fetch(&m,1,false)
        if e!=nil {
            break
        }
        i++
        jobs <- m
        toolkit.Printfn("Sending %s | %d of %d", tablename, i, objCount)
    }
    close(jobs)

    for i:=1;i<=objCount;i++{
        toolkit.Printfn("Receiving %s | %d of %d", tablename, i, objCount)
    }
    close(outs)
}

func workerSave(src string, jobs <-chan toolkit.M, outs chan<- string){
    workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()

    for m := range jobs{
        r := new(gdrj.RawDataPL)
        r.Year = 2015
        r.Src=src
        r.Account = toolkit.ToString(m.GetInt("glaccount"))
        r.Grouping = m.GetString("grouping")
        r.Period = m.GetInt("period")
        r.CCID = m.GetString("ccid")
        r.CostCenterName = m.GetString("ccname")
        r.AmountinIDR = m.GetFloat64("amount")
        r.EntityID = m.GetString("cocd")
        r.APProposalNo = m.GetString("proposalno")
        r.PCID = m.GetString("pcid")
        if r.AmountinIDR==0 {
            amountInStr := m.GetString("amount")
            if amountInStr!=""{
                r.AmountinIDR = toolkit.ToFloat64(amountInStr,0,toolkit.RoundingAuto)
            }
        }
        r.ID = bson.NewObjectId().String()
        e := workerConn.NewQuery().From(r.TableName()).Save().Exec(toolkit.M{}.Set("data",r))
        if e!=nil {
            toolkit.Printfn("Error save %s: \n%s", toolkit.JsonString(r), e.Error())
            os.Exit(100)
        }
    }
}

func worker(wi int, jobs <-chan *gdrj.RawDataPL, r chan<- string) {
	workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()

    for m := range jobs {
        lowersrc := strings.ToLower(m.Src)
		if strings.Contains(lowersrc,"salesrd"){
            m.Src="SALESRD"
        } else if strings.Contains(lowersrc,"disc-rd"){
            m.Src="DISCRD"
        } else if strings.Contains(lowersrc,"export"){
            m.Src="EXPORT"
        } else if strings.Contains(lowersrc,"freight"){
            m.Src="FREIGHT"
        } else if strings.Contains(lowersrc,"sgapl"){
            m.Src="SGAPL"
        } else {
            m.Src="APROMO"
        }
		workerConn.NewQuery().From(m.TableName()).Save().Exec(toolkit.M{}.Set("data",m))
	    r <- "OK " + m.OutletName
	}
}
<commit_msg>updat<commit_after>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"sync"
	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"gopkg.in/mgo.v2/bson"
    "strings"
)

var conn dbox.IConnection
var count int
var wg *sync.WaitGroup
var mtx *sync.Mutex

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

type alloc struct {
	Total  float64
	Ratios []*gdrj.SalesRatio
}

var (
	//ledgers = toolkit.M{}
	plmodels = toolkit.M{}
	pcs      = toolkit.M{}
	ccs      = toolkit.M{}
	prods    = toolkit.M{}
	custs    = toolkit.M{}
	ratios   = map[string]*alloc{}
)

func getCursor(obj orm.IModel) dbox.ICursor {
	c, e := gdrj.Find(obj, nil, nil)
	if e != nil {
		return nil
	}
	return c
}
//var cogss = map[string]*cogs{}
func main() {
	setinitialconnection()
	defer gdrj.CloseDb()

    conn.NewQuery().From(new(gdrj.RawDataPL).TableName()).
        Where(dbox.Eq("year",2015)).
        Delete().Exec(nil)

	toolkit.Println("START...")
	t0 := time.Now()
	/*
    crx, err := conn.NewQuery().
        From(new(gdrj.RawDataPL).TableName()).
        //Where(dbox.In("src","31052016SAP_DISC-RDJKT","30052016SAP_EXPORT")).
		Cursor(nil)
	if err != nil {
		toolkit.Println("Error Found : ", err.Error())
		os.Exit(1)
	}
	defer crx.Close()

	count := crx.Count()
	jobs := make(chan *gdrj.RawDataPL, count)
	result := make(chan string, count)

	for wi := 1; wi < 10; wi++ {
		go worker(wi, jobs, result)
	}

	i := 0
	step := count / 100
	limit := step
	for {
		//datas := []gdrj.RawDataPL{}
		data := new(gdrj.RawDataPL)
        err = crx.Fetch(data,1, false)
		if err != nil {
			toolkit.Printfn("Exit loop: %s", err.Error())
			break
		}

        i++
        jobs <- data

        if i >= limit {
            toolkit.Printfn("Calc %d of %d (%dpct) in %s", i, count, i*100/count,
                time.Since(t0).String())
            limit += step
        }
	}
	close(jobs)

	toolkit.Println("Saving")
	limit = step
	for ri := 0; ri < count; ri++ {
		<-result
		if ri >= limit {
			toolkit.Printfn("Saving %d of %d (%dpct) in %s", ri, count, ri*100/count,
				time.Since(t0).String())
			limit += step
		}
	}
    */

    saveOtherTable("tmpapintra2016","APROMO")
    saveOtherTable("tmpfreight2016","FREIGHT")
    saveOtherTable("tmpmegasari2016","APROMO")
    //saveOtherTable("tmpsusemi2016","APROMO")
    saveOtherTable("tmproyalti201516","ROYALTI")
    saveOtherTable("tmpsga2016","SGAPL")

    toolkit.Printfn("Done %s", time.Since(t0).String())
}

func saveOtherTable(tablename string, src string){
    toolkit.Printfn("START PROCESSING %s", tablename)
    workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()

    qdata, _ := conn.NewQuery().From(tablename).Cursor(nil)
    defer qdata.Close()

    objCount := qdata.Count()
    /*
    jobs := make(chan toolkit.M, objCount)
    outs := make(chan string, objCount)

    for wi:=0;wi<10;wi++{
        go workerSave(src, jobs, outs)
    }
    */

    i:=0
    for{

        m := toolkit.M{}
        e := qdata.Fetch(&m,1,false)
        if e!=nil {
            break
        }
        i++

        r := new(gdrj.RawDataPL)
        r.Year = 2015
        r.Src=src
        r.Account = toolkit.ToString(m.GetInt("glaccount"))
        r.Grouping = m.GetString("grouping")
        r.Period = m.GetInt("period")
        r.CCID = m.GetString("ccid")
        r.CostCenterName = m.GetString("ccname")
        r.AmountinIDR = m.GetFloat64("amount")
        r.EntityID = m.GetString("cocd")
        r.APProposalNo = m.GetString("proposalno")
        r.PCID = m.GetString("pcid")
        if r.AmountinIDR==0 {
            amountInStr := m.GetString("amount")
            if amountInStr!=""{
                r.AmountinIDR = toolkit.ToFloat64(amountInStr,0,toolkit.RoundingAuto)
            }
        }
        r.ID = bson.NewObjectId().String()
        e = workerConn.NewQuery().From(r.TableName()).Save().Exec(toolkit.M{}.Set("data",r))
        if e!=nil {
            toolkit.Printfn("Error save %s: \n%s", toolkit.JsonString(r), e.Error())
            os.Exit(100)
        }

        //jobs <- m
        toolkit.Printfn("Sending %s | %d of %d", tablename, i, objCount)
    }
    //close(jobs)

    /*
    for i:=1;i<=objCount;i++{
        toolkit.Printfn("Receiving %s | %d of %d", tablename, i, objCount)
    }
    close(outs)
    */
}

func workerSave(src string, jobs <-chan toolkit.M, outs chan<- string){
}

func worker(wi int, jobs <-chan *gdrj.RawDataPL, r chan<- string) {
	workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()

    for m := range jobs {
        lowersrc := strings.ToLower(m.Src)
		if strings.Contains(lowersrc,"salesrd"){
            m.Src="SALESRD"
        } else if strings.Contains(lowersrc,"disc-rd"){
            m.Src="DISCRD"
        } else if strings.Contains(lowersrc,"export"){
            m.Src="EXPORT"
        } else if strings.Contains(lowersrc,"freight"){
            m.Src="FREIGHT"
        } else if strings.Contains(lowersrc,"sgapl"){
            m.Src="SGAPL"
        } else {
            m.Src="APROMO"
        }
		workerConn.NewQuery().From(m.TableName()).Save().Exec(toolkit.M{}.Set("data",m))
	    r <- "OK " + m.OutletName
	}
}
<|endoftext|>


<commit_before>// Tideland Go Cells - Behaviors - Unit Tests - Event Combination
//
// Copyright (C) 2010-2017 Frank Mueller / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package behaviors_test

//--------------------
// IMPORTS
//--------------------

import (
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gocells/behaviors"
	"github.com/tideland/gocells/cells"
)

//--------------------
// TESTS
//--------------------

// TestComboBehavior tests the event combo behavior.
func TestComboBehavior(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	generator := audit.NewGenerator(audit.FixedRand())
	sigc := audit.MakeSigChan()
	env := cells.NewEnvironment("combo-behavior")
	defer env.Stop()

	matcher := func(accessor cells.EventSinkAccessor) (cells.CriterionMatch, cells.Payload) {
		combo := map[string]int{
			"a": 0,
			"b": 0,
			"c": 0,
			"d": 0,
		}
		matches, err := accessor.Match(func(index int, event cells.Event) (bool, error) {
			_, ok := combo[event.Topic()]
			if ok {
				combo[event.Topic()]++
			}
			return ok, nil
		})
		if err != nil || !matches {
			return cells.CriterionDropLast, nil
		}
		for _, count := range combo {
			if count == 0 {
				return cells.CriterionKeep, nil
			}
		}
		payload, err := cells.NewPayload(combo)
		assert.Nil(err)
		return cells.CriterionDone, payload
	}
	processor := func(accessor cells.EventSinkAccessor) error {
		sigc <- accessor.Len()
		return nil
	}

	topics := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "now"}

	env.StartCell("combiner", behaviors.NewComboBehavior(matcher))
	env.StartCell("collector", behaviors.NewCollectorBehavior(100, processor))
	env.Subscribe("combiner", "collector")

	for i := 0; i < 1000; i++ {
		topic := generator.OneStringOf(topics...)
		env.EmitNew("combiner", topic, nil)
		// generator.SleepOneOf(0, 1*time.Millisecond, 2*time.Millisecond)
	}

	env.EmitNew("collector", cells.TopicProcess, nil)
	assert.Wait(sigc, 10, time.Minute)
}

// EOF
<commit_msg>Fixed combo test<commit_after>// Tideland Go Cells - Behaviors - Unit Tests - Event Combination
//
// Copyright (C) 2010-2017 Frank Mueller / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package behaviors_test

//--------------------
// IMPORTS
//--------------------

import (
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gocells/behaviors"
	"github.com/tideland/gocells/cells"
)

//--------------------
// TESTS
//--------------------

// TestComboBehavior tests the event combo behavior.
func TestComboBehavior(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	generator := audit.NewGenerator(audit.FixedRand())
	sigc := audit.MakeSigChan()
	env := cells.NewEnvironment("combo-behavior")
	defer env.Stop()

	matcher := func(accessor cells.EventSinkAccessor) (cells.CriterionMatch, cells.Payload) {
		combo := map[string]int{
			"a": 0,
			"b": 0,
			"c": 0,
			"d": 0,
		}
		matches, err := accessor.Match(func(index int, event cells.Event) (bool, error) {
			_, ok := combo[event.Topic()]
			if ok {
				combo[event.Topic()]++
			}
			return ok, nil
		})
		if err != nil || !matches {
			return cells.CriterionDropLast, nil
		}
		for _, count := range combo {
			if count == 0 {
				return cells.CriterionKeep, nil
			}
		}
		payload, err := cells.NewPayload(combo)
		assert.Nil(err)
		return cells.CriterionDone, payload
	}
	processor := func(accessor cells.EventSinkAccessor) error {
		ok, err := accessor.Match(func(index int, event cells.Event) (bool, error) {
			var payload map[string]int
			if err := event.Payload().Unmarshal(&payload); err != nil {
				return false, err
			}
			if len(payload) != 4 {
				return false, nil
			}
			for key := range payload {
				if payload[key] == 0 {
					return false, nil
				}
			}
			return true, nil
		})
		sigc <- ok
		return err
	}

	topics := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "now"}

	env.StartCell("combiner", behaviors.NewComboBehavior(matcher))
	env.StartCell("collector", behaviors.NewCollectorBehavior(100, processor))
	env.Subscribe("combiner", "collector")

	for i := 0; i < 1000; i++ {
		topic := generator.OneStringOf(topics...)
		env.EmitNew("combiner", topic, nil)
	}

	env.EmitNew("collector", cells.TopicProcess, nil)
	assert.Wait(sigc, true, time.Minute)
}

// EOF
<|endoftext|>


<commit_before>package mqutil

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/go-openapi/swag"
	"gopkg.in/yaml.v2"
)

// MapInterfaceToMapString converts the params map (all primitive types with exception of array)
// before passing to resty.
func MapInterfaceToMapString(src map[string]interface{}) map[string]string {
	dst := make(map[string]string)
	for k, v := range src {
		if ar, ok := v.([]interface{}); ok {
			str := ""
			for _, entry := range ar {
				str += fmt.Sprintf("%v,", entry)
			}
			str = strings.TrimRight(str, ",")
			dst[k] = str
		} else {
			dst[k] = fmt.Sprint(v)
		}
	}
	return dst
}

// MapIsCompatible checks if the first map has every key in the second.
func MapIsCompatible(big map[string]interface{}, small map[string]interface{}) bool {
	for k, _ := range small {
		if _, ok := big[k]; !ok {
			return false
		}
	}
	return true
}

func TimeCompare(v1 interface{}, v2 interface{}) bool {
	s1, ok := v1.(string)
	if !ok {
		return false
	}
	s2, ok := v2.(string)
	if !ok {
		return false
	}
	var t time.Time
	var s string
	var b1, b2 bool
	t1, err := time.Parse(time.RFC3339, s1)
	if err == nil {
		t = t1
		s = s2
		b1 = true
	}
	t2, err := time.Parse(time.RFC3339, s2)
	if err == nil {
		t = t2
		s = s1
		b2 = true
	}
	if b1 && b2 {
		return t1 == t2
	}
	if !b1 && !b2 {
		return false
	}
	// One of b1 and b2 is true, now t point to time and s point to a potential time string
	// that's not RFC3339 format. We make a guess buy searching for a few key elements.
	return strings.Contains(s, fmt.Sprintf("%d", t.Second())) && strings.Contains(s, fmt.Sprintf("%d", t.Minute()))
}

// MapCombine combines two map together. If there is any overlap the dst will be overwritten.
func MapCombine(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(dst) == 0 {
		return MapCopy(src)
	}
	if len(src) == 0 {
		return dst
	}
	for k, v := range src {
		dst[k] = v
	}
	return dst
}

// Just like MapCombine but keep the original dst value if there is an overlap.
func MapAdd(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(dst) == 0 {
		return MapCopy(src)
	}
	if len(src) == 0 {
		return dst
	}
	for k, v := range src {
		if _, exist := dst[k]; !exist {
			dst[k] = v
		}
	}
	return dst
}

// MapReplace replaces the values in dst with the ones in src with the matching keys.
func MapReplace(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(src) == 0 {
		return dst
	}
	for k := range dst {
		if v, ok := src[k]; ok {
			dst[k] = v
		}
	}
	return dst
}

func MapEquals(big map[string]interface{}, small map[string]interface{}, strict bool) bool {
	if strict && len(big) != len(small) {
		return false
	}
	for k, v := range small {
		if big[k] != v && fmt.Sprint(big[k]) != fmt.Sprint(v) && !TimeCompare(big[k], v) {
			fmt.Printf("key %v: %v %v mismatch", k, big[k], v)
			return false
		}
	}
	return true
}

func MapCopy(src map[string]interface{}) map[string]interface{} {
	if len(src) == 0 {
		return nil
	}
	dst := make(map[string]interface{})
	for k, v := range src {
		if m, ok := v.(map[string]interface{}); ok {
			v = MapCopy(m)
		}
		if a, ok := v.([]interface{}); ok {
			v = ArrayCopy(a)
		}
		dst[k] = v
	}
	return dst
}

func ArrayCopy(src []interface{}) (dst []interface{}) {
	if len(src) == 0 {
		return nil
	}
	for _, v := range src {
		if m, ok := v.(map[string]interface{}); ok {
			v = MapCopy(m)
		}
		if a, ok := v.([]interface{}); ok {
			v = ArrayCopy(a)
		}
		dst = append(dst, v)
	}
	return dst
}

func InterfacePrint(m interface{}, prefix string) {
	jsonBytes, _ := json.Marshal(m)
	Logger.Printf("%s%s", prefix, string(jsonBytes))
}

// InterfaceToArray converts interface type to []map[string]interface{}.
func InterfaceToArray(obj interface{}) []map[string]interface{} {
	var objarray []map[string]interface{}
	if a, ok := obj.([]interface{}); ok {
		if len(a) > 0 {
			if _, ok := a[0].(map[string]interface{}); ok {
				objarray = obj.([]map[string]interface{})
			}
		}
	} else if o, ok := obj.(map[string]interface{}); ok {
		objarray = []map[string]interface{}{o}
	}
	return objarray
}

func MarshalJsonIndentNoEscape(i interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	enc.SetEscapeHTML(false)
	enc.SetIndent("", "    ")
	err := enc.Encode(i)
	if err != nil {
		return nil, err
	}
	result := buf.String()
	result = strings.Replace(result, "\\u003c", "<", -1)
	result = strings.Replace(result, "\\u003e", ">", -1)

	return []byte(result), nil
}

// Given a yaml stream, output a json stream.
func YamlToJson(in []byte) (json.RawMessage, error) {
	var unmarshaled interface{}
	err := yaml.Unmarshal(in, &unmarshaled)
	if err != nil {
		return nil, err
	}
	return swag.YAMLToJSON(unmarshaled)
}

func JsonToYaml(in []byte) ([]byte, error) {
	var out interface{}
	err := json.Unmarshal(in, &out)
	if err != nil {
		return nil, err
	}
	return yaml.Marshal(out)
}

func YamlObjToJsonObj(in interface{}) (interface{}, error) {
	jsonRaw, err := swag.YAMLToJSON(in)
	if err != nil {
		return nil, err
	}
	var out interface{}
	err = json.Unmarshal(jsonRaw, &out)
	if err != nil {
		return nil, err
	}
	return out, nil
}
<commit_msg>Minor fix.<commit_after>package mqutil

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

	"github.com/go-openapi/swag"
	"gopkg.in/yaml.v2"
)

// MapInterfaceToMapString converts the params map (all primitive types with exception of array)
// before passing to resty.
func MapInterfaceToMapString(src map[string]interface{}) map[string]string {
	dst := make(map[string]string)
	for k, v := range src {
		if ar, ok := v.([]interface{}); ok {
			str := ""
			for _, entry := range ar {
				str += fmt.Sprintf("%v,", entry)
			}
			str = strings.TrimRight(str, ",")
			dst[k] = str
		} else {
			dst[k] = fmt.Sprint(v)
		}
	}
	return dst
}

// MapIsCompatible checks if the first map has every key in the second.
func MapIsCompatible(big map[string]interface{}, small map[string]interface{}) bool {
	for k, _ := range small {
		if _, ok := big[k]; !ok {
			return false
		}
	}
	return true
}

func TimeCompare(v1 interface{}, v2 interface{}) bool {
	s1, ok := v1.(string)
	if !ok {
		return false
	}
	s2, ok := v2.(string)
	if !ok {
		return false
	}
	var t time.Time
	var s string
	var b1, b2 bool
	t1, err := time.Parse(time.RFC3339, s1)
	if err == nil {
		t = t1
		s = s2
		b1 = true
	}
	t2, err := time.Parse(time.RFC3339, s2)
	if err == nil {
		t = t2
		s = s1
		b2 = true
	}
	if b1 && b2 {
		return t1 == t2
	}
	if !b1 && !b2 {
		return false
	}
	// One of b1 and b2 is true, now t point to time and s point to a potential time string
	// that's not RFC3339 format. We make a guess buy searching for a few key elements.
	return strings.Contains(s, fmt.Sprintf("%d", t.Second())) && strings.Contains(s, fmt.Sprintf("%d", t.Minute()))
}

// MapCombine combines two map together. If there is any overlap the dst will be overwritten.
func MapCombine(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(dst) == 0 {
		return MapCopy(src)
	}
	if len(src) == 0 {
		return dst
	}
	for k, v := range src {
		dst[k] = v
	}
	return dst
}

// Just like MapCombine but keep the original dst value if there is an overlap.
func MapAdd(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(dst) == 0 {
		return MapCopy(src)
	}
	if len(src) == 0 {
		return dst
	}
	for k, v := range src {
		if _, exist := dst[k]; !exist {
			dst[k] = v
		}
	}
	return dst
}

// MapReplace replaces the values in dst with the ones in src with the matching keys.
func MapReplace(dst map[string]interface{}, src map[string]interface{}) map[string]interface{} {
	if len(src) == 0 {
		return dst
	}
	for k := range dst {
		if v, ok := src[k]; ok {
			dst[k] = v
		}
	}
	return dst
}

func MapEquals(big map[string]interface{}, small map[string]interface{}, strict bool) bool {
	if strict && len(big) != len(small) {
		return false
	}
	for k, v := range small {
		vType := reflect.TypeOf(v)
		if reflect.TypeOf(big[k]) == vType && vType.Comparable() && big[k] == v {
			continue
		}
		bJson, _ := json.Marshal(big[k])
		vJson, _ := json.Marshal(v)
		if string(bJson) != string(vJson) && !TimeCompare(big[k], v) {
			fmt.Printf("key %v: %v %v mismatch", k, big[k], v)
			return false
		}
	}
	return true
}

func MapCopy(src map[string]interface{}) map[string]interface{} {
	if len(src) == 0 {
		return nil
	}
	dst := make(map[string]interface{})
	for k, v := range src {
		if m, ok := v.(map[string]interface{}); ok {
			v = MapCopy(m)
		}
		if a, ok := v.([]interface{}); ok {
			v = ArrayCopy(a)
		}
		dst[k] = v
	}
	return dst
}

func ArrayCopy(src []interface{}) (dst []interface{}) {
	if len(src) == 0 {
		return nil
	}
	for _, v := range src {
		if m, ok := v.(map[string]interface{}); ok {
			v = MapCopy(m)
		}
		if a, ok := v.([]interface{}); ok {
			v = ArrayCopy(a)
		}
		dst = append(dst, v)
	}
	return dst
}

func InterfacePrint(m interface{}, prefix string) {
	jsonBytes, _ := json.Marshal(m)
	Logger.Printf("%s%s", prefix, string(jsonBytes))
}

// InterfaceToArray converts interface type to []map[string]interface{}.
func InterfaceToArray(obj interface{}) []map[string]interface{} {
	var objarray []map[string]interface{}
	if a, ok := obj.([]interface{}); ok {
		if len(a) > 0 {
			if _, ok := a[0].(map[string]interface{}); ok {
				objarray = obj.([]map[string]interface{})
			}
		}
	} else if o, ok := obj.(map[string]interface{}); ok {
		objarray = []map[string]interface{}{o}
	}
	return objarray
}

func MarshalJsonIndentNoEscape(i interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := json.NewEncoder(buf)
	enc.SetEscapeHTML(false)
	enc.SetIndent("", "    ")
	err := enc.Encode(i)
	if err != nil {
		return nil, err
	}
	result := buf.String()
	result = strings.Replace(result, "\\u003c", "<", -1)
	result = strings.Replace(result, "\\u003e", ">", -1)

	return []byte(result), nil
}

// Given a yaml stream, output a json stream.
func YamlToJson(in []byte) (json.RawMessage, error) {
	var unmarshaled interface{}
	err := yaml.Unmarshal(in, &unmarshaled)
	if err != nil {
		return nil, err
	}
	return swag.YAMLToJSON(unmarshaled)
}

func JsonToYaml(in []byte) ([]byte, error) {
	var out interface{}
	err := json.Unmarshal(in, &out)
	if err != nil {
		return nil, err
	}
	return yaml.Marshal(out)
}

func YamlObjToJsonObj(in interface{}) (interface{}, error) {
	jsonRaw, err := swag.YAMLToJSON(in)
	if err != nil {
		return nil, err
	}
	var out interface{}
	err = json.Unmarshal(jsonRaw, &out)
	if err != nil {
		return nil, err
	}
	return out, nil
}
<|endoftext|>