<commit_before>package veneur

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/url"
	"sync"

	"github.com/Sirupsen/logrus"
)

// ResolveAddr takes a URL-style listen address specification,
// resolves it and returns a net.Addr that corresponds to the
// string. If any error (in URL decoding, destructuring or resolving)
// occurs, ResolveAddr returns the respective error.
//
// Valid address examples are:
//   udp6://127.0.0.1:8000
//   unix:///tmp/foo.sock
//   tcp://127.0.0.1:9002
func ResolveAddr(str string) (net.Addr, error) {
	u, err := url.Parse(str)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "unix", "unixgram", "unixpacket":
		addr, err := net.ResolveUnixAddr(u.Scheme, u.Path)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "tcp6", "tcp4", "tcp":
		addr, err := net.ResolveTCPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "udp6", "udp4", "udp":
		addr, err := net.ResolveUDPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	}
	return nil, fmt.Errorf("unknown address family %q on address %q", u.Scheme, u.String())
}

// StartStatsd spawns a goroutine that listens for metrics in statsd
// format on the address a. As this is a setup routine, if any error
// occurs, it panics.
func StartStatsd(s *Server, a net.Addr, packetPool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startStatsdUDP(s, addr, packetPool)
	case *net.TCPAddr:
		startStatsdTCP(s, addr, packetPool)
	default:
		panic(fmt.Sprintf("Can't listen on %v: only TCP and UDP are supported", a))
	}
}

func startStatsdUDP(s *Server, addr *net.UDPAddr, packetPool *sync.Pool) {
	for i := 0; i < s.numReaders; i++ {
		go func() {
			defer func() {
				ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
			}()
			// each goroutine gets its own socket
			// if the sockets support SO_REUSEPORT, then this will cause the
			// kernel to distribute datagrams across them, for better read
			// performance
			sock, err := NewSocket(addr, s.RcvbufBytes, s.numReaders != 1)
			if err != nil {
				// if any goroutine fails to create the socket, we can't really
				// recover, so we just blow up
				// this probably indicates a systemic issue, eg lack of
				// SO_REUSEPORT support
				panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
			}
			log.WithField("address", addr).Info("Listening for statsd metrics on UDP socket")
			s.ReadMetricSocket(sock, packetPool)
		}()
	}
}

func startStatsdTCP(s *Server, addr *net.TCPAddr, packetPool *sync.Pool) {
	var listener net.Listener
	var err error

	listener, err = net.ListenTCP("tcp", addr)
	if err != nil {
		panic(fmt.Sprintf("couldn't listen on TCP socket %v: %v", addr, err))
	}

	go func() {
		<-s.shutdown
		// TODO: the socket is in use until there are no goroutines blocked in Accept
		// we should wait until the accepting goroutine exits
		err := listener.Close()
		if err != nil {
			log.WithError(err).Warn("Ignoring error closing TCP listener")
		}
	}()

	mode := "unencrypted"
	if s.tlsConfig != nil {
		// wrap the listener with TLS
		listener = tls.NewListener(listener, s.tlsConfig)
		if s.tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
			mode = "authenticated"
		} else {
			mode = "encrypted"
		}
	}

	log.WithFields(logrus.Fields{
		"address": addr, "mode": mode,
	}).Info("Listening for statsd metrics on TCP socket")

	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadTCPSocket(listener)
	}()
}

func StartSSF(s *Server, a net.Addr, tracePool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startSSFUDP(s, addr, tracePool)
	case *net.UnixAddr:
		startSSFUnix(s, addr)
	default:
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// & unix:// are supported", a))
	}
	log.WithFields(logrus.Fields{
		"address": a.String(),
		"network": a.Network(),
	}).Info("Listening for SSF traces")
}

func startSSFUDP(s *Server, addr *net.UDPAddr, tracePool *sync.Pool) {
	// if we want to use multiple readers, make reuseport a parameter, like ReadMetricSocket.
	listener, err := NewSocket(addr, s.RcvbufBytes, false)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
	}
	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadSSFPacketSocket(listener, tracePool)
	}()
}

func startSSFUnix(s *Server, addr *net.UnixAddr) <-chan struct{} {
	done := make(chan struct{})
	if addr.Network() != "unix" {
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// and unix:// addresses are supported", addr))
	}
	listener, err := net.ListenUnix(addr.Network(), addr)
	if err != nil {
		panic(fmt.Sprintf("Couldn't listen on UNIX socket %v: %v", addr, err))
	}
	go func() {
		for {
			conn, err := listener.AcceptUnix()
			if err != nil {
				select {
				case <-s.shutdown:
					// occurs when cleanly shutting down the server e.g. in tests; ignore errors
					log.WithError(err).Info("Ignoring Accept error while shutting down")
					close(done)
					return
				default:
					log.WithError(err).Fatal("Unix accept failed")
				}
			}
			go s.ReadSSFStreamSocket(conn)
		}
	}()
	return done
}
<commit_msg>flock a lockfile next to UNIX domain sockets<commit_after>package veneur

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/url"
	"os"
	"sync"

	"github.com/Sirupsen/logrus"
	flock "github.com/theckman/go-flock"
)

// ResolveAddr takes a URL-style listen address specification,
// resolves it and returns a net.Addr that corresponds to the
// string. If any error (in URL decoding, destructuring or resolving)
// occurs, ResolveAddr returns the respective error.
//
// Valid address examples are:
//   udp6://127.0.0.1:8000
//   unix:///tmp/foo.sock
//   tcp://127.0.0.1:9002
func ResolveAddr(str string) (net.Addr, error) {
	u, err := url.Parse(str)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "unix", "unixgram", "unixpacket":
		addr, err := net.ResolveUnixAddr(u.Scheme, u.Path)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "tcp6", "tcp4", "tcp":
		addr, err := net.ResolveTCPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "udp6", "udp4", "udp":
		addr, err := net.ResolveUDPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	}
	return nil, fmt.Errorf("unknown address family %q on address %q", u.Scheme, u.String())
}

// StartStatsd spawns a goroutine that listens for metrics in statsd
// format on the address a. As this is a setup routine, if any error
// occurs, it panics.
func StartStatsd(s *Server, a net.Addr, packetPool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startStatsdUDP(s, addr, packetPool)
	case *net.TCPAddr:
		startStatsdTCP(s, addr, packetPool)
	default:
		panic(fmt.Sprintf("Can't listen on %v: only TCP and UDP are supported", a))
	}
}

func startStatsdUDP(s *Server, addr *net.UDPAddr, packetPool *sync.Pool) {
	for i := 0; i < s.numReaders; i++ {
		go func() {
			defer func() {
				ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
			}()
			// each goroutine gets its own socket
			// if the sockets support SO_REUSEPORT, then this will cause the
			// kernel to distribute datagrams across them, for better read
			// performance
			sock, err := NewSocket(addr, s.RcvbufBytes, s.numReaders != 1)
			if err != nil {
				// if any goroutine fails to create the socket, we can't really
				// recover, so we just blow up
				// this probably indicates a systemic issue, eg lack of
				// SO_REUSEPORT support
				panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
			}
			log.WithField("address", addr).Info("Listening for statsd metrics on UDP socket")
			s.ReadMetricSocket(sock, packetPool)
		}()
	}
}

func startStatsdTCP(s *Server, addr *net.TCPAddr, packetPool *sync.Pool) {
	var listener net.Listener
	var err error

	listener, err = net.ListenTCP("tcp", addr)
	if err != nil {
		panic(fmt.Sprintf("couldn't listen on TCP socket %v: %v", addr, err))
	}

	go func() {
		<-s.shutdown
		// TODO: the socket is in use until there are no goroutines blocked in Accept
		// we should wait until the accepting goroutine exits
		err := listener.Close()
		if err != nil {
			log.WithError(err).Warn("Ignoring error closing TCP listener")
		}
	}()

	mode := "unencrypted"
	if s.tlsConfig != nil {
		// wrap the listener with TLS
		listener = tls.NewListener(listener, s.tlsConfig)
		if s.tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
			mode = "authenticated"
		} else {
			mode = "encrypted"
		}
	}

	log.WithFields(logrus.Fields{
		"address": addr, "mode": mode,
	}).Info("Listening for statsd metrics on TCP socket")

	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadTCPSocket(listener)
	}()
}

func StartSSF(s *Server, a net.Addr, tracePool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startSSFUDP(s, addr, tracePool)
	case *net.UnixAddr:
		startSSFUnix(s, addr)
	default:
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// & unix:// are supported", a))
	}
	log.WithFields(logrus.Fields{
		"address": a.String(),
		"network": a.Network(),
	}).Info("Listening for SSF traces")
}

func startSSFUDP(s *Server, addr *net.UDPAddr, tracePool *sync.Pool) {
	// if we want to use multiple readers, make reuseport a parameter, like ReadMetricSocket.
	listener, err := NewSocket(addr, s.RcvbufBytes, false)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
	}
	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadSSFPacketSocket(listener, tracePool)
	}()
}

func startSSFUnix(s *Server, addr *net.UnixAddr) <-chan struct{} {
	done := make(chan struct{})
	if addr.Network() != "unix" {
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// and unix:// addresses are supported", addr))
	}
	// ensure we are the only ones locking this socket:
	lockname := fmt.Sprintf("%s.lock", addr.String())
	lock := flock.NewFlock(lockname)
	locked, err := lock.TryLock()
	if err != nil {
		panic(fmt.Sprintf("Could not acquire the lock %q to listen on %v: %v", lockname, addr, err))
	}
	if !locked {
		panic(fmt.Sprintf("Lock file %q for %v is in use by another process already", lockname, addr))
	}
	// We have the exclusive use of the socket, clear away any old sockets and listen:
	_ = os.Remove(addr.String())
	listener, err := net.ListenUnix(addr.Network(), addr)
	if err != nil {
		panic(fmt.Sprintf("Couldn't listen on UNIX socket %v: %v", addr, err))
	}
	go func() {
		conns := make(chan net.Conn)
		go func() {
			defer lock.Unlock()
			defer close(done)

			conn, err := listener.AcceptUnix()
			if err != nil {
				select {
				case <-s.shutdown:
					// occurs when cleanly shutting down the server e.g. in tests; ignore errors
					log.WithError(err).Info("Ignoring Accept error while shutting down")
					return
				default:
					log.WithError(err).Fatal("Unix accept failed")
				}
			}
			conns <- conn
		}()
		for {
			select {
			case conn := <-conns:
				go s.ReadSSFStreamSocket(conn)
			case <-s.shutdown:
				listener.Close()
				return
			}
		}
	}()
	return done
}
<|endoftext|>


<commit_before>//lint_ext_ian_uri_not_ia5_test.go
package lints

import (

	"testing"
)

func TestIanUriIA5(t *testing.T) {
	inputPath := "../testlint/testCerts/ianURIIa5.cer"
	desEnum := Pass
	out, _ := Lints["ext_ian_uri_not_ia5"].ExecuteTest(ReadCertificate(inputPath))
	if out.Result != desEnum {
		t.Error(
			"For", inputPath, /* input path*/
			"expected", desEnum, /* The enum you expected */
			"got", out.Result, /* Actual Result */
		)
	}
}

func TestIanUriNotIA5(t *testing.T) {
	inputPath := "../testlint/testCerts/ianURINotIA5.cer"
	desEnum := Error
	out, _ := Lints["ext_ian_uri_not_ia5"].ExecuteTest(ReadCertificate(inputPath))
	if out.Result != desEnum {
		t.Error(
			"For", inputPath, /* input path*/
			"expected", desEnum, /* The enum you expected */
			"got", out.Result, /* Actual Result */
		)
	}
}
<commit_msg>casing issue fix<commit_after>//lint_ext_ian_uri_not_ia5_test.go
package lints

import (
	"testing"
)

func TestIanUriIA5(t *testing.T) {
	inputPath := "../testlint/testCerts/ianURIIA5.cer"
	desEnum := Pass
	out, _ := Lints["ext_ian_uri_not_ia5"].ExecuteTest(ReadCertificate(inputPath))
	if out.Result != desEnum {
		t.Error(
			"For", inputPath, /* input path*/
			"expected", desEnum, /* The enum you expected */
			"got", out.Result, /* Actual Result */
		)
	}
}

func TestIanUriNotIA5(t *testing.T) {
	inputPath := "../testlint/testCerts/ianURINotIA5.cer"
	desEnum := Error
	out, _ := Lints["ext_ian_uri_not_ia5"].ExecuteTest(ReadCertificate(inputPath))
	if out.Result != desEnum {
		t.Error(
			"For", inputPath, /* input path*/
			"expected", desEnum, /* The enum you expected */
			"got", out.Result, /* Actual Result */
		)
	}
}
<|endoftext|>


<commit_before>package drivers

// FilterIPv6All used to indicate to firewall package to filter all IPv6 traffic.
const FilterIPv6All = "::"

// FilterIPv4All used to indicate to firewall package to filter all IPv4 traffic.
const FilterIPv4All = "0.0.0.0"
<commit_msg>lxd/firewall/drivers/driver/consts: Add network firewall Opts<commit_after>package drivers

import "net"

// FilterIPv6All used to indicate to firewall package to filter all IPv6 traffic.
const FilterIPv6All = "::"

// FilterIPv4All used to indicate to firewall package to filter all IPv4 traffic.
const FilterIPv4All = "0.0.0.0"

// FeatureOpts specify how firewall features are setup.
type FeatureOpts struct {
	DHCPDNSAccess   bool // Add rules to allow DHCP and DNS access.
	ForwardingAllow bool // Add rules to allow IP forwarding. Blocked if false.
}

// SNATOpts specify how SNAT rules are setup.
type SNATOpts struct {
	Append      bool       // Append rules (has no effect if driver doesn't support it).
	Subnet      *net.IPNet // Subnet of source network used to identify candidate traffic.
	SNATAddress net.IP     // SNAT IP address to use. If nil then MASQUERADE is used.
}

// Opts for setting up the firewall.
type Opts struct {
	FeaturesV4 *FeatureOpts // Enable IPv4 firewall with specified options. Off if not provided.
	FeaturesV6 *FeatureOpts // Enable IPv6 firewall with specified options. Off if not provided.
	SNATV4     *SNATOpts    // Enable IPv4 SNAT with specified options. Off if not provided.
	SNATV6     *SNATOpts    // Enable IPv6 SNAT with specified options. Off if not provided.
}
<|endoftext|>


<commit_before>package mpsidekiq

import (
	"flag"
	"fmt"
	"strconv"

	r "github.com/go-redis/redis"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

// SidekiqPlugin for fetching metrics
type SidekiqPlugin struct {
	Tempfile string
	client   *r.Client
}

var graphdef = map[string]mp.Graphs{
	"Sidekiq.ProcessedANDFailed": mp.Graphs{
		Label: "Sidekiq processed and failed count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "processed", Label: "Processed", Type: "uint64", Diff: true},
			{Name: "failed", Label: "Failed", Type: "uint64", Diff: true},
		},
	},
	"Sidekiq.Stats": mp.Graphs{
		Label: "Sidekiq stats",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "busy", Label: "Busy", Type: "uint64"},
			{Name: "enqueued", Label: "Enqueued", Type: "uint64"},
			{Name: "schedule", Label: "Schedule", Type: "uint64"},
			{Name: "retry", Label: "Retry", Type: "uint64"},
			{Name: "dead", Label: "Dead", Type: "uint64"},
		},
	},
}

// GraphDefinition Graph definition
func (sp SidekiqPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

func (sp SidekiqPlugin) get(key string) uint64 {
	val, err := sp.client.Get(key).Result()
	if err == r.Nil {
		return 0
	}

	r, _ := strconv.ParseUint(val, 10, 64)
	return r
}

func (sp SidekiqPlugin) zCard(key string) uint64 {
	val, err := sp.client.ZCard(key).Result()
	if err == r.Nil {
		return 0
	}

	return uint64(val)
}

func (sp SidekiqPlugin) sMembers(key string) []string {
	val, err := sp.client.SMembers(key).Result()
	if err == r.Nil {
		return make([]string, 0)
	}

	return val
}

func (sp SidekiqPlugin) hGet(key string, field string) uint64 {
	val, err := sp.client.HGet(key, field).Result()
	if err == r.Nil {
		return 0
	}

	r, _ := strconv.ParseUint(val, 10, 64)
	return r
}

func (sp SidekiqPlugin) lLen(key string) uint64 {
	val, err := sp.client.LLen(key).Result()
	if err == r.Nil {
		return 0
	}

	return uint64(val)
}

func (sp SidekiqPlugin) getProcessed() uint64 {
	return sp.get("stat:processed")
}

func (sp SidekiqPlugin) getFailed() uint64 {
	return sp.get("stat:failed")
}

func inject(slice []uint64, base uint64) uint64 {
	for _, e := range slice {
		base += uint64(e)
	}

	return base
}

func (sp SidekiqPlugin) getBusy() uint64 {
	processes := sp.sMembers("processes")
	busies := make([]uint64, 10)
	for _, e := range processes {
		busies = append(busies, sp.hGet(e, "busy"))
	}

	return inject(busies, 0)
}

func (sp SidekiqPlugin) getEnqueued() uint64 {
	queues := sp.sMembers("queues")
	queuesLlens := make([]uint64, 10)

	for _, e := range queues {
		queuesLlens = append(queuesLlens, sp.lLen("queue:"+e))
	}

	return inject(queuesLlens, 0)
}

func (sp SidekiqPlugin) getSchedule() uint64 {
	return sp.zCard("schedule")
}

func (sp SidekiqPlugin) getRetry() uint64 {
	return sp.zCard("retry")
}

func (sp SidekiqPlugin) getDead() uint64 {
	return sp.zCard("dead")
}

func (sp SidekiqPlugin) getProcessedFailed() map[string]interface{} {
	data := make(map[string]interface{}, 20)

	data["processed"] = sp.getProcessed()
	data["failed"] = sp.getFailed()

	return data
}

func (sp SidekiqPlugin) getStats(field []string) map[string]interface{} {
	stats := make(map[string]interface{}, 20)
	for _, e := range field {
		switch e {
		case "busy":
			stats[e] = sp.getBusy()
		case "enqueued":
			stats[e] = sp.getEnqueued()
		case "schedule":
			stats[e] = sp.getSchedule()
		case "retry":
			stats[e] = sp.getRetry()
		case "dead":
			stats[e] = sp.getDead()
		}
	}

	return stats
}

// FetchMetrics fetch the metrics
func (sp SidekiqPlugin) FetchMetrics() (map[string]interface{}, error) {
	field := []string{"busy", "enqueued", "schedule", "retry", "dead"}
	stats := sp.getStats(field)
	pf := sp.getProcessedFailed()

	// merge maps
	m := func(map1 map[string]interface{}, map2 map[string]interface{}) map[string]interface{} {
		for k, v := range map2 {
			map1[k] = v
		}

		return map1
	}(stats, pf)

	return m, nil
}

// Do the plugin
func Do() {
	optHost := flag.String("host", "localhost", "Hostname")
	optPort := flag.String("port", "6379", "Port")
	optPassword := flag.String("password", "", "Password")
	optDB := flag.Int("db", 0, "DB")
	optTempfile := flag.String("tempfile", "/tmp/mackerel-plugin-sidekiq", "Temp file name")
	flag.Parse()

	client := r.NewClient(&r.Options{
		Addr:     fmt.Sprintf("%s:%s", *optHost, *optPort),
		Password: *optPassword, // no password set
		DB:       *optDB,       // use default DB
	})

	sp := SidekiqPlugin{client: client}
	helper := mp.NewMackerelPlugin(sp)
	helper.Tempfile = *optTempfile

	helper.Run()
}
<commit_msg>fix: - delete Tempfile - delete optTempfile default value - implement PluginWithPrefix interface<commit_after>package mpsidekiq

import (
	"flag"
	"fmt"
	"strconv"

	r "github.com/go-redis/redis"
	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

// SidekiqPlugin for fetching metrics
type SidekiqPlugin struct {
	Client *r.Client
	Prefix string
}

var graphdef = map[string]mp.Graphs{
	"ProcessedANDFailed": mp.Graphs{
		Label: "Sidekiq processed and failed count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "processed", Label: "Processed", Type: "uint64", Diff: true},
			{Name: "failed", Label: "Failed", Type: "uint64", Diff: true},
		},
	},
	"Stats": mp.Graphs{
		Label: "Sidekiq stats",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "busy", Label: "Busy", Type: "uint64"},
			{Name: "enqueued", Label: "Enqueued", Type: "uint64"},
			{Name: "schedule", Label: "Schedule", Type: "uint64"},
			{Name: "retry", Label: "Retry", Type: "uint64"},
			{Name: "dead", Label: "Dead", Type: "uint64"},
		},
	},
}

// GraphDefinition Graph definition
func (sp SidekiqPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

func (sp SidekiqPlugin) get(key string) uint64 {
	val, err := sp.Client.Get(key).Result()
	if err == r.Nil {
		return 0
	}

	r, _ := strconv.ParseUint(val, 10, 64)
	return r
}

func (sp SidekiqPlugin) zCard(key string) uint64 {
	val, err := sp.Client.ZCard(key).Result()
	if err == r.Nil {
		return 0
	}

	return uint64(val)
}

func (sp SidekiqPlugin) sMembers(key string) []string {
	val, err := sp.Client.SMembers(key).Result()
	if err == r.Nil {
		return make([]string, 0)
	}

	return val
}

func (sp SidekiqPlugin) hGet(key string, field string) uint64 {
	val, err := sp.Client.HGet(key, field).Result()
	if err == r.Nil {
		return 0
	}

	r, _ := strconv.ParseUint(val, 10, 64)
	return r
}

func (sp SidekiqPlugin) lLen(key string) uint64 {
	val, err := sp.Client.LLen(key).Result()
	if err == r.Nil {
		return 0
	}

	return uint64(val)
}

func (sp SidekiqPlugin) getProcessed() uint64 {
	return sp.get("stat:processed")
}

func (sp SidekiqPlugin) getFailed() uint64 {
	return sp.get("stat:failed")
}

func inject(slice []uint64, base uint64) uint64 {
	for _, e := range slice {
		base += uint64(e)
	}

	return base
}

func (sp SidekiqPlugin) getBusy() uint64 {
	processes := sp.sMembers("processes")
	busies := make([]uint64, 10)
	for _, e := range processes {
		busies = append(busies, sp.hGet(e, "busy"))
	}

	return inject(busies, 0)
}

func (sp SidekiqPlugin) getEnqueued() uint64 {
	queues := sp.sMembers("queues")
	queuesLlens := make([]uint64, 10)

	for _, e := range queues {
		queuesLlens = append(queuesLlens, sp.lLen("queue:"+e))
	}

	return inject(queuesLlens, 0)
}

func (sp SidekiqPlugin) getSchedule() uint64 {
	return sp.zCard("schedule")
}

func (sp SidekiqPlugin) getRetry() uint64 {
	return sp.zCard("retry")
}

func (sp SidekiqPlugin) getDead() uint64 {
	return sp.zCard("dead")
}

func (sp SidekiqPlugin) getProcessedFailed() map[string]interface{} {
	data := make(map[string]interface{}, 20)

	data["processed"] = sp.getProcessed()
	data["failed"] = sp.getFailed()

	return data
}

func (sp SidekiqPlugin) getStats(field []string) map[string]interface{} {
	stats := make(map[string]interface{}, 20)
	for _, e := range field {
		switch e {
		case "busy":
			stats[e] = sp.getBusy()
		case "enqueued":
			stats[e] = sp.getEnqueued()
		case "schedule":
			stats[e] = sp.getSchedule()
		case "retry":
			stats[e] = sp.getRetry()
		case "dead":
			stats[e] = sp.getDead()
		}
	}

	return stats
}

// FetchMetrics fetch the metrics
func (sp SidekiqPlugin) FetchMetrics() (map[string]interface{}, error) {
	field := []string{"busy", "enqueued", "schedule", "retry", "dead"}
	stats := sp.getStats(field)
	pf := sp.getProcessedFailed()

	// merge maps
	m := func(map1 map[string]interface{}, map2 map[string]interface{}) map[string]interface{} {
		for k, v := range map2 {
			map1[k] = v
		}

		return map1
	}(stats, pf)

	return m, nil
}

// MetricKeyPrefix interface for PluginWithPrefix
func (sp SidekiqPlugin) MetricKeyPrefix() string {
	if sp.Prefix == "" {
		sp.Prefix = "sidekiq"
	}
	return sp.Prefix
}

// Do the plugin
func Do() {
	optHost := flag.String("host", "localhost", "Hostname")
	optPort := flag.String("port", "6379", "Port")
	optPassword := flag.String("password", "", "Password")
	optDB := flag.Int("db", 0, "DB")
	optPrefix := flag.String("metric-key-prefix", "sidekiq", "Metric key prefix")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	client := r.NewClient(&r.Options{
		Addr:     fmt.Sprintf("%s:%s", *optHost, *optPort),
		Password: *optPassword,
		DB:       *optDB,
	})

	sp := SidekiqPlugin{
		Client: client,
		Prefix: *optPrefix,
	}
	helper := mp.NewMackerelPlugin(sp)
	helper.Tempfile = *optTempfile

	helper.Run()
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

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

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

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

*/

package com

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"sync"

	"github.com/admpub/fsnotify"
)

var (
	DefaultMonitor = NewMonitor()
	defaultEventFn = func(string) {}
)

func NewMonitor() *MonitorEvent {
	return &MonitorEvent{
		Create:  defaultEventFn,
		Delete:  defaultEventFn,
		Modify:  defaultEventFn,
		Chmod:   defaultEventFn,
		Rename:  defaultEventFn,
		filters: []func(string) bool{},
	}
}

//MonitorEvent 监控事件函数
type MonitorEvent struct {
	//文件事件
	Create func(string) //创建
	Delete func(string) //删除（包含文件夹和文件。因为已经删除，无法确定是文件夹还是文件）
	Modify func(string) //修改（包含修改权限。如果是文件夹，则内部的文件被更改也会触发此事件）
	Chmod  func(string) //修改权限（windows不支持）
	Rename func(string) //重命名

	//其它
	Channel chan bool //管道
	Debug   bool
	lock    *sync.Once
	watcher *fsnotify.Watcher
	filters []func(string) bool
}

func (m *MonitorEvent) AddFilter(args ...func(string) bool) {
	if m.filters == nil {
		m.filters = []func(string) bool{}
	}
	m.filters = append(m.filters, args...)
}

func (m *MonitorEvent) SetFilters(args ...func(string) bool) {
	m.filters = args
}

func (m *MonitorEvent) Watch(args ...func(string) bool) {
	m.SetFilters(args...)
	go func() {
		m.backendListen()
		<-m.Channel
	}()
}

func (m *MonitorEvent) Close() error {
	if m.Channel != nil {
		close(m.Channel)
	}
	if m.watcher != nil {
		return m.watcher.Close()
	}
	return nil
}

func (m *MonitorEvent) Watcher() *fsnotify.Watcher {
	if m.watcher == nil {
		var err error
		m.watcher, err = fsnotify.NewWatcher()
		m.lock = &sync.Once{}
		m.Channel = make(chan bool)
		m.filters = []func(string) bool{}
		if err != nil {
			log.Panic(err)
		}
	}
	return m.watcher
}

func (m *MonitorEvent) backendListen() {
	go m.listen()
}

func (m *MonitorEvent) AddDir(dir string) error {
	f, err := os.Stat(dir)
	if err != nil {
		return err
	}
	if !f.IsDir() {
		return errors.New(dir + ` is not dir.`)
	}
	err = filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if m.Debug {
				log.Println(`[Monitor]`, `Add Watch:`, f)
			}
			return m.Watcher().Add(f)
		}
		return nil
	})
	return err
}

func (m *MonitorEvent) AddFile(file string) error {
	return m.Watcher().Add(file)
}

func (m *MonitorEvent) Remove(fileOrDir string) error {
	if m.watcher != nil {
		return m.watcher.Remove(fileOrDir)
	}
	return nil
}

func (m *MonitorEvent) listen() {
	for {
		watcher := m.Watcher()
		select {
		case ev := <-watcher.Events:
			if m.Debug {
				log.Println(`[Monitor]`, `Trigger Event:`, ev)
			}
			if m.filters != nil {
				var skip bool
				for _, filter := range m.filters {
					if !filter(ev.Name) {
						skip = true
						break
					}
				}
				if skip {
					break
				}
			}
			m.lock.Do(func() {
				switch ev.Op {
				case fsnotify.Create:
					if m.IsDir(ev.Name) {
						watcher.Add(ev.Name)
					}
					if m.Create != nil {
						m.Create(ev.Name)
					}
				case fsnotify.Remove:
					if m.Delete != nil {
						m.Delete(ev.Name)
					}
				case fsnotify.Write:
					if m.Modify != nil {
						m.Modify(ev.Name)
					}
				case fsnotify.Rename:
					if m.Rename != nil {
						m.Rename(ev.Name)
					}
				case fsnotify.Chmod:
					if m.Chmod != nil {
						m.Chmod(ev.Name)
					}
				}
				m.lock = &sync.Once{}
			})
		case err := <-watcher.Errors:
			if err != nil {
				log.Println("Watcher error:", err)
			}
		}
	}
}

func (m *MonitorEvent) IsDir(path string) bool {
	d, e := os.Stat(path)
	if e != nil {
		return false
	}
	return d.IsDir()
}

//Monitor 文件监测
func Monitor(rootDir string, callback *MonitorEvent, args ...func(string) bool) error {
	watcher := callback.Watcher()
	defer watcher.Close()
	callback.Watch(args...)
	err := callback.AddDir(rootDir)
	if err != nil {
		callback.Close()
		return err
	}
	return nil
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

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

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

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

*/

package com

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"sync"

	"github.com/admpub/fsnotify"
)

var (
	DefaultMonitor      = NewMonitor()
	MonitorEventEmptyFn = func(string) {}
)

func NewMonitor() *MonitorEvent {
	return &MonitorEvent{
		Create:  MonitorEventEmptyFn,
		Delete:  MonitorEventEmptyFn,
		Modify:  MonitorEventEmptyFn,
		Chmod:   MonitorEventEmptyFn,
		Rename:  MonitorEventEmptyFn,
		filters: []func(string) bool{},
	}
}

//MonitorEvent 监控事件函数
type MonitorEvent struct {
	//文件事件
	Create func(string) //创建
	Delete func(string) //删除（包含文件夹和文件。因为已经删除，无法确定是文件夹还是文件）
	Modify func(string) //修改（包含修改权限。如果是文件夹，则内部的文件被更改也会触发此事件）
	Chmod  func(string) //修改权限（windows不支持）
	Rename func(string) //重命名

	//其它
	Channel chan bool //管道
	Debug   bool
	lock    *sync.Once
	watcher *fsnotify.Watcher
	filters []func(string) bool
}

func (m *MonitorEvent) AddFilter(args ...func(string) bool) {
	if m.filters == nil {
		m.filters = []func(string) bool{}
	}
	m.filters = append(m.filters, args...)
}

func (m *MonitorEvent) SetFilters(args ...func(string) bool) {
	m.filters = args
}

func (m *MonitorEvent) Watch(args ...func(string) bool) {
	m.SetFilters(args...)
	go func() {
		m.backendListen()
		<-m.Channel
	}()
}

func (m *MonitorEvent) Close() error {
	if m.Channel != nil {
		close(m.Channel)
	}
	if m.watcher != nil {
		return m.watcher.Close()
	}
	return nil
}

func (m *MonitorEvent) Watcher() *fsnotify.Watcher {
	if m.watcher == nil {
		var err error
		m.watcher, err = fsnotify.NewWatcher()
		m.lock = &sync.Once{}
		m.Channel = make(chan bool)
		m.filters = []func(string) bool{}
		if err != nil {
			log.Panic(err)
		}
	}
	return m.watcher
}

func (m *MonitorEvent) backendListen() {
	go m.listen()
}

func (m *MonitorEvent) AddDir(dir string) error {
	f, err := os.Stat(dir)
	if err != nil {
		return err
	}
	if !f.IsDir() {
		return errors.New(dir + ` is not dir.`)
	}
	err = filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if m.Debug {
				log.Println(`[Monitor]`, `Add Watch:`, f)
			}
			return m.Watcher().Add(f)
		}
		return nil
	})
	return err
}

func (m *MonitorEvent) AddFile(file string) error {
	return m.Watcher().Add(file)
}

func (m *MonitorEvent) Remove(fileOrDir string) error {
	if m.watcher != nil {
		return m.watcher.Remove(fileOrDir)
	}
	return nil
}

func (m *MonitorEvent) listen() {
	for {
		watcher := m.Watcher()
		select {
		case ev := <-watcher.Events:
			if m.Debug {
				log.Println(`[Monitor]`, `Trigger Event:`, ev)
			}
			if m.filters != nil {
				var skip bool
				for _, filter := range m.filters {
					if !filter(ev.Name) {
						skip = true
						break
					}
				}
				if skip {
					break
				}
			}
			m.lock.Do(func() {
				switch ev.Op {
				case fsnotify.Create:
					if m.IsDir(ev.Name) {
						watcher.Add(ev.Name)
					}
					if m.Create != nil {
						m.Create(ev.Name)
					}
				case fsnotify.Remove:
					if m.Delete != nil {
						m.Delete(ev.Name)
					}
				case fsnotify.Write:
					if m.Modify != nil {
						m.Modify(ev.Name)
					}
				case fsnotify.Rename:
					if m.Rename != nil {
						m.Rename(ev.Name)
					}
				case fsnotify.Chmod:
					if m.Chmod != nil {
						m.Chmod(ev.Name)
					}
				}
				m.lock = &sync.Once{}
			})
		case err := <-watcher.Errors:
			if err != nil {
				log.Println("Watcher error:", err)
			}
		}
	}
}

func (m *MonitorEvent) IsDir(path string) bool {
	d, e := os.Stat(path)
	if e != nil {
		return false
	}
	return d.IsDir()
}

//Monitor 文件监测
func Monitor(rootDir string, callback *MonitorEvent, args ...func(string) bool) error {
	watcher := callback.Watcher()
	defer watcher.Close()
	callback.Watch(args...)
	err := callback.AddDir(rootDir)
	if err != nil {
		callback.Close()
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package mux

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/yinghuocho/golibfq/utils"
)

const (
	SYN  = 0x1
	FIN  = 0x2
	RST  = 0x4
	DATA = 0x8

	maxDataLen = 65535
)

type muxFrame struct {
	sID     uint32
	flag    byte
	dataLen uint16
	data    []byte
}

type Session struct {
	isClient bool

	// atomic generation Id for new Streams
	genStreamID uint32

	wlock sync.Mutex
	conn  net.Conn
	quit  chan bool

	// mapLock protects operations on streams-map by Session.loop or someone
	// invokes Stream.Close, or Client.OpenStream
	//
	// Closed session has a nil map to prevent new streams by Client.OpenStream
	streams map[uint32]*Stream
	mapLock sync.Mutex

	// Used by Server to write new Streams to someone waiting on Server.Accept.
	streamCh chan *Stream

	// idle session will be closed
	idle time.Duration
}

type Client struct {
	s *Session
}

type Server struct {
	s *Session
}

// implement net.Conn interface
type Stream struct {
	id uint32

	// checked by Write to ensure first data from Client Stream has a SYN flag.
	synSent bool

	up    *utils.BytePipe
	upCur []byte

	readDeadline  time.Time
	writeDeadline time.Time

	quit     chan bool
	quitFlag uint32

	session *Session
}

var (
	framePool *sync.Pool = &sync.Pool{
		New: func() interface{} {
			return &muxFrame{}
		},
	}
)

func newFrame(sID uint32, flag byte, dataLen uint16, data []byte) *muxFrame {
	f := framePool.Get().(*muxFrame)
	f.sID = sID
	f.flag = flag
	f.dataLen = dataLen
	f.data = data
	return f
}

func releaseFrame(f *muxFrame) {
	f.data = nil
	framePool.Put(f)
}

func NewClient(c net.Conn) *Client {
	s := &Session{
		isClient: true,
		conn:     c,
		streams:  make(map[uint32]*Stream),
		quit:     make(chan bool),
		streamCh: make(chan *Stream),
	}
	go s.loop()
	return &Client{s: s}
}

func (c *Client) OpenStream() (*Stream, error) {
	id := atomic.AddUint32(&c.s.genStreamID, 1)
	return c.s.newStream(id)
}

func (c *Client) SetIdleTime(idle time.Duration) {
	c.s.idle = idle
}

func (c *Client) Close() error {
	return c.s.cloze()
}

func NewServer(c net.Conn) *Server {
	s := &Session{
		isClient: false,
		conn:     c,
		streams:  make(map[uint32]*Stream),
		quit:     make(chan bool),
		streamCh: make(chan *Stream),
	}
	go s.loop()
	return &Server{s: s}
}

func (s *Server) Accept() (*Stream, error) {
	stream, ok := <-s.s.streamCh
	if !ok {
		return nil, io.EOF
	}
	return stream, nil
}

func (s *Server) Close() error {
	return s.s.cloze()
}

func (s *Server) SetIdleTime(idle time.Duration) {
	s.s.idle = idle
}

func (s *Session) readFrame() (*muxFrame, error) {
	var buf [7]byte
	_, err := io.ReadFull(s.conn, buf[:])
	if err != nil {
		return nil, err
	}
	sID := binary.BigEndian.Uint32(buf[0:4])
	flag := buf[4]
	dataLen := binary.BigEndian.Uint16(buf[5:7])
	if dataLen > 0 {
		data := make([]byte, dataLen)
		_, err := io.ReadFull(s.conn, data[0:dataLen])
		if err != nil {
			return nil, err
		}
		return newFrame(sID, flag, dataLen, data), nil
	} else {
		return newFrame(sID, flag, dataLen, nil), nil
	}
}

func (s *Session) writeFrame(frame *muxFrame) error {
	s.wlock.Lock()
	defer s.wlock.Unlock()

	var buf [65535 + 8]byte
	binary.BigEndian.PutUint32(buf[0:], frame.sID)
	buf[4] = frame.flag
	binary.BigEndian.PutUint16(buf[5:], frame.dataLen)
	if frame.dataLen > 0 {
		copy(buf[7:], frame.data[0:frame.dataLen])
	}
	_, err := s.conn.Write(buf[0 : uint32(frame.dataLen)+7])
	return err
}

func (s *Session) getStream(sID uint32) *Stream {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	return s.streams[sID]
}

func (s *Session) newStream(sID uint32) (*Stream, error) {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	// Session already closed
	if s.streams == nil {
		return nil, io.EOF
	}
	stream := &Stream{
		id:      sID,
		up:      utils.NewBytePipe(fmt.Sprintf("%d-UP", sID), 0),
		quit:    make(chan bool),
		session: s,
	}

	s.streams[sID] = stream
	go stream.up.Start()
	return stream, nil
}

func (s *Session) clearStream(sID uint32) {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	delete(s.streams, sID)
}

func (s *Session) loop() {
	var pendingStream []*Stream

	readCh := make(chan *muxFrame)
	// reader
	go func() {
		for {
			f, err := s.readFrame()
			if err != nil {
				break
			}
			readCh <- f
		}
		s.cloze()
		close(s.quit)
		return
	}()

loop:
	for {
		var streamCh chan *Stream
		var curStream *Stream
		var timer *time.Timer
		var to <-chan time.Time

		if s.idle != 0 {
			timer = time.NewTimer(s.idle)
			to = timer.C
		}

		if !s.isClient && len(pendingStream) > 0 {
			streamCh = s.streamCh
			curStream = pendingStream[0]
		}

		select {
		case <-to:
			s.mapLock.Lock()
			for _, stream := range s.streams {
				stream.cloze()
			}
			s.streams = nil
			s.mapLock.Unlock()
			break loop
		case streamCh <- curStream:
			pendingStream = pendingStream[1:]
		case f := <-readCh:
			stream := s.getStream(f.sID)
			// SYN
			if (stream == nil) && (f.flag&SYN != 0) {
				stream, _ = s.newStream(f.sID)
				if !s.isClient {
					pendingStream = append(pendingStream, stream)
				}
			}

			// DATA
			if (f.flag&DATA != 0) && (f.dataLen > 0) {
				if stream != nil {
					stream.up.In(f.data, time.Time{})
				} else {
					// unsolicited frame, respond with RST
					rst := newFrame(f.sID, RST, 0, nil)
					s.writeFrame(rst)
					releaseFrame(rst)
				}
			}

			// FIN or RST
			if (f.flag&FIN != 0) || (f.flag&RST != 0) {
				if stream != nil {
					s.clearStream(f.sID)
					stream.cloze()
				}
			}
			releaseFrame(f)

		case <-s.quit:
			// quit message needs to broadcast to all streams.
			s.mapLock.Lock()
			for _, stream := range s.streams {
				stream.cloze()
			}
			s.streams = nil
			s.mapLock.Unlock()
			break loop
		}
		if timer != nil {
			timer.Stop()
		}
	}
	close(s.streamCh)
	s.cloze()
}

func (s *Session) cloze() error {
	return s.conn.Close()
}

func (s *Session) remoteAddr() net.Addr {
	return s.conn.RemoteAddr()
}

func (s *Session) localAddr() net.Addr {
	return s.conn.LocalAddr()
}

func (m *Stream) Read(buf []byte) (n int, err error) {
	if len(m.upCur) == 0 {
		m.upCur, err = m.up.Out(m.readDeadline)
		if err != nil {
			return
		}
	}
	n = copy(buf, m.upCur)
	m.upCur = m.upCur[n:]
	return
}

func (m *Stream) Write(b []byte) (int, error) {
	var timeout <-chan time.Time
	if !m.writeDeadline.IsZero() {
		t := time.NewTimer(m.writeDeadline.Sub(time.Now()))
		defer t.Stop()
		timeout = t.C
	}

	sent := 0
	total := len(b)
loop:
	for {
		select {
		case <-m.session.quit:
			return sent, &net.OpError{Op: "write", Err: syscall.EPIPE}
		case <-m.quit:
			return sent, &net.OpError{Op: "write", Err: syscall.EPIPE}
		case <-timeout:
			return sent, &utils.TimeoutError{}
		default:
			n := total - sent
			if n <= 0 {
				break loop
			}
			if n > maxDataLen {
				n = maxDataLen
			}
			f := newFrame(m.id, DATA, uint16(n), b[sent:sent+n])
			if !m.synSent && m.session.isClient {
				f.flag |= SYN
				m.synSent = true
			}
			err := m.session.writeFrame(f)
			if err != nil {
				return sent, err
			}
			releaseFrame(f)
			sent += n
		}
	}
	return total, nil
}

func (m *Stream) Close() error {
	m.session.clearStream(m.id)
	if m.cloze() {
		fin := newFrame(m.id, FIN, 0, nil)
		select {
		case <-m.session.quit:
		default:
			m.session.writeFrame(fin)
		}
		releaseFrame(fin)
	}
	return nil
}

func (m *Stream) cloze() bool {
	if atomic.AddUint32(&m.quitFlag, 1) > 1 {
		return false
	}
	close(m.quit)
	m.up.Stop()
	return true
}

func (m *Stream) SetDeadline(t time.Time) error {
	err := m.SetReadDeadline(t)
	if err != nil {
		return err
	}
	err = m.SetWriteDeadline(t)
	if err != nil {
		return err
	}
	return nil
}

func (m *Stream) SetReadDeadline(t time.Time) error {
	m.readDeadline = t
	return nil
}

func (m *Stream) SetWriteDeadline(t time.Time) error {
	m.writeDeadline = t
	return nil
}

func (m *Stream) RemoteAddr() net.Addr {
	return m.session.remoteAddr()
}

func (m *Stream) LocalAddr() net.Addr {
	return m.session.localAddr()
}
<commit_msg>changed mux to SocketPipe<commit_after>package mux

import (
	"encoding/binary"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/yinghuocho/golibfq/utils"
)

const (
	SYN  = 0x1
	FIN  = 0x2
	RST  = 0x4
	DATA = 0x8

	maxDataLen = 65535
)

type muxFrame struct {
	sID     uint32
	flag    byte
	dataLen uint16
	data    []byte
}

type Session struct {
	isClient bool

	// atomic generation Id for new Streams
	genStreamID uint32

	wlock sync.Mutex
	conn  net.Conn
	quit  chan bool

	// mapLock protects operations on streams-map by Session.loop or someone
	// invokes Stream.Close, or Client.OpenStream
	//
	// Closed session has a nil map to prevent new streams by Client.OpenStream
	streams map[uint32]*Stream
	mapLock sync.Mutex

	// Used by Server to write new Streams to someone waiting on Server.Accept.
	streamCh chan *Stream

	// idle session will be closed
	idle time.Duration
}

type Client struct {
	s *Session
}

type Server struct {
	s *Session
}

// implement net.Conn interface
type Stream struct {
	id uint32

	// checked by Write to ensure first data from Client Stream has a SYN flag.
	synSent bool

	pc net.Conn
	ps net.Conn
	// up    *utils.BytePipe
	// upCur []byte

	// readDeadline  time.Time
	writeDeadline time.Time
	closed        bool

	// quit     chan bool
	// quitFlag uint32

	session *Session
}

func NewClient(c net.Conn) *Client {
	s := &Session{
		isClient: true,
		conn:     c,
		streams:  make(map[uint32]*Stream),
		quit:     make(chan bool),
		streamCh: make(chan *Stream),
	}
	go s.loop()
	return &Client{s: s}
}

func (c *Client) OpenStream() (*Stream, error) {
	id := atomic.AddUint32(&c.s.genStreamID, 1)
	return c.s.newStream(id)
}

func (c *Client) SetIdleTime(idle time.Duration) {
	c.s.idle = idle
}

func (c *Client) Close() error {
	return c.s.cloze()
}

func NewServer(c net.Conn) *Server {
	s := &Session{
		isClient: false,
		conn:     c,
		streams:  make(map[uint32]*Stream),
		quit:     make(chan bool),
		streamCh: make(chan *Stream),
	}
	go s.loop()
	return &Server{s: s}
}

func (s *Server) Accept() (*Stream, error) {
	stream, ok := <-s.s.streamCh
	if !ok {
		return nil, io.EOF
	}
	return stream, nil
}

func (s *Server) Close() error {
	return s.s.cloze()
}

func (s *Server) SetIdleTime(idle time.Duration) {
	s.s.idle = idle
}

func (s *Session) readFrame() (*muxFrame, error) {
	var buf [7]byte
	_, err := io.ReadFull(s.conn, buf[:])
	if err != nil {
		return nil, err
	}
	sID := binary.BigEndian.Uint32(buf[0:4])
	flag := buf[4]
	dataLen := binary.BigEndian.Uint16(buf[5:7])
	if dataLen > 0 {
		data := make([]byte, dataLen)
		_, err := io.ReadFull(s.conn, data[0:dataLen])
		if err != nil {
			return nil, err
		}
		return &muxFrame{sID, flag, dataLen, data}, nil
	} else {
		return &muxFrame{sID, flag, dataLen, nil}, nil
	}
}

func (s *Session) writeFrame(frame *muxFrame, deadline time.Time) error {
	s.wlock.Lock()
	defer s.wlock.Unlock()

	var buf [65535 + 8]byte
	binary.BigEndian.PutUint32(buf[0:], frame.sID)
	buf[4] = frame.flag
	binary.BigEndian.PutUint16(buf[5:], frame.dataLen)
	if frame.dataLen > 0 {
		copy(buf[7:], frame.data[0:frame.dataLen])
	}
	s.conn.SetWriteDeadline(deadline)
	_, err := s.conn.Write(buf[0 : uint32(frame.dataLen)+7])
	// log.Printf("frame send: %d %d %d: error(%v)", frame.sID, frame.flag, frame.dataLen, err)
	return err
}

func (s *Session) getStream(sID uint32) *Stream {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	return s.streams[sID]
}

func (s *Session) newStream(sID uint32) (*Stream, error) {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	// Session already closed
	if s.streams == nil {
		return nil, io.EOF
	}
	pc, ps := utils.SocketPipe()
	stream := &Stream{
		id: sID,
		// up:      utils.NewBytePipe(fmt.Sprintf("%d-UP", sID), 0),
		// quit:    make(chan bool),
		pc:            pc,
		ps:            ps,
		writeDeadline: time.Time{},
		closed:        false,
		session:       s,
	}

	s.streams[sID] = stream
	// go stream.up.Start()
	return stream, nil
}

func (s *Session) clearStream(sID uint32) {
	s.mapLock.Lock()
	defer s.mapLock.Unlock()

	delete(s.streams, sID)
}

func (s *Session) loop() {
	var pendingStream []*Stream

	readCh := make(chan *muxFrame)
	// reader
	go func() {
		for {
			f, err := s.readFrame()
			if err != nil {
				break
			}
			readCh <- f
		}
		s.cloze()
		close(s.quit)
		return
	}()

loop:
	for {
		var streamCh chan *Stream
		var curStream *Stream
		var timer *time.Timer
		var to <-chan time.Time

		if s.idle != 0 {
			timer = time.NewTimer(s.idle)
			to = timer.C
		}

		if !s.isClient && len(pendingStream) > 0 {
			streamCh = s.streamCh
			curStream = pendingStream[0]
		}

		select {
		case <-to:
			s.mapLock.Lock()
			for _, stream := range s.streams {
				stream.cloze()
			}
			s.streams = nil
			s.mapLock.Unlock()
			break loop
		case streamCh <- curStream:
			pendingStream = pendingStream[1:]
		case f := <-readCh:
			stream := s.getStream(f.sID)
			// SYN
			// log.Printf("frame recv: %d %d %d", f.sID, f.flag, f.dataLen)
			if (stream == nil) && (f.flag&SYN != 0) {
				stream, _ = s.newStream(f.sID)
				if !s.isClient {
					pendingStream = append(pendingStream, stream)
				}
			}

			// DATA
			if (f.flag&DATA != 0) && (f.dataLen > 0) {
				if stream != nil {
					// stream.up.In(f.data, time.Time{})
					stream.ps.SetWriteDeadline(time.Time{})
					_, e := stream.ps.Write(f.data)
					if e != nil {
						stream.cloze()
					}
				} else {
					// unsolicited frame, respond with RST
					rst := &muxFrame{f.sID, RST, 0, nil}
					s.writeFrame(rst, time.Time{})
				}
			}

			// FIN or RST
			if (f.flag&FIN != 0) || (f.flag&RST != 0) {
				if stream != nil {
					s.clearStream(f.sID)
					stream.cloze()
				}
			}

		case <-s.quit:
			// quit message needs to broadcast to all streams.
			s.mapLock.Lock()
			for _, stream := range s.streams {
				stream.cloze()
			}
			s.streams = nil
			s.mapLock.Unlock()
			break loop
		}
		if timer != nil {
			timer.Stop()
		}
	}
	close(s.streamCh)
	s.cloze()
}

func (s *Session) cloze() error {
	return s.conn.Close()
}

func (s *Session) remoteAddr() net.Addr {
	return s.conn.RemoteAddr()
}

func (s *Session) localAddr() net.Addr {
	return s.conn.LocalAddr()
}

func (m *Stream) Read(buf []byte) (n int, err error) {
	// if len(m.upCur) == 0 {
	//	m.upCur, err = m.up.Out(m.readDeadline)
	//	if err != nil {
	//		return
	//	}
	// }
	// n = copy(buf, m.upCur)
	// m.upCur = m.upCur[n:]
	// return
	return m.pc.Read(buf)
}

func (m *Stream) Write(b []byte) (int, error) {
	total := len(b)
	sent := 0
	for {
		n := total - sent
		if n == 0 {
			break
		}
		if n > maxDataLen {
			n = maxDataLen
		}
		f := &muxFrame{m.id, DATA, uint16(n), b[sent : sent+n]}
		if !m.synSent && m.session.isClient {
			f.flag |= SYN
			m.synSent = true
		}
		err := m.session.writeFrame(f, m.writeDeadline)
		if err != nil {
			return sent, err
		}
		sent += n
	}
	return total, nil

	// var timeout <-chan time.Time
	// if !m.writeDeadline.IsZero() {
	//	t := time.NewTimer(m.writeDeadline.Sub(time.Now()))
	//	defer t.Stop()
	//	timeout = t.C
	// }

	// sent := 0
	// total := len(b)
	// loop:
	// for {
	//	select {
	//	case <-m.session.quit:
	//		return sent, &net.OpError{Op: "write", Err: syscall.EPIPE}
	//	case <-m.quit:
	//		return sent, &net.OpError{Op: "write", Err: syscall.EPIPE}
	//	case <-timeout:
	//		return sent, &utils.TimeoutError{}
	//	default:
	//		n := total - sent
	//		if n <= 0 {
	//			break loop
	//		}
	//		if n > maxDataLen {
	//			n = maxDataLen
	//		}
	//		f := newFrame(m.id, DATA, uint16(n), b[sent:sent+n])
	//		if !m.synSent && m.session.isClient {
	//			f.flag |= SYN
	//			m.synSent = true
	//		}
	//		err := m.session.writeFrame(f)
	//		if err != nil {
	//			return sent, err
	//		}
	//		releaseFrame(f)
	//		sent += n
	//	}
	// }
	// return total, nil
}

func (m *Stream) Close() error {
	if m.closed {
		return nil
	}
	m.closed = true
	fin := &muxFrame{m.id, FIN, 0, nil}
	m.session.writeFrame(fin, m.writeDeadline)
	m.session.clearStream(m.id)
	m.pc.Close()
	return m.ps.Close()

	// m.session.clearStream(m.id)
	// if m.cloze() {
	//	fin := newFrame(m.id, FIN, 0, nil)
	//	select {
	//	case <-m.session.quit:
	//	default:
	//		m.session.writeFrame(fin)
	//	}
	//	releaseFrame(fin)
	// }
	// return nil
	// return m.pc.Close()
}

func (m *Stream) cloze() {
	// if atomic.AddUint32(&m.quitFlag, 1) > 1 {
	//	return false
	// }
	// close(m.quit)
	// m.up.Stop()

	// return true
	m.ps.Close()
}

func (m *Stream) SetDeadline(t time.Time) error {
	err := m.pc.SetReadDeadline(t)
	if err != nil {
		return err
	}
	err = m.pc.SetWriteDeadline(t)
	if err != nil {
		return err
	}
	return nil
}

func (m *Stream) SetReadDeadline(t time.Time) error {
	return m.pc.SetReadDeadline(t)
}

func (m *Stream) SetWriteDeadline(t time.Time) error {
	m.writeDeadline = t
	return nil
	// return m.pc.SetWriteDeadline(t)
}

func (m *Stream) RemoteAddr() net.Addr {
	return m.session.remoteAddr()
}

func (m *Stream) LocalAddr() net.Addr {
	return m.session.localAddr()
}
<|endoftext|>


<commit_before>package mux

import (
	"net/http"
	"regexp"
)

type RecoverHandler func(*http.Request, http.ResponseWriter, interface{}) interface{}

type RequestProcessor func(*http.Request) (*http.Request, bool)

type Handler func(http.ResponseWriter, *http.Request, *Context)

type handlerInfo struct {
	/* TODO: Add support for patterns specifing a host */
	re      *regexp.Regexp
	handler Handler
}

type Mux struct {
	handlers          []*handlerInfo
	RequestProcessors []RequestProcessor
	RecoverHandlers   []RecoverHandler
}

func (mux *Mux) HandleMuxFunc(pattern string, handler Handler) {
	info := &handlerInfo{
		re:      regexp.MustCompile(pattern),
		handler: handler,
	}
	mux.handlers = append(mux.handlers, info)
}

func (mux *Mux) AddRequestProcessor(rp RequestProcessor) {
	mux.RequestProcessors = append(mux.RequestProcessors, rp)
}

func (mux *Mux) AddRecoverHandler(rh RecoverHandler) {
	mux.RecoverHandlers = append(mux.RecoverHandlers, rh)
}

func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			for _, v := range mux.RecoverHandlers {
				err = v(r, w, err)
				if err == nil {
					break
				}
			}
			if err != nil {
				panic(err)
			}
		}
	}()
	stop := false
	for _, v := range mux.RequestProcessors {
		r, stop = v(r)
		if stop {
			break
		}
	}
	if !stop {
		/* Try mux handlers first */
		for _, v := range mux.handlers {
			if submatches := v.re.FindStringSubmatch(r.URL.Path); submatches != nil {
				params := map[string]string{}
				for ii, n := range v.re.SubexpNames() {
					if n != "" {
						params[n] = submatches[ii]
					}
				}
				ctx := &Context{
					submatches: submatches,
					params:     params,
				}
				v.handler(w, r, ctx)
				stop = true
				break
			}
		}
		if !stop {
			http.DefaultServeMux.ServeHTTP(w, r)
		}
	}
}

func New() *Mux {
	return &Mux{}
}

type Context struct {
	submatches []string
	params     map[string]string
}

func (c *Context) IndexValue(idx int) string {
	if idx < len(c.submatches) {
	    return c.submatches[idx]
	}
	return ""
}

func (c *Context) ParamValue(name string) string {
	return c.params[name]
}
<commit_msg>Allow more flexible context processors<commit_after>package mux

import (
	"net/http"
	"regexp"
)

type RecoverHandler func(*http.Request, http.ResponseWriter, interface{}) interface{}

type RequestProcessor func(*http.Request, http.ResponseWriter, *Context) (*http.Request, bool)

type Handler func(http.ResponseWriter, *http.Request, *Context)

type handlerInfo struct {
	/* TODO: Add support for patterns specifing a host */
	re      *regexp.Regexp
	handler Handler
}

type Mux struct {
	handlers          []*handlerInfo
	RequestProcessors []RequestProcessor
	RecoverHandlers   []RecoverHandler
}

func (mux *Mux) HandleMuxFunc(pattern string, handler Handler) {
	info := &handlerInfo{
		re:      regexp.MustCompile(pattern),
		handler: handler,
	}
	mux.handlers = append(mux.handlers, info)
}

func (mux *Mux) AddRequestProcessor(rp RequestProcessor) {
	mux.RequestProcessors = append(mux.RequestProcessors, rp)
}

func (mux *Mux) AddRecoverHandler(rh RecoverHandler) {
	mux.RecoverHandlers = append(mux.RecoverHandlers, rh)
}

func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			for _, v := range mux.RecoverHandlers {
				err = v(r, w, err)
				if err == nil {
					break
				}
			}
			if err != nil {
				panic(err)
			}
		}
	}()
	stop := false
	ctx := &Context{}
	for _, v := range mux.RequestProcessors {
		r, stop = v(r, w, ctx)
		if stop {
			break
		}
	}
	if !stop {
		/* Try mux handlers first */
		for _, v := range mux.handlers {
			if submatches := v.re.FindStringSubmatch(r.URL.Path); submatches != nil {
				params := map[string]string{}
				for ii, n := range v.re.SubexpNames() {
					if n != "" {
						params[n] = submatches[ii]
					}
				}
				ctx.submatches = submatches
				ctx.params = params
				v.handler(w, r, ctx)
				stop = true
				break
			}
		}
		if !stop {
			http.DefaultServeMux.ServeHTTP(w, r)
		}
	}
}

func New() *Mux {
	return &Mux{}
}

type Context struct {
	submatches []string
	params     map[string]string
}

func (c *Context) Count() int {
	return len(c.submatches)
}

func (c *Context) IndexValue(idx int) string {
	if idx < len(c.submatches) {
		return c.submatches[idx]
	}
	return ""
}

func (c *Context) ParamValue(name string) string {
	return c.params[name]
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2015, zheng-ji.info
*/

package monitor

import (
	"fmt"
	"testing"
	"time"
)

func TestMonitor(t *testing.T) {
	InitMonitor([]string{"WRITE", "READ"}, 1)
	StartMonitorServer("0.0.0.0:7070")
	timeStart := time.Now()
	time.Sleep(300 * time.Millisecond)
	StatByAction("READ", timeStart)
}
<commit_msg>modify test monitor<commit_after>/*
Copyright (c) 2015, zheng-ji.info
*/

package monitor

import (
	"testing"
	"time"
)

func TestMonitor(t *testing.T) {
	InitMonitor([]string{"WRITE", "READ"}, 1)
	StartMonitorServer("0.0.0.0:7070")
	timeStart := time.Now()
	time.Sleep(300 * time.Millisecond)
	StatByAction("READ", timeStart)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"os"
)

var settings struct {
	Monsti util.MonstiSettings
}

var logger *log.Logger
var renderer template.Renderer

type editFormData struct {
	Title string
	Image string
}

func edit(req service.Request, res *service.Response, s *service.Session) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		var imageData []byte
		var err error
		if len(req.Files["Image"]) == 1 {
			imageData, err = req.Files["Image"][0].ReadFile()
			if err != nil {
				panic("Could not read image data: " + err.Error())
			}
		}
		if form.Fill(req.FormData) {
			if len(imageData) > 0 {
				dataC := s.Data()
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				if err := dataC.UpdateNode(req.Site, node); err != nil {
					panic("Could not update node: " + err.Error())
				}
				if err := dataC.WriteNodeData(req.Site, req.Node.Path,
					"image.data", string(imageData)); err != nil {
					panic("Could not write image data: " + err.Error())
				}
				res.Redirect = req.Node.Path
				return
			}
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req service.Request, res *service.Response, s *service.Session) {
	body, err := s.Data().GetNodeData(req.Site, req.Node.Path,
		"image.data")
	if err != nil {
		panic("Could not get image data: " + err.Error())
	}
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "image ", log.LstdFlags)
	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	if err := util.LoadModuleSettings("image", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}

	infoPath := settings.Monsti.GetServicePath(service.Info.String())

	l10n.Setup("monsti", settings.Monsti.GetLocalePath())
	renderer.Root = settings.Monsti.GetTemplatesPath()

	provider := service.NewNodeProvider(logger, infoPath)
	image := service.NodeTypeHandler{
		Name:       "Image",
		ViewAction: view,
		EditAction: edit,
	}
	provider.AddNodeType(&image)
	if err := provider.Serve(settings.Monsti.GetServicePath(
		service.Node.String() + "_image")); err != nil {
		panic("Could not setup node provider: " + err.Error())
	}

}
<commit_msg>Add copyright notice.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

/*
 Monsti is a simple and resource efficient CMS.

 This package implements the image node type.
*/
package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"os"
)

var settings struct {
	Monsti util.MonstiSettings
}

var logger *log.Logger
var renderer template.Renderer

type editFormData struct {
	Title string
	Image string
}

func edit(req service.Request, res *service.Response, s *service.Session) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		var imageData []byte
		var err error
		if len(req.Files["Image"]) == 1 {
			imageData, err = req.Files["Image"][0].ReadFile()
			if err != nil {
				panic("Could not read image data: " + err.Error())
			}
		}
		if form.Fill(req.FormData) {
			if len(imageData) > 0 {
				dataC := s.Data()
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				if err := dataC.UpdateNode(req.Site, node); err != nil {
					panic("Could not update node: " + err.Error())
				}
				if err := dataC.WriteNodeData(req.Site, req.Node.Path,
					"image.data", string(imageData)); err != nil {
					panic("Could not write image data: " + err.Error())
				}
				res.Redirect = req.Node.Path
				return
			}
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req service.Request, res *service.Response, s *service.Session) {
	body, err := s.Data().GetNodeData(req.Site, req.Node.Path,
		"image.data")
	if err != nil {
		panic("Could not get image data: " + err.Error())
	}
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "image ", log.LstdFlags)
	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	if err := util.LoadModuleSettings("image", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}

	infoPath := settings.Monsti.GetServicePath(service.Info.String())

	l10n.Setup("monsti", settings.Monsti.GetLocalePath())
	renderer.Root = settings.Monsti.GetTemplatesPath()

	provider := service.NewNodeProvider(logger, infoPath)
	image := service.NodeTypeHandler{
		Name:       "Image",
		ViewAction: view,
		EditAction: edit,
	}
	provider.AddNodeType(&image)
	if err := provider.Serve(settings.Monsti.GetServicePath(
		service.Node.String() + "_image")); err != nil {
		panic("Could not setup node provider: " + err.Error())
	}

}
<|endoftext|>


<commit_before>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

/*
 Monsti is a simple and resource efficient CMS.

 This package implements the image node type.
*/
package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"os"
)

var settings struct {
	Monsti util.MonstiSettings
}

var logger *log.Logger
var renderer template.Renderer

type editFormData struct {
	Title string
	Image string
}

func edit(req service.Request, res *service.Response, s *service.Session) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		var imageData []byte
		var err error
		if len(req.Files["Image"]) == 1 {
			imageData, err = req.Files["Image"][0].ReadFile()
			if err != nil {
				panic("Could not read image data: " + err.Error())
			}
		}
		if form.Fill(req.FormData) {
			if len(imageData) > 0 {
				dataC := s.Data()
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				if err := dataC.UpdateNode(req.Site, node); err != nil {
					panic("Could not update node: " + err.Error())
				}
				if err := dataC.WriteNodeData(req.Site, req.Node.Path,
					"image.data", string(imageData)); err != nil {
					panic("Could not write image data: " + err.Error())
				}
				res.Redirect = req.Node.Path
				return
			}
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req service.Request, res *service.Response, s *service.Session) {
	body, err := s.Data().GetNodeData(req.Site, req.Node.Path,
		"image.data")
	if err != nil {
		panic("Could not get image data: " + err.Error())
	}
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "image ", log.LstdFlags)
	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	if err := util.LoadModuleSettings("image", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}

	infoPath := settings.Monsti.GetServicePath(service.Info.String())

	l10n.Setup("monsti", settings.Monsti.GetLocalePath())
	renderer.Root = settings.Monsti.GetTemplatesPath()

	provider := service.NewNodeProvider(logger, infoPath)
	image := service.NodeTypeHandler{
		Name:       "Image",
		ViewAction: view,
		EditAction: edit,
	}
	provider.AddNodeType(&image)
	if err := provider.Serve(settings.Monsti.GetServicePath(
		service.Node.String() + "_image")); err != nil {
		panic("Could not setup node provider: " + err.Error())
	}
}
<commit_msg>Fix translation domain name.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

/*
 Monsti is a simple and resource efficient CMS.

 This package implements the image node type.
*/
package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"os"
)

var settings struct {
	Monsti util.MonstiSettings
}

var logger *log.Logger
var renderer template.Renderer

type editFormData struct {
	Title string
	Image string
}

func edit(req service.Request, res *service.Response, s *service.Session) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		var imageData []byte
		var err error
		if len(req.Files["Image"]) == 1 {
			imageData, err = req.Files["Image"][0].ReadFile()
			if err != nil {
				panic("Could not read image data: " + err.Error())
			}
		}
		if form.Fill(req.FormData) {
			if len(imageData) > 0 {
				dataC := s.Data()
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				if err := dataC.UpdateNode(req.Site, node); err != nil {
					panic("Could not update node: " + err.Error())
				}
				if err := dataC.WriteNodeData(req.Site, req.Node.Path,
					"image.data", string(imageData)); err != nil {
					panic("Could not write image data: " + err.Error())
				}
				res.Redirect = req.Node.Path
				return
			}
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req service.Request, res *service.Response, s *service.Session) {
	body, err := s.Data().GetNodeData(req.Site, req.Node.Path,
		"image.data")
	if err != nil {
		panic("Could not get image data: " + err.Error())
	}
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "image ", log.LstdFlags)
	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	if err := util.LoadModuleSettings("image", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}

	infoPath := settings.Monsti.GetServicePath(service.Info.String())

	l10n.Setup("monsti-image", settings.Monsti.GetLocalePath())
	renderer.Root = settings.Monsti.GetTemplatesPath()

	provider := service.NewNodeProvider(logger, infoPath)
	image := service.NodeTypeHandler{
		Name:       "Image",
		ViewAction: view,
		EditAction: edit,
	}
	provider.AddNodeType(&image)
	if err := provider.Serve(settings.Monsti.GetServicePath(
		service.Node.String() + "_image")); err != nil {
		panic("Could not setup node provider: " + err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/util/l10n"
	"github.com/monsti/rpc/client"
	"github.com/monsti/util/template"
	"github.com/monsti/util"
	"log"
	"os"
	"path/filepath"
)

type settings struct {
	// Absolute paths to used directories.
	Directories struct {
		// HTML Templates
		Templates string
		// Locales, i.e. the gettext machine objects (.mo)
		Locales string
	}
}

var renderer template.Renderer
var logger *log.Logger

func handle(req client.Request, res *client.Response, c client.Connection) {
	switch req.Action {
	case "edit":
		edit(req, res, c)
	default:
		view(req, res, c)
	}
}

type editFormData struct {
	Title string
	Image string
}

func edit(req client.Request, res *client.Response, c client.Connection) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		imageData, imgerr := c.GetFileData("Image")
		if form.Fill(c.GetFormData()) {
			if imgerr == nil {
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				c.UpdateNode(node)
				c.WriteNodeData(req.Node.Path, "image.data", string(imageData))
				res.Redirect = req.Node.Path
				return
			}
			logger.Println("Image upload failed: ", imgerr)
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req client.Request, res *client.Response, c client.Connection) {
	body := c.GetNodeData(req.Node.Path, "image.data")
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "monsti-image", log.LstdFlags)
	flag.Parse()
	cfgPath := util.GetConfigPath("image", flag.Arg(0))
	var settings settings
	if err := util.ParseYAML(cfgPath, &settings); err != nil {
		logger.Fatal("Could not load monsti-image configuration file: ", err)
	}
	util.MakeAbsolute(&settings.Directories.Templates, filepath.Dir(cfgPath))
	util.MakeAbsolute(&settings.Directories.Locales, filepath.Dir(cfgPath))
	l10n.Setup("monsti-image", settings.Directories.Locales)
	renderer.Root = settings.Directories.Templates
	client.NewConnection("monsti-image", logger).Serve(handle)
}
<commit_msg>Refactor to use new API.<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/monsti/form"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"os"
)

var settings struct {
	Monsti util.MonstiSettings
}

var logger *log.Logger
var renderer template.Renderer

type editFormData struct {
	Title string
	Image string
}

func edit(req service.Request, res *service.Response, s *service.Session) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Image": form.Field{G("Image"), "", nil, new(form.FileWidget)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
	case "POST":
		var imageData []byte
		var err error
		if len(req.Files["Image"]) == 1 {
			imageData, err = req.Files["Image"][0].ReadFile()
			if err != nil {
				panic("Could not read image data: " + err.Error())
			}
		}
		if form.Fill(req.FormData) {
			if len(imageData) > 0 {
				dataC := s.Data()
				node := req.Node
				node.Title = data.Title
				node.Hide = true
				if err := dataC.UpdateNode(req.Site, node); err != nil {
					panic("Could not update node: " + err.Error())
				}
				if err := dataC.WriteNodeData(req.Site, req.Node.Path,
					"image.data", string(imageData)); err != nil {
					panic("Could not write image data: " + err.Error())
				}
				res.Redirect = req.Node.Path
				return
			}
			form.AddError("Image", G("There was a problem with your image upload."))
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("image/edit",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func view(req service.Request, res *service.Response, s *service.Session) {
	body, err := s.Data().GetNodeData(req.Site, req.Node.Path,
		"image.data")
	if err != nil {
		panic("Could not get image data: " + err.Error())
	}
	res.Raw = true
	res.Write(body)
}

func main() {
	logger = log.New(os.Stderr, "image ", log.LstdFlags)
	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	if err := util.LoadModuleSettings("image", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}

	infoPath := settings.Monsti.GetServicePath(service.Info.String())

	l10n.Setup("monsti", settings.Monsti.GetLocalePath())
	renderer.Root = settings.Monsti.GetTemplatesPath()

	provider := service.NewNodeProvider(logger, infoPath)
	image := service.NodeTypeHandler{
		Name:       "Image",
		ViewAction: view,
		EditAction: edit,
	}
	provider.AddNodeType(&image)
	if err := provider.Serve(settings.Monsti.GetServicePath(
		service.Node.String() + "_image")); err != nil {
		panic("Could not setup node provider: " + err.Error())
	}

}
<|endoftext|>


<commit_before>package prometheus

import (
	"github.com/mozilla-services/heka/message"
	"github.com/mozilla-services/heka/pipeline"
	"github.com/prometheus/client_golang/prometheus"
	//"net/http"
	//"net/url"
	"strings"
	"sync"
	//"time"
)

type PromOutConfig struct {
	Address     string
	MetricsPath string
}

type PromOut struct {
	config    *PromOutConfig
	rlock     *sync.RWMutex
	gaugeVecs map[string]*prometheus.GaugeVec
	gauges    map[string]prometheus.Gauge
}

func (p *PromOut) ConfigStruct() interface{} {
	return &PromOutConfig{
		Address: "0.0.0.0:9107",
	}
}

func (p *PromOut) Init(config interface{}) error {
	p.config = config.(*PromOutConfig)
	p.rlock = &sync.RWMutex{}
	return nil
}

func (p *PromOut) validMsg(m *message.Message) bool {
	/*
		switch string.ToLowerm.GetType()) {
			case
		}
	*/
	return true
}

func (p *PromOut) Describe(ch chan<- *prometheus.Desc) {

	p.rlock.RLock()
	defer p.rlock.RUnlock()

	for _, gauge := range p.gauges {
		ch <- gauge.Desc()
	}
	for _, gaugeVec := range p.gaugeVecs {
		gaugeVec.Describe(ch)
	}

}
func (p *PromOut) Collect(ch chan<- prometheus.Metric) {
	p.rlock.Lock()
	defer p.rlock.Unlock()

}

func (p *PromOut) Run(or pipeline.OutputRunner, h pipeline.PluginHelper) (err error) {
	var (
		pack         *pipeline.PipelinePack
		field        *message.Field
		seen_metrics map[string]map[string]bool
	)

	for pack = range or.InChan {
		if p.validMsg(pack.Message) {
			namespace := pack.Message
			msgType := strings.ToLower(pack.Message.GetType())
			switch strings.ToLower(pack.Message.GetType()) {
			case "gaugevecs":
			case "gauge":

			}
		}
		pack.Recycle()
	}

}
func gaugeOpts(m *message.Message) prometheus.GaugeOpts {
	return prometheus.GaugeOpts{
		Namespace: m.FindFirstField("Namespace"),
		Name:      m.FindFirstField("Name"),
		Help:      m.FindFirstField("Help"),
	}

}

func newGaugeVec(m *message.Message, opts prometheus.GaugeOpts) (*prometheus.GaugeVec, error) {

	return prometheus.NewGaugeVec(gaugeOpts(m),
		m.FindFirstField("labels"),
	)

}
func newGauge(m *message.Message) (prometheus.Gauge, error) {
}

func init() {
	pipeline.RegisterPlugin("PrometheusOutput", func() interface{} {
		return new(PromOut)
	})
}
<commit_msg>works<commit_after>// Package prometheus implements a heka output plugin which provides acts as a prometheus endpoint
// ready for scraping
//
// Messages that arrive via the heka router must have a carefully formatted structure, all data is conveyed in Heka Fields:  http://hekad.readthedocs.org/en/v0.9.2/message/index.html
//
// Prometheus Data types limited to: Gauge and GaugeVect
///
package prometheus

import (
	"github.com/mozilla-services/heka/message"
	"github.com/mozilla-services/heka/pipeline"
	"github.com/prometheus/client_golang/prometheus"
	//"net/http"
	//"net/url"
	"fmt"
	"net/http"
	"strings"
	"sync"
	//"time"
)

var (
	metricFieldVal  = "metric_value"
	metricFieldName = "metric_name"
	metricFieldType = "metric_type"
)
var (
	metricFieldTagK = "tags_key"
	metricFieldTagV = "tags_val"
)

type PromOutConfig struct {
	Address string
}

type PromOut struct {
	config    *PromOutConfig
	rlock     *sync.RWMutex
	gaugeVecs map[string]map[string]*prometheus.GaugeVec
	gauges    map[string]prometheus.Gauge
	inSuccess prometheus.Counter
	inFailure prometheus.Counter
	l         func(string)
}

func (p *PromOut) ConfigStruct() interface{} {
	return &PromOutConfig{
		Address: "0.0.0.0:9107",
	}
}

func (p *PromOut) Init(config interface{}) error {
	p.gaugeVecs = make(map[string]map[string]*prometheus.GaugeVec)
	p.gauges = make(map[string]prometheus.Gauge)

	p.inSuccess = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "hekagateway_msg_success",
			Help: "properly formatted messages",
		},
	)

	p.inFailure = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "hekagateway_msg_failed",
			Help: "improperly formatted messages",
		},
	)

	p.config = config.(*PromOutConfig)
	p.rlock = &sync.RWMutex{}
	e := prometheus.Register(p)
	if e != nil {
		return e
	}

	http.Handle("/metrics", prometheus.Handler())
	go http.ListenAndServe(p.config.Address, nil)
	return nil

}

func (p *PromOut) Describe(ch chan<- *prometheus.Desc) {

	p.rlock.RLock()
	defer p.rlock.RUnlock()

	for _, gauge := range p.gauges {
		ch <- gauge.Desc()
	}
	for _, v := range p.gaugeVecs {
		for r, gaugeVec := range v {
			if p.l != nil {
				p.l(fmt.Sprintf("Describe: %s", r))
				p.l(r)
			}

			gaugeVec.Describe(ch)
		}
	}
	ch <- p.inSuccess.Desc()
	ch <- p.inFailure.Desc()

}
func (p *PromOut) Collect(ch chan<- prometheus.Metric) {
	p.rlock.Lock()
	defer p.rlock.Unlock()
	for _, v := range p.gaugeVecs {
		for r, gv := range v {
			if p.l != nil {
				p.l(fmt.Sprintf("Collect: %s", r))
			}

			gv.Collect(ch)
		}
	}
	for _, g := range p.gauges {
		ch <- g
	}
	ch <- p.inSuccess
	ch <- p.inFailure
}

func (p *PromOut) Run(or pipeline.OutputRunner, h pipeline.PluginHelper) (err error) {
	var (
		gv    *prometheus.GaugeVec
		g     prometheus.Gauge
		m     *pMetric
		found bool
		f     *message.Field
	)
	p.l = or.LogMessage

	for pack := range or.InChan() {

		m, err = newPMetric(pack.Message)
		if err != nil {
			or.LogError(err)
			p.inFailure.Inc()
			pack.Recycle()
			continue

		}

		switch m.mType {

		case "gaugevec":

			p.rlock.Lock()

			if f = pack.Message.FindFirstField(metricFieldTagK); f == nil {
				or.LogError(fmt.Errorf("type: %s missing mandatory field: '%s'", m.mType, metricFieldTagK))

				p.inFailure.Inc()
				pack.Recycle()
				continue
			}

			tagsKeys := f.GetValueString()
			tagsLookup := strings.Join(tagsKeys, "")

			if f = pack.Message.FindFirstField(metricFieldTagV); f == nil {
			}
			tagsVals := f.GetValueString()
			if len(tagsKeys) != len(tagsVals) {
				or.LogError(fmt.Errorf("tag fields mismatched lengths: '%s/%s'",
					strings.Join(tagsKeys, ","),
					strings.Join(tagsVals, ","),
				))

				p.inFailure.Inc()
				pack.Recycle()
				continue

			}
			gopts := m.gaugeOpts(pack.Message)

			_, found = p.gaugeVecs[m.mName]
			if !found {
				p.gaugeVecs[m.mName] = make(map[string]*prometheus.GaugeVec)
				p.gaugeVecs[m.mName][tagsLookup] = prometheus.NewGaugeVec(gopts, tagsKeys)
				gv, _ = p.gaugeVecs[m.mName][tagsLookup]

			} else {
				gv, found = p.gaugeVecs[m.mName][tagsLookup]
				if !found {
					p.gaugeVecs[m.mName][tagsLookup] = prometheus.NewGaugeVec(gopts, tagsKeys)
				}
			}

			if g, err = gv.GetMetricWithLabelValues(tagsKeys...); err != nil {
				or.LogError(err)
				p.inFailure.Inc()
				pack.Recycle()
				continue
			}
			gv.Reset()
			g.Set(m.v)
			p.inSuccess.Inc()

			p.rlock.Unlock()

		case "gauge":
			p.rlock.Lock()
			g, found = p.gauges[m.mName]
			if !found {
				p.gauges[m.mName] = prometheus.NewGauge(m.gaugeOpts(pack.Message))
				g, _ = p.gauges[m.mName]
			}
			g.Set(m.v)
			p.inSuccess.Inc()

			p.rlock.Unlock()
			//g.Set(
		default:
			or.LogError(fmt.Errorf("unsupported message Type: %s", m.mType))
			p.inFailure.Inc()
			//pack.Recycle()
			//continue

		}

		pack.Recycle()
	}
	return nil
}

func init() {
	pipeline.RegisterPlugin("PrometheusOutput", func() interface{} {
		return new(PromOut)
	})
}

func newPMetric(m *message.Message) (*pMetric, error) {

	var (
		pm = &pMetric{}
		f  *message.Field
	)
	requiredMissing := func(s string) error {
		return fmt.Errorf("missing required field: %s", s)
	}

	singleFieldWrongCount := func(s string, i int) error {
		return fmt.Errorf("required singleton field: %s, with %d vals", s, i)
	}

	if f = m.FindFirstField(metricFieldVal); f != nil {
		d := f.GetValueDouble()
		if len(d) != 1 {
			return nil, singleFieldWrongCount(metricFieldVal, len(d))
		}
		pm.v = d[0]
	} else {

		return nil, requiredMissing(metricFieldVal)

	}

	if f = m.FindFirstField(metricFieldName); f != nil {
		if s := f.GetValueString(); len(s) != 1 {
			return nil, singleFieldWrongCount(metricFieldName, len(s))

		} else {
			pm.mName = s[0]
		}

	} else {
		return nil, requiredMissing(metricFieldName)
	}

	if f = m.FindFirstField(metricFieldType); f != nil {
		if s := f.GetValueString(); len(s) != 1 {
			return nil, singleFieldWrongCount(metricFieldType, len(s))

		} else {
			pm.mType = strings.ToLower(s[0])
		}

	} else {
		return nil, requiredMissing(metricFieldType)
	}

	return pm, nil
}

type pMetric struct {
	mType, mName string
	v            float64
}

func (p *pMetric) gaugeOpts(m *message.Message) prometheus.GaugeOpts {

	var f *message.Field
	gopts := prometheus.GaugeOpts{
		Name: p.mName,
	}
	if f = m.FindFirstField("Help"); f != nil {
		gopts.Help = f.GetValueString()[0]

	}
	if f = m.FindFirstField("Namespace"); f != nil {
		gopts.Namespace = f.GetValueString()[0]

	}
	return gopts
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	log "github.com/Sirupsen/logrus"
	"github.com/nats-io/go-nats"
	"github.com/stefanprodan/syros/models"
)

type Consumer struct {
	Config         *Config
	NatsConnection *nats.Conn
	Repository     *Repository
}

func NewConsumer(config *Config, nc *nats.Conn, repo *Repository) (*Consumer, error) {
	consumer := &Consumer{
		Config:         config,
		NatsConnection: nc,
		Repository:     repo,
	}
	return consumer, nil
}

func (c *Consumer) Consume() {
	c.DockerConsume()
	c.ConsulConsume()
}

func (c *Consumer) DockerConsume() {
	c.NatsConnection.QueueSubscribe("docker", c.Config.CollectorQueue, func(m *nats.Msg) {
		crepo, err := NewRepository(c.Config)
		if err != nil {
			log.Fatalf("RethinkDB connection error %v", err)
		}
		var payload models.DockerPayload
		err = json.Unmarshal(m.Data, &payload)
		if err != nil {
			log.Errorf("Docker payload unmarshal error %v", err)
		} else {
			log.Debugf("Docker payload received from host %v running containes %v", payload.Host.Name, payload.Host.ContainersRunning)
			crepo.HostUpsert(payload.Host)

			for _, container := range payload.Containers {
				crepo.ContainerUpsert(container)
			}
			crepo.Session.Close()
		}
	})
}

func (c *Consumer) ConsulConsume() {
	c.NatsConnection.QueueSubscribe("consul", c.Config.CollectorQueue, func(m *nats.Msg) {
		crepo, err := NewRepository(c.Config)
		if err != nil {
			log.Fatalf("RethinkDB connection error %v", err)
		}

		var payload models.ConsulPayload
		err = json.Unmarshal(m.Data, &payload)
		if err != nil {
			log.Errorf("Consul payload unmarshal error %v", err)
		} else {
			log.Debugf("Consul payload received %v checks", len(payload.HealthChecks))
			for _, check := range payload.HealthChecks {
				crepo.CheckUpsert(check)
			}
			crepo.Session.Close()
		}
	})
}
<commit_msg>undo dedicated rdb session per collector<commit_after>package main

import (
	"encoding/json"
	log "github.com/Sirupsen/logrus"
	"github.com/nats-io/go-nats"
	"github.com/stefanprodan/syros/models"
)

type Consumer struct {
	Config         *Config
	NatsConnection *nats.Conn
	Repository     *Repository
}

func NewConsumer(config *Config, nc *nats.Conn, repo *Repository) (*Consumer, error) {
	consumer := &Consumer{
		Config:         config,
		NatsConnection: nc,
		Repository:     repo,
	}
	return consumer, nil
}

func (c *Consumer) Consume() {
	c.DockerConsume()
	c.ConsulConsume()
}

func (c *Consumer) DockerConsume() {
	c.NatsConnection.QueueSubscribe("docker", c.Config.CollectorQueue, func(m *nats.Msg) {
		var payload models.DockerPayload
		err := json.Unmarshal(m.Data, &payload)
		if err != nil {
			log.Errorf("Docker payload unmarshal error %v", err)
		} else {
			log.Debugf("Docker payload received from host %v running containes %v", payload.Host.Name, payload.Host.ContainersRunning)
			c.Repository.HostUpsert(payload.Host)

			for _, container := range payload.Containers {
				c.Repository.ContainerUpsert(container)
			}
		}
	})
}

func (c *Consumer) ConsulConsume() {
	c.NatsConnection.QueueSubscribe("consul", c.Config.CollectorQueue, func(m *nats.Msg) {
		var payload models.ConsulPayload
		err := json.Unmarshal(m.Data, &payload)
		if err != nil {
			log.Errorf("Consul payload unmarshal error %v", err)
		} else {
			log.Debugf("Consul payload received %v checks", len(payload.HealthChecks))
			for _, check := range payload.HealthChecks {
				c.Repository.CheckUpsert(check)
			}
		}
	})
}
<|endoftext|>