<commit_before>package diego

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"

	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	"github.com/onsi/ginkgo/reporters"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry/cf-acceptance-tests/helpers"
)

func TestApplications(t *testing.T) {
	RegisterFailHandler(Fail)

	config := helpers.LoadConfig()

	helpers.SetupEnvironment(t, helpers.NewContext(config))

	rs := []Reporter{}

	if config.ArtifactsDirectory != "" {
		os.Setenv(
			"CF_TRACE",
			filepath.Join(
				config.ArtifactsDirectory,
				fmt.Sprintf("CATS-TRACE-%s-%d.txt", "DiegoApplications", ginkgoconfig.GinkgoConfig.ParallelNode),
			),
		)

		rs = append(
			rs,
			reporters.NewJUnitReporter(
				filepath.Join(
					config.ArtifactsDirectory,
					fmt.Sprintf("junit-%s-%d.xml", "DiegoApplications", ginkgoconfig.GinkgoConfig.ParallelNode),
				),
			),
		)
	}

	RunSpecsWithDefaultAndCustomReporters(t, "Applications with Diego", rs)
}
<commit_msg>fix SetupEnvironment in diego suite<commit_after>package diego

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"

	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	"github.com/onsi/ginkgo/reporters"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry/cf-acceptance-tests/helpers"
)

func TestApplications(t *testing.T) {
	RegisterFailHandler(Fail)

	config := helpers.LoadConfig()

	helpers.SetupEnvironment(helpers.NewContext(config))

	rs := []Reporter{}

	if config.ArtifactsDirectory != "" {
		os.Setenv(
			"CF_TRACE",
			filepath.Join(
				config.ArtifactsDirectory,
				fmt.Sprintf("CATS-TRACE-%s-%d.txt", "DiegoApplications", ginkgoconfig.GinkgoConfig.ParallelNode),
			),
		)

		rs = append(
			rs,
			reporters.NewJUnitReporter(
				filepath.Join(
					config.ArtifactsDirectory,
					fmt.Sprintf("junit-%s-%d.xml", "DiegoApplications", ginkgoconfig.GinkgoConfig.ParallelNode),
				),
			),
		)
	}

	RunSpecsWithDefaultAndCustomReporters(t, "Applications with Diego", rs)
}
<|endoftext|>


<commit_before>package log

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/mholt/caddy/caddyhttp/httpserver"
)

type erroringMiddleware struct{}

func (erroringMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	if rr, ok := w.(*httpserver.ResponseRecorder); ok {
		rr.Replacer.Set("testval", "foobar")
	}
	return http.StatusNotFound, nil
}

func TestLoggedStatus(t *testing.T) {
	var f bytes.Buffer
	var next erroringMiddleware
	rule := Rule{
		PathScope: "/",
		Entries: []*Entry{{
			Format: DefaultLogFormat + " {testval}",
			Log:    log.New(&f, "", 0),
		}},
	}

	logger := Logger{
		Rules: []*Rule{&rule},
		Next:  next,
	}

	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	rec := httptest.NewRecorder()

	status, err := logger.ServeHTTP(rec, r)
	if status != 0 {
		t.Errorf("Expected status to be 0, but was %d", status)
	}

	if err != nil {
		t.Errorf("Expected error to be nil, instead got: %v", err)
	}

	logged := f.String()
	if !strings.Contains(logged, "404 13") {
		t.Errorf("Expected log entry to contain '404 13', but it didn't: %s", logged)
	}

	// check custom placeholder
	if !strings.Contains(logged, "foobar") {
		t.Errorf("Expected the log entry to contain 'foobar' (custom placeholder), but it didn't: %s", logged)
	}
}

func TestLogRequestBody(t *testing.T) {
	var got bytes.Buffer
	logger := Logger{
		Rules: []*Rule{{
			PathScope: "/",
			Entries: []*Entry{{
				Format: "{request_body}",
				Log:    log.New(&got, "", 0),
			}},
		}},
		Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			// drain up body
			ioutil.ReadAll(r.Body)
			return 0, nil
		}),
	}

	for i, c := range []struct {
		body   string
		expect string
	}{
		{"", "\n"},
		{"{hello} world!", "{hello} world!\n"},
		{func() string {
			length := httpserver.MaxLogBodySize + 100
			b := make([]byte, length)
			for i := 0; i < length; i++ {
				b[i] = 0xab
			}
			return string(b)
		}(), func() string {
			b := make([]byte, httpserver.MaxLogBodySize)
			for i := 0; i < httpserver.MaxLogBodySize; i++ {
				b[i] = 0xab
			}
			return string(b) + "\n"
		}(),
		},
	} {
		got.Reset()
		r, err := http.NewRequest("POST", "/", bytes.NewBufferString(c.body))
		if err != nil {
			t.Fatal(err)
		}
		r.Header.Set("Content-Type", "application/json")
		status, err := logger.ServeHTTP(httptest.NewRecorder(), r)
		if status != 0 {
			t.Errorf("case %d: Expected status to be 0, but was %d", i, status)
		}
		if err != nil {
			t.Errorf("case %d: Expected error to be nil, instead got: %v", i, err)
		}
		if got.String() != c.expect {
			t.Errorf("case %d: Expected body %q, but got %q", i, c.expect, got.String())
		}
	}
}
<commit_msg>log: add multiple log entry test<commit_after>package log

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/mholt/caddy/caddyhttp/httpserver"
)

type erroringMiddleware struct{}

func (erroringMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	if rr, ok := w.(*httpserver.ResponseRecorder); ok {
		rr.Replacer.Set("testval", "foobar")
	}
	return http.StatusNotFound, nil
}

func TestLoggedStatus(t *testing.T) {
	var f bytes.Buffer
	var next erroringMiddleware
	rule := Rule{
		PathScope: "/",
		Entries: []*Entry{{
			Format: DefaultLogFormat + " {testval}",
			Log:    log.New(&f, "", 0),
		}},
	}

	logger := Logger{
		Rules: []*Rule{&rule},
		Next:  next,
	}

	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	rec := httptest.NewRecorder()

	status, err := logger.ServeHTTP(rec, r)
	if status != 0 {
		t.Errorf("Expected status to be 0, but was %d", status)
	}

	if err != nil {
		t.Errorf("Expected error to be nil, instead got: %v", err)
	}

	logged := f.String()
	if !strings.Contains(logged, "404 13") {
		t.Errorf("Expected log entry to contain '404 13', but it didn't: %s", logged)
	}

	// check custom placeholder
	if !strings.Contains(logged, "foobar") {
		t.Errorf("Expected the log entry to contain 'foobar' (custom placeholder), but it didn't: %s", logged)
	}
}

func TestLogRequestBody(t *testing.T) {
	var got bytes.Buffer
	logger := Logger{
		Rules: []*Rule{{
			PathScope: "/",
			Entries: []*Entry{{
				Format: "{request_body}",
				Log:    log.New(&got, "", 0),
			}},
		}},
		Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			// drain up body
			ioutil.ReadAll(r.Body)
			return 0, nil
		}),
	}

	for i, c := range []struct {
		body   string
		expect string
	}{
		{"", "\n"},
		{"{hello} world!", "{hello} world!\n"},
		{func() string {
			length := httpserver.MaxLogBodySize + 100
			b := make([]byte, length)
			for i := 0; i < length; i++ {
				b[i] = 0xab
			}
			return string(b)
		}(), func() string {
			b := make([]byte, httpserver.MaxLogBodySize)
			for i := 0; i < httpserver.MaxLogBodySize; i++ {
				b[i] = 0xab
			}
			return string(b) + "\n"
		}(),
		},
	} {
		got.Reset()
		r, err := http.NewRequest("POST", "/", bytes.NewBufferString(c.body))
		if err != nil {
			t.Fatal(err)
		}
		r.Header.Set("Content-Type", "application/json")
		status, err := logger.ServeHTTP(httptest.NewRecorder(), r)
		if status != 0 {
			t.Errorf("case %d: Expected status to be 0, but was %d", i, status)
		}
		if err != nil {
			t.Errorf("case %d: Expected error to be nil, instead got: %v", i, err)
		}
		if got.String() != c.expect {
			t.Errorf("case %d: Expected body %q, but got %q", i, c.expect, got.String())
		}
	}
}

func TestMultiEntries(t *testing.T) {
	var (
		got1 bytes.Buffer
		got2 bytes.Buffer
	)
	logger := Logger{
		Rules: []*Rule{{
			PathScope: "/",
			Entries: []*Entry{
				{
					Format: "foo {request_body}",
					Log:    log.New(&got1, "", 0),
				},
				{
					Format: "{method} {request_body}",
					Log:    log.New(&got2, "", 0),
				},
			},
		}},
		Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			// drain up body
			ioutil.ReadAll(r.Body)
			return 0, nil
		}),
	}

	r, err := http.NewRequest("POST", "/", bytes.NewBufferString("hello world"))
	if err != nil {
		t.Fatal(err)
	}
	r.Header.Set("Content-Type", "application/json")
	status, err := logger.ServeHTTP(httptest.NewRecorder(), r)
	if status != 0 {
		t.Errorf("Expected status to be 0, but was %d", status)
	}
	if err != nil {
		t.Errorf("Expected error to be nil, instead got: %v", err)
	}
	if got, expect := got1.String(), "foo hello world\n"; got != expect {
		t.Errorf("Expected %q, but got %q", expect, got)
	}
	if got, expect := got2.String(), "POST hello world\n"; got != expect {
		t.Errorf("Expected %q, but got %q", expect, got)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gnd.la/log"
	"math"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	// avoids starting multiple services
	// at the same time, to enforce resource limits
	startLock sync.Mutex
)

type State uint8

const (
	StateStopped State = iota
	StateStopping
	StateStarted
	StateStarting
	StateBackoff
	StateFailed
)

func (s State) isRunState() bool {
	return s == StateStarted || s == StateStarting
}

func (s State) canStop() bool {
	return s.isRunState() || s == StateBackoff
}

const (
	minTime    = time.Second
	maxRetries = 10
)

type Service struct {
	mu         sync.Mutex // protects access to the fields
	st         sync.Mutex // prevents start/stop from running concurrently
	Config     *Config
	Cmd        *exec.Cmd
	State      State
	Started    time.Time
	Restarts   int
	Err        error
	stopCh     chan error
	errCh      chan error
	retries    int
	startTimer *time.Timer
	nextStart  time.Time
}

func newService(cfg *Config) *Service {
	return &Service{Config: cfg, stopCh: make(chan error)}
}

func (s *Service) Name() string {
	return s.Config.ServiceName()
}

func (s *Service) sendErr(ch *chan<- error, err error) {
	if err != nil && s.State != StateStopping {
		s.errorf("%v", err)
	}
	s.Err = err
	if ch != nil && *ch != nil {
		select {
		case *ch <- err:
			*ch = nil
		default:
		}
	}
	if s.errCh != nil {
		select {
		case s.errCh <- err:
		default:
		}
	}
}

func (s *Service) Start() error {
	s.st.Lock()
	defer s.st.Unlock()
	if s.State.isRunState() {
		return nil
	}
	if err := s.Config.Log.Open(); err != nil {
		return err
	}
	if err := s.startService(); err != nil {
		return err
	}
	if err := s.startWatchdog(); err != nil {
		s.errorf("error starting watchdog: %s", s.Name(), err)
	}
	return nil
}

func (s *Service) startIn(d time.Duration) {
	s.stopTimer()
	s.startTimer = time.AfterFunc(d, func() { s.Run(nil) })
	s.nextStart = time.Now().Add(d)
}

func (s *Service) started(ch *chan<- error) {
	s.State = StateStarted
	s.stopTimer()
	s.sendErr(ch, nil)
	s.retries = 0
}

func (s *Service) startFailed(ch *chan<- error, err error) {
	s.sendErr(ch, err)
	if s.retries < maxRetries-1 {
		s.State = StateBackoff
		duration := time.Second * time.Duration(math.Pow(2, float64(s.retries)))
		s.startIn(duration)
		s.retries++
		s.infof("will retry in %s", duration)
	} else {
		s.State = StateFailed
		s.Cmd = nil
		s.errorf("maximum retries reached")
	}
}

func (s *Service) untilNextRestart() time.Duration {
	return s.nextStart.Sub(time.Now())
}

func (s *Service) Run(ch chan<- error) {
	s.mu.Lock()
	s.State = StateStarted
	s.mu.Unlock()
	for {
		s.mu.Lock()
		if s.State != StateStarted {
			s.mu.Unlock()
			break
		}
		cmd, err := s.Config.Cmd()
		if err != nil {
			s.State = StateFailed
			s.errorf("could not initialize: %s", err)
			s.sendErr(&ch, err)
			s.mu.Unlock()
			break
		}
		if s.Config.Log != nil {
			cmd.Stdout = s.Config.Log.Stdout
			cmd.Stderr = s.Config.Log.Stderr
		}
		s.Cmd = cmd
		s.Started = time.Now()
		s.infof("starting")
		startLock.Lock()
		limits, err := SetLimits(s.Config)
		if err != nil {
			s.errorf("error setting service limits: %s", err)
		}
		serr := s.Cmd.Start()
		if err := RestoreLimits(limits); err != nil {
			s.errorf("error restoring limits: %s", err)
		}
		startLock.Unlock()
		if serr != nil {
			s.errorf("failed to start: %s", serr)
			s.startFailed(&ch, serr)
			s.mu.Unlock()
			break
		}
		s.mu.Unlock()
		timer := time.AfterFunc(time.Duration(float64(minTime)*1.1), func() {
			s.mu.Lock()
			defer s.mu.Unlock()
			// Clear any potentially stored errors
			s.started(&ch)
			s.infof("started")
		})
		err = s.Cmd.Wait()
		timer.Stop()
		s.mu.Lock()
		if s.State != StateStarted {
			s.Cmd = nil
			s.sendErr(&ch, err)
			s.stopCh <- nil
			s.mu.Unlock()
			break
		}
		if since := time.Since(s.Started); since < minTime {
			// Consider failure
			s.startFailed(&ch, fmt.Errorf("exited too fast (%s)", since))
			s.mu.Unlock()
			break
		}
		s.Restarts++
		s.mu.Unlock()
		if err != nil {
			s.infof("exited with error %s - restarting", err)
		} else {
			s.infof("exited without error - restarting")
		}
	}
}

func (s *Service) Stop() error {
	s.st.Lock()
	defer s.st.Unlock()
	s.stopWatchdog()
	if err := s.stopService(); err != nil {
		s.startWatchdog()
		return err
	}
	return nil
}

func (s *Service) startWatchdog() error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Config.Watchdog != nil {
		interval := s.Config.WatchdogInterval
		if interval < 0 {
			interval = defaultWatchdogInterval
		}
		return s.Config.Watchdog.Start(s, interval)
	}
	return nil
}

func (s *Service) stopWatchdog() {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Config.Watchdog != nil {
		s.Config.Watchdog.Stop()
	}
}

func (s *Service) stopTimerLocking() {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.stopTimer()
}

func (s *Service) stopTimer() {
	if s.startTimer != nil {
		s.startTimer.Stop()
		s.startTimer = nil
		s.nextStart = time.Time{}
	}
}

func (s *Service) startService() error {
	ch := make(chan error)
	s.stopTimerLocking()
	go s.Run(ch)
	err := <-ch
	close(ch)
	return err
}

func (s *Service) stopService() error {
	s.stopTimer()
	s.mu.Lock()
	if !s.State.isRunState() {
		if s.State.canStop() {
			s.infof("stopped")
		}
		s.State = StateStopped
		s.mu.Unlock()
		return nil
	}
	prevState := s.State
	s.State = StateStopping
	s.infof("stopping")
	p := s.Cmd.Process
	s.mu.Unlock()
	if s != nil {
		stopped := isStoppedErr(p.Signal(os.Signal(syscall.SIGTERM)))
		if !stopped {
			select {
			case <-s.stopCh:
				stopped = true
			case <-time.After(10 * time.Second):
				stopped = isStoppedErr(p.Kill())
			}
			if !stopped {
				select {
				case <-s.stopCh:
				case <-time.After(2 * time.Second):
					// sending signal 0 checks that the process is
					// alive and we're allowed to send the signal
					// without actually sending anything
					if isStoppedErr(p.Signal(syscall.Signal(0))) {
						break
					}
					s.mu.Lock()
					s.State = prevState
					s.mu.Unlock()
					err := fmt.Errorf("could not stop, probably stuck")
					s.errorf("%v", err)
					return err
				}
			}
		}
	}
	s.mu.Lock()
	s.State = StateStopped
	s.Restarts = 0
	s.mu.Unlock()
	if s.Config.Log != nil {
		s.Config.Log.Close()
	}
	s.infof("stopped")
	return nil
}

func (s *Service) log(level log.LLevel, prefix string, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	log.Logf(level, "[%s] %s", s.Name(), msg)
	if s.Config.Log != nil {
		s.Config.Log.WriteString(prefix, msg)
	}
}

func (s *Service) errorf(format string, args ...interface{}) {
	s.log(log.LError, "error", format, args...)
}

func (s *Service) infof(format string, args ...interface{}) {
	s.log(log.LInfo, "info", format, args...)
}

func (s *Service) debugf(format string, args ...interface{}) {
	s.log(log.LDebug, "debug", format, args...)
}

func (s *Service) updateConfig(cfg *Config) {
	if reflect.DeepEqual(s.Config, cfg) {
		// there were changes to the file which don't affect the conf
		return
	}
	log.Debugf("changed service %s's configuration", s.Name())
	start := false
	if s.State == StateStarted {
		start = s.Stop() == nil
	}
	s.Config = cfg
	if start {
		s.Start()
	}
}

func isStoppedErr(err error) bool {
	return err != nil && strings.Contains(err.Error(), "process already finished")
}
<commit_msg>Fix error format<commit_after>package main

import (
	"fmt"
	"gnd.la/log"
	"math"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	// avoids starting multiple services
	// at the same time, to enforce resource limits
	startLock sync.Mutex
)

type State uint8

const (
	StateStopped State = iota
	StateStopping
	StateStarted
	StateStarting
	StateBackoff
	StateFailed
)

func (s State) isRunState() bool {
	return s == StateStarted || s == StateStarting
}

func (s State) canStop() bool {
	return s.isRunState() || s == StateBackoff
}

const (
	minTime    = time.Second
	maxRetries = 10
)

type Service struct {
	mu         sync.Mutex // protects access to the fields
	st         sync.Mutex // prevents start/stop from running concurrently
	Config     *Config
	Cmd        *exec.Cmd
	State      State
	Started    time.Time
	Restarts   int
	Err        error
	stopCh     chan error
	errCh      chan error
	retries    int
	startTimer *time.Timer
	nextStart  time.Time
}

func newService(cfg *Config) *Service {
	return &Service{Config: cfg, stopCh: make(chan error)}
}

func (s *Service) Name() string {
	return s.Config.ServiceName()
}

func (s *Service) sendErr(ch *chan<- error, err error) {
	if err != nil && s.State != StateStopping {
		s.errorf("%v", err)
	}
	s.Err = err
	if ch != nil && *ch != nil {
		select {
		case *ch <- err:
			*ch = nil
		default:
		}
	}
	if s.errCh != nil {
		select {
		case s.errCh <- err:
		default:
		}
	}
}

func (s *Service) Start() error {
	s.st.Lock()
	defer s.st.Unlock()
	if s.State.isRunState() {
		return nil
	}
	if err := s.Config.Log.Open(); err != nil {
		return err
	}
	if err := s.startService(); err != nil {
		return err
	}
	if err := s.startWatchdog(); err != nil {
		s.errorf("error starting watchdog %s: %s", s.Name(), err)
	}
	return nil
}

func (s *Service) startIn(d time.Duration) {
	s.stopTimer()
	s.startTimer = time.AfterFunc(d, func() { s.Run(nil) })
	s.nextStart = time.Now().Add(d)
}

func (s *Service) started(ch *chan<- error) {
	s.State = StateStarted
	s.stopTimer()
	s.sendErr(ch, nil)
	s.retries = 0
}

func (s *Service) startFailed(ch *chan<- error, err error) {
	s.sendErr(ch, err)
	if s.retries < maxRetries-1 {
		s.State = StateBackoff
		duration := time.Second * time.Duration(math.Pow(2, float64(s.retries)))
		s.startIn(duration)
		s.retries++
		s.infof("will retry in %s", duration)
	} else {
		s.State = StateFailed
		s.Cmd = nil
		s.errorf("maximum retries reached")
	}
}

func (s *Service) untilNextRestart() time.Duration {
	return s.nextStart.Sub(time.Now())
}

func (s *Service) Run(ch chan<- error) {
	s.mu.Lock()
	s.State = StateStarted
	s.mu.Unlock()
	for {
		s.mu.Lock()
		if s.State != StateStarted {
			s.mu.Unlock()
			break
		}
		cmd, err := s.Config.Cmd()
		if err != nil {
			s.State = StateFailed
			s.errorf("could not initialize: %s", err)
			s.sendErr(&ch, err)
			s.mu.Unlock()
			break
		}
		if s.Config.Log != nil {
			cmd.Stdout = s.Config.Log.Stdout
			cmd.Stderr = s.Config.Log.Stderr
		}
		s.Cmd = cmd
		s.Started = time.Now()
		s.infof("starting")
		startLock.Lock()
		limits, err := SetLimits(s.Config)
		if err != nil {
			s.errorf("error setting service limits: %s", err)
		}
		serr := s.Cmd.Start()
		if err := RestoreLimits(limits); err != nil {
			s.errorf("error restoring limits: %s", err)
		}
		startLock.Unlock()
		if serr != nil {
			s.errorf("failed to start: %s", serr)
			s.startFailed(&ch, serr)
			s.mu.Unlock()
			break
		}
		s.mu.Unlock()
		timer := time.AfterFunc(time.Duration(float64(minTime)*1.1), func() {
			s.mu.Lock()
			defer s.mu.Unlock()
			// Clear any potentially stored errors
			s.started(&ch)
			s.infof("started")
		})
		err = s.Cmd.Wait()
		timer.Stop()
		s.mu.Lock()
		if s.State != StateStarted {
			s.Cmd = nil
			s.sendErr(&ch, err)
			s.stopCh <- nil
			s.mu.Unlock()
			break
		}
		if since := time.Since(s.Started); since < minTime {
			// Consider failure
			s.startFailed(&ch, fmt.Errorf("exited too fast (%s)", since))
			s.mu.Unlock()
			break
		}
		s.Restarts++
		s.mu.Unlock()
		if err != nil {
			s.infof("exited with error %s - restarting", err)
		} else {
			s.infof("exited without error - restarting")
		}
	}
}

func (s *Service) Stop() error {
	s.st.Lock()
	defer s.st.Unlock()
	s.stopWatchdog()
	if err := s.stopService(); err != nil {
		s.startWatchdog()
		return err
	}
	return nil
}

func (s *Service) startWatchdog() error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Config.Watchdog != nil {
		interval := s.Config.WatchdogInterval
		if interval < 0 {
			interval = defaultWatchdogInterval
		}
		return s.Config.Watchdog.Start(s, interval)
	}
	return nil
}

func (s *Service) stopWatchdog() {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Config.Watchdog != nil {
		s.Config.Watchdog.Stop()
	}
}

func (s *Service) stopTimerLocking() {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.stopTimer()
}

func (s *Service) stopTimer() {
	if s.startTimer != nil {
		s.startTimer.Stop()
		s.startTimer = nil
		s.nextStart = time.Time{}
	}
}

func (s *Service) startService() error {
	ch := make(chan error)
	s.stopTimerLocking()
	go s.Run(ch)
	err := <-ch
	close(ch)
	return err
}

func (s *Service) stopService() error {
	s.stopTimer()
	s.mu.Lock()
	if !s.State.isRunState() {
		if s.State.canStop() {
			s.infof("stopped")
		}
		s.State = StateStopped
		s.mu.Unlock()
		return nil
	}
	prevState := s.State
	s.State = StateStopping
	s.infof("stopping")
	p := s.Cmd.Process
	s.mu.Unlock()
	if s != nil {
		stopped := isStoppedErr(p.Signal(os.Signal(syscall.SIGTERM)))
		if !stopped {
			select {
			case <-s.stopCh:
				stopped = true
			case <-time.After(10 * time.Second):
				stopped = isStoppedErr(p.Kill())
			}
			if !stopped {
				select {
				case <-s.stopCh:
				case <-time.After(2 * time.Second):
					// sending signal 0 checks that the process is
					// alive and we're allowed to send the signal
					// without actually sending anything
					if isStoppedErr(p.Signal(syscall.Signal(0))) {
						break
					}
					s.mu.Lock()
					s.State = prevState
					s.mu.Unlock()
					err := fmt.Errorf("could not stop, probably stuck")
					s.errorf("%v", err)
					return err
				}
			}
		}
	}
	s.mu.Lock()
	s.State = StateStopped
	s.Restarts = 0
	s.mu.Unlock()
	if s.Config.Log != nil {
		s.Config.Log.Close()
	}
	s.infof("stopped")
	return nil
}

func (s *Service) log(level log.LLevel, prefix string, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	log.Logf(level, "[%s] %s", s.Name(), msg)
	if s.Config.Log != nil {
		s.Config.Log.WriteString(prefix, msg)
	}
}

func (s *Service) errorf(format string, args ...interface{}) {
	s.log(log.LError, "error", format, args...)
}

func (s *Service) infof(format string, args ...interface{}) {
	s.log(log.LInfo, "info", format, args...)
}

func (s *Service) debugf(format string, args ...interface{}) {
	s.log(log.LDebug, "debug", format, args...)
}

func (s *Service) updateConfig(cfg *Config) {
	if reflect.DeepEqual(s.Config, cfg) {
		// there were changes to the file which don't affect the conf
		return
	}
	log.Debugf("changed service %s's configuration", s.Name())
	start := false
	if s.State == StateStarted {
		start = s.Stop() == nil
	}
	s.Config = cfg
	if start {
		s.Start()
	}
}

func isStoppedErr(err error) bool {
	return err != nil && strings.Contains(err.Error(), "process already finished")
}
<|endoftext|>


<commit_before>package discord

import (
	"fmt"
	"github.com/bwmarrin/discordgo"
	"log"
	"math/rand"
	"time"

	"github.com/adayoung/ada-bot/discord/bot_reactions"
)

var BotID string
var dg *discordgo.Session

func init() {
	rand.Seed(time.Now().Unix())
}

func InitDiscordSession(token string, q_length int, wait_ms string) error {
	// Create a new Discord session using the provided login information.
	var err error
	if dg, err = discordgo.New(fmt.Sprintf("Bot %s", token)); err == nil {
		if u, err := dg.User("@me"); err == nil {
			BotID = u.ID

			dg.AddHandler(ready)
			// Add handlers for messages received
			dg.AddHandler(messageCreate)
			if err := dg.Open(); err == nil {
				fmt.Println("Successfully launched a new Discord session.")
			} else {
				return err // Error at opening Discord Session
			}
		} else {
			return err // Error at obtaining account details
		}
	} else {
		return err // Error at creating a new Discord session
	}

	if _wait_ms, err := time.ParseDuration(wait_ms); err == nil {
		messageQueue = make(chan message, q_length)
		rateLimit = time.NewTicker(_wait_ms)
		go dispatchMessages()
	} else {
		return err
	}
	return nil
}

func PostMessage(c string, m string) {
	mq := message{ChannelID: c, Message: m}
	messageQueue <- mq
}

func CloseDiscordSession() {
	dg.Close()
}

func ready(s *discordgo.Session, r *discordgo.Ready) {
	if guilds, err := s.UserGuilds(); err != nil {
		fmt.Println("ERROR: We couldn't get UserGuilds")
		log.Fatalf("error: %v", err)
	} else {
		for index, guild := range guilds {
			fmt.Printf("[%d] ------------------------------\n", index)
			fmt.Println("Guild ID: ", guild.ID)
			fmt.Println("Guild Name: ", guild.Name)
			fmt.Println("Guild Permissions: ", guild.Permissions)

		}
		fmt.Println("----------------------------------")
	}
}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	go _botReactions(s, m)
}

func _botReactions(s *discordgo.Session, m *discordgo.MessageCreate) {
	if m.Author.ID == BotID { // ignore the bot's own messages from processing
		return
	}

	if channel, err := s.State.Channel(m.ChannelID); err == nil {
		guildID := channel.GuildID

		if guildID == "" { // log direct messages sent to the bot
			fmt.Printf("Message received from %s: %s\n", m.Author.Username, m.Content)
			_postReactions(m.Message, &discordgo.Member{})
			return
		}

		if member, err := s.State.Member(guildID, m.Author.ID); err == nil {
			_postReactions(m.Message, member)
		} else {
			log.Printf("warning: %v", err) // Non-fatal error at s.State.Member() call
		}
	} else {
		log.Printf("warning: %v", err) // Non-fatal error at s.State.Channel() call
	}
}

func _postReactions(m *discordgo.Message, member *discordgo.Member) {
	for _, reaction := range bot_reactions.GetReactions(m, member) {
		PostMessage(m.ChannelID, reaction)
	}
}
<commit_msg>Let's not post empty reactions<commit_after>package discord

import (
	"fmt"
	"github.com/bwmarrin/discordgo"
	"log"
	"math/rand"
	"time"

	"github.com/adayoung/ada-bot/discord/bot_reactions"
)

var BotID string
var dg *discordgo.Session

func init() {
	rand.Seed(time.Now().Unix())
}

func InitDiscordSession(token string, q_length int, wait_ms string) error {
	// Create a new Discord session using the provided login information.
	var err error
	if dg, err = discordgo.New(fmt.Sprintf("Bot %s", token)); err == nil {
		if u, err := dg.User("@me"); err == nil {
			BotID = u.ID

			dg.AddHandler(ready)
			// Add handlers for messages received
			dg.AddHandler(messageCreate)
			if err := dg.Open(); err == nil {
				fmt.Println("Successfully launched a new Discord session.")
			} else {
				return err // Error at opening Discord Session
			}
		} else {
			return err // Error at obtaining account details
		}
	} else {
		return err // Error at creating a new Discord session
	}

	if _wait_ms, err := time.ParseDuration(wait_ms); err == nil {
		messageQueue = make(chan message, q_length)
		rateLimit = time.NewTicker(_wait_ms)
		go dispatchMessages()
	} else {
		return err
	}
	return nil
}

func PostMessage(c string, m string) {
	if len(m) > 0 {
		mq := message{ChannelID: c, Message: m}
		messageQueue <- mq
	}
}

func CloseDiscordSession() {
	dg.Close()
}

func ready(s *discordgo.Session, r *discordgo.Ready) {
	if guilds, err := s.UserGuilds(); err != nil {
		fmt.Println("ERROR: We couldn't get UserGuilds")
		log.Fatalf("error: %v", err)
	} else {
		for index, guild := range guilds {
			fmt.Printf("[%d] ------------------------------\n", index)
			fmt.Println("Guild ID: ", guild.ID)
			fmt.Println("Guild Name: ", guild.Name)
			fmt.Println("Guild Permissions: ", guild.Permissions)

		}
		fmt.Println("----------------------------------")
	}
}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	go _botReactions(s, m)
}

func _botReactions(s *discordgo.Session, m *discordgo.MessageCreate) {
	if m.Author.ID == BotID { // ignore the bot's own messages from processing
		return
	}

	if channel, err := s.State.Channel(m.ChannelID); err == nil {
		guildID := channel.GuildID

		if guildID == "" { // log direct messages sent to the bot
			fmt.Printf("Message received from %s: %s\n", m.Author.Username, m.Content)
			_postReactions(m.Message, &discordgo.Member{})
			return
		}

		if member, err := s.State.Member(guildID, m.Author.ID); err == nil {
			_postReactions(m.Message, member)
		} else {
			log.Printf("warning: %v", err) // Non-fatal error at s.State.Member() call
		}
	} else {
		log.Printf("warning: %v", err) // Non-fatal error at s.State.Channel() call
	}
}

func _postReactions(m *discordgo.Message, member *discordgo.Member) {
	for _, reaction := range bot_reactions.GetReactions(m, member) {
		PostMessage(m.ChannelID, reaction)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Sandpass Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
	"zombiezen.com/go/sandpass/pkg/kdbcrypt"
	"zombiezen.com/go/sandpass/pkg/keepass"
)

// Session flags.
func init() {
	flag.StringVar(&sessions.keyPath, "session_key", "", "path to file to store session key material")
	flag.DurationVar(&sessions.keyRotation, "session_key_rotation", 12*time.Hour, "minimum duration between generating new session keys")
	flag.DurationVar(&sessions.expiry, "session_expiry", 30*time.Minute, "length of time that a session token is valid")
	sessions.now = time.Now
}

// sessionCookie is the name of browser cookie containing the session token.
const sessionCookie = "sandpass_session"

type sessionStorage struct {
	keyPath     string
	keyRotation time.Duration
	expiry      time.Duration
	now         func() time.Time
}

// new creates a new session.
func (ss *sessionStorage) new(w http.ResponseWriter, data sessionData) (*session, error) {
	keyFile, err := ss.refreshKey()
	if err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	var nonce [24]byte
	if _, err := rand.Read(nonce[:]); err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	s := &session{
		Data: sessionData{
			Key: append([]byte(nil), data.Key...), // defensive copy
		},
		Expires: ss.now().Add(ss.expiry),
	}
	plaintext, err := json.Marshal(s)
	if err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	ciphertext := secretbox.Seal(nonce[:], plaintext, &nonce, keyFile.Primary.Key())
	http.SetCookie(w, &http.Cookie{
		Name:   sessionCookie,
		Value:  base64.StdEncoding.EncodeToString(ciphertext),
		Path:   "/",
		MaxAge: int(ss.expiry/time.Second) + 1,
	})
	return s, nil
}

func (ss *sessionStorage) dbFromRequest(w http.ResponseWriter, r *http.Request) (*keepass.Database, error) {
	s := ss.fromRequest(r)
	if !ss.isValid(s) {
		// Attempt to decrypt with no credentials, since that shouldn't require the
		// user to enter credentials.
		if db, err := openDatabase(nil); err == nil {
			if _, err := ss.new(w, sessionData{Key: db.ComputedKey()}); err != nil {
				return nil, err
			}
			return db, nil
		}
		return nil, errInvalidSession
	}
	return openDatabase(&keepass.Options{
		ComputedKey: s.Data.Key,
	})
}

// fromRequest obtains the request's session data. If the session information is
// in any way invalid, fromRequest returns nil. It does not return an error so
// as to potentially avoid leaking information to an attacker.
func (ss *sessionStorage) fromRequest(r *http.Request) *session {
	// Read key file before handling user input.
	keyFile, err := ss.refreshKey()
	if err != nil {
		return nil
	}
	primary := keyFile.Primary.Key()
	secondary := keyFile.Secondary.Key()
	if secondary == nil {
		secondary = primary
	}

	// Decode into binary, splitting nonce from ciphertext.
	c, err := r.Cookie(sessionCookie)
	if err != nil {
		return nil
	}
	ciphertext, err := base64.StdEncoding.DecodeString(c.Value)
	if err != nil {
		return nil
	}
	nonce := new([24]byte)
	if copy((*nonce)[:], ciphertext) < len(*nonce) {
		return nil
	}
	ciphertext = ciphertext[len(*nonce):]
	// Attempt to decrypt. Unconditionally unseal twice to avoid potential
	// timing attacks.
	plaintext1, ok1 := secretbox.Open(nil, ciphertext, nonce, primary)
	plaintext2, ok2 := secretbox.Open(nil, ciphertext, nonce, secondary)
	if !ok1 && !ok2 {
		return nil
	}
	var plaintext []byte
	if ok1 {
		plaintext = plaintext1
	} else {
		plaintext = plaintext2
	}
	s := new(session)
	if err := json.Unmarshal(plaintext, s); err != nil {
		return nil
	}
	if !ss.now().Before(s.Expires) {
		return nil
	}
	return s
}

func (ss *sessionStorage) isValid(s *session) bool {
	return s != nil && ss.now().Before(s.Expires)
}

// invalidateAll deletes the session keys. This effectively makes all sessions
// invalid, since they can no longer be decrypted.
func (ss *sessionStorage) invalidateAll() error {
	if err := os.Remove(ss.keyPath); err != nil {
		return fmt.Errorf("invalidate sessions: %v", err)
	}
	return nil
}

// refreshKey loads the keys from persistent storage, rotating them
// if necessary.
func (ss *sessionStorage) refreshKey() (*sessionKeyFile, error) {
	f := new(sessionKeyFile)
	if data, err := ioutil.ReadFile(ss.keyPath); err == nil {
		if err := json.Unmarshal(data, f); err != nil {
			// Don't want to proceed since we could clobber unknown data.
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
	} else if !os.IsNotExist(err) {
		// Don't want to proceed since we have permissions errors.
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	now := ss.now().UTC()
	switch {
	case f.Primary.Key() == nil || !now.Before(f.Primary.Expires):
		// Primary key doesn't exist or expired.
		primary, err := newSessionKey(now.Add(ss.keyRotation))
		if err != nil {
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
		f = &sessionKeyFile{Primary: primary}
	case now.After(f.Primary.Expires.Add(-ss.expiry)):
		// Sessions would be cut short by key rotation time.
		// Phase out primary to secondary ("grace period").
		newPrimary, err := newSessionKey(now.Add(ss.keyRotation))
		if err != nil {
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
		secondary := new(sessionKey)
		*secondary = f.Primary
		f = &sessionKeyFile{
			Primary:   newPrimary,
			Secondary: secondary,
		}
	case f.Secondary != nil && !now.Before(f.Secondary.Expires):
		// Secondary key has expired. Clear it.
		f.Secondary = nil
	}
	newData, err := json.Marshal(f)
	if err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	tempPath := ss.keyPath + "~"
	if err := ioutil.WriteFile(tempPath, newData, 0600); err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	if err := os.Rename(tempPath, ss.keyPath); err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	return f, nil
}

type sessionData struct {
	Key kdbcrypt.ComputedKey `json:"key"`
}

type session struct {
	Data    sessionData `json:"data"`
	Expires time.Time   `json:"expires"`
}

type sessionKeyFile struct {
	Primary   sessionKey  `json:"primary"`
	Secondary *sessionKey `json:"secondary,omitempty"`
}

type sessionKey struct {
	RawKey  []byte    `json:"key"`
	Expires time.Time `json:"expires"`
}

func newSessionKey(expires time.Time) (sessionKey, error) {
	k := sessionKey{
		RawKey:  make([]byte, 32),
		Expires: expires,
	}
	if _, err := rand.Read(k.RawKey); err != nil {
		return sessionKey{}, fmt.Errorf("generate session key: %v", err)
	}
	return k, nil
}

func (k *sessionKey) Key() *[32]byte {
	if k == nil || len(k.RawKey) != 32 {
		return nil
	}
	arr := new([32]byte)
	copy((*arr)[:], k.RawKey)
	return arr
}
<commit_msg>Don't add 1 to max age unnecessarily<commit_after>// Copyright 2016 The Sandpass Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"golang.org/x/crypto/nacl/secretbox"
	"zombiezen.com/go/sandpass/pkg/kdbcrypt"
	"zombiezen.com/go/sandpass/pkg/keepass"
)

// Session flags.
func init() {
	flag.StringVar(&sessions.keyPath, "session_key", "", "path to file to store session key material")
	flag.DurationVar(&sessions.keyRotation, "session_key_rotation", 12*time.Hour, "minimum duration between generating new session keys")
	flag.DurationVar(&sessions.expiry, "session_expiry", 30*time.Minute, "length of time that a session token is valid")
	sessions.now = time.Now
}

// sessionCookie is the name of browser cookie containing the session token.
const sessionCookie = "sandpass_session"

type sessionStorage struct {
	keyPath     string
	keyRotation time.Duration
	expiry      time.Duration
	now         func() time.Time
}

// new creates a new session.
func (ss *sessionStorage) new(w http.ResponseWriter, data sessionData) (*session, error) {
	keyFile, err := ss.refreshKey()
	if err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	var nonce [24]byte
	if _, err := rand.Read(nonce[:]); err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	s := &session{
		Data: sessionData{
			Key: append([]byte(nil), data.Key...), // defensive copy
		},
		Expires: ss.now().Add(ss.expiry),
	}
	plaintext, err := json.Marshal(s)
	if err != nil {
		return nil, fmt.Errorf("new session: %v", err)
	}
	ciphertext := secretbox.Seal(nonce[:], plaintext, &nonce, keyFile.Primary.Key())
	http.SetCookie(w, &http.Cookie{
		Name:   sessionCookie,
		Value:  base64.StdEncoding.EncodeToString(ciphertext),
		Path:   "/",
		MaxAge: int(ss.expiry / time.Second),
	})
	return s, nil
}

func (ss *sessionStorage) dbFromRequest(w http.ResponseWriter, r *http.Request) (*keepass.Database, error) {
	s := ss.fromRequest(r)
	if !ss.isValid(s) {
		// Attempt to decrypt with no credentials, since that shouldn't require the
		// user to enter credentials.
		if db, err := openDatabase(nil); err == nil {
			if _, err := ss.new(w, sessionData{Key: db.ComputedKey()}); err != nil {
				return nil, err
			}
			return db, nil
		}
		return nil, errInvalidSession
	}
	return openDatabase(&keepass.Options{
		ComputedKey: s.Data.Key,
	})
}

// fromRequest obtains the request's session data. If the session information is
// in any way invalid, fromRequest returns nil. It does not return an error so
// as to potentially avoid leaking information to an attacker.
func (ss *sessionStorage) fromRequest(r *http.Request) *session {
	// Read key file before handling user input.
	keyFile, err := ss.refreshKey()
	if err != nil {
		return nil
	}
	primary := keyFile.Primary.Key()
	secondary := keyFile.Secondary.Key()
	if secondary == nil {
		secondary = primary
	}

	// Decode into binary, splitting nonce from ciphertext.
	c, err := r.Cookie(sessionCookie)
	if err != nil {
		return nil
	}
	ciphertext, err := base64.StdEncoding.DecodeString(c.Value)
	if err != nil {
		return nil
	}
	nonce := new([24]byte)
	if copy((*nonce)[:], ciphertext) < len(*nonce) {
		return nil
	}
	ciphertext = ciphertext[len(*nonce):]
	// Attempt to decrypt. Unconditionally unseal twice to avoid potential
	// timing attacks.
	plaintext1, ok1 := secretbox.Open(nil, ciphertext, nonce, primary)
	plaintext2, ok2 := secretbox.Open(nil, ciphertext, nonce, secondary)
	if !ok1 && !ok2 {
		return nil
	}
	var plaintext []byte
	if ok1 {
		plaintext = plaintext1
	} else {
		plaintext = plaintext2
	}
	s := new(session)
	if err := json.Unmarshal(plaintext, s); err != nil {
		return nil
	}
	if !ss.now().Before(s.Expires) {
		return nil
	}
	return s
}

func (ss *sessionStorage) isValid(s *session) bool {
	return s != nil && ss.now().Before(s.Expires)
}

// invalidateAll deletes the session keys. This effectively makes all sessions
// invalid, since they can no longer be decrypted.
func (ss *sessionStorage) invalidateAll() error {
	if err := os.Remove(ss.keyPath); err != nil {
		return fmt.Errorf("invalidate sessions: %v", err)
	}
	return nil
}

// refreshKey loads the keys from persistent storage, rotating them
// if necessary.
func (ss *sessionStorage) refreshKey() (*sessionKeyFile, error) {
	f := new(sessionKeyFile)
	if data, err := ioutil.ReadFile(ss.keyPath); err == nil {
		if err := json.Unmarshal(data, f); err != nil {
			// Don't want to proceed since we could clobber unknown data.
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
	} else if !os.IsNotExist(err) {
		// Don't want to proceed since we have permissions errors.
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	now := ss.now().UTC()
	switch {
	case f.Primary.Key() == nil || !now.Before(f.Primary.Expires):
		// Primary key doesn't exist or expired.
		primary, err := newSessionKey(now.Add(ss.keyRotation))
		if err != nil {
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
		f = &sessionKeyFile{Primary: primary}
	case now.After(f.Primary.Expires.Add(-ss.expiry)):
		// Sessions would be cut short by key rotation time.
		// Phase out primary to secondary ("grace period").
		newPrimary, err := newSessionKey(now.Add(ss.keyRotation))
		if err != nil {
			return nil, fmt.Errorf("refresh session key: %v", err)
		}
		secondary := new(sessionKey)
		*secondary = f.Primary
		f = &sessionKeyFile{
			Primary:   newPrimary,
			Secondary: secondary,
		}
	case f.Secondary != nil && !now.Before(f.Secondary.Expires):
		// Secondary key has expired. Clear it.
		f.Secondary = nil
	}
	newData, err := json.Marshal(f)
	if err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	tempPath := ss.keyPath + "~"
	if err := ioutil.WriteFile(tempPath, newData, 0600); err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	if err := os.Rename(tempPath, ss.keyPath); err != nil {
		return nil, fmt.Errorf("refresh session key: %v", err)
	}
	return f, nil
}

type sessionData struct {
	Key kdbcrypt.ComputedKey `json:"key"`
}

type session struct {
	Data    sessionData `json:"data"`
	Expires time.Time   `json:"expires"`
}

type sessionKeyFile struct {
	Primary   sessionKey  `json:"primary"`
	Secondary *sessionKey `json:"secondary,omitempty"`
}

type sessionKey struct {
	RawKey  []byte    `json:"key"`
	Expires time.Time `json:"expires"`
}

func newSessionKey(expires time.Time) (sessionKey, error) {
	k := sessionKey{
		RawKey:  make([]byte, 32),
		Expires: expires,
	}
	if _, err := rand.Read(k.RawKey); err != nil {
		return sessionKey{}, fmt.Errorf("generate session key: %v", err)
	}
	return k, nil
}

func (k *sessionKey) Key() *[32]byte {
	if k == nil || len(k.RawKey) != 32 {
		return nil
	}
	arr := new([32]byte)
	copy((*arr)[:], k.RawKey)
	return arr
}
<|endoftext|>


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

package set

// Set is a set of integer identifiers.
type Set map[int]struct{}

// For cleanliness
var flag struct{} = struct{}{}

func NewSet() *Set {
	s := make(Set)
	return &s
}

func (s1 *Set) Clear() *Set {
	if len(*s1) == 0 {
		return s1
	}

	*s1 = make(Set)

	return s1
}

// Ensures a perfect copy from s1 to dst (meaning the sets will be equal)
func (dst *Set) Copy(src *Set) *Set {
	if src == dst {
		return dst
	}

	d := *dst
	if len(d) > 0 {
		d = make(Set, len(*src))
	}

	for e := range *src {
		d[e] = flag
	}
	*dst = d

	return dst
}

// If every element in s1 is also in s2 (and vice versa), the sets are deemed equal.
func Equal(s1, s2 *Set) bool {
	if s1 == s2 {
		return true
	}
	s2m := *s2
	if len(*s1) != len(s2m) {
		return false
	}

	for e := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Takes the union of s1 and s2, and stores it in dst.
//
// The union of two sets, s1 and s2, is the set containing all the elements of each, for instance:
//
//     {a,b,c} UNION {d,e,f} = {a,b,c,d,e,f}
//
// Since sets may not have repetition, unions of two sets that overlap do not contain repeat
// elements, that is:
//
//     {a,b,c} UNION {b,c,d} = {a,b,c,d}
func (dst *Set) Union(s1, s2 *Set) *Set {
	if s1 == s2 {
		return dst.Copy(s1)
	}

	if s1 != dst && s2 != dst {
		dst.Clear()
	}

	d := *dst
	if dst != s1 {
		for e := range *s1 {
			d[e] = flag
		}
	}

	if dst != s2 {
		for e := range *s2 {
			d[e] = flag
		}
	}

	return dst
}

// Takes the intersection of s1 and s2, and stores it in dst
//
// The intersection of two sets, s1 and s2, is the set containing all the elements shared between
// the two sets, for instance:
//
//     {a,b,c} INTERSECT {b,c,d} = {b,c}
//
// The intersection between a set and itself is itself, and thus effectively a copy operation:
//
//     {a,b,c} INTERSECT {a,b,c} = {a,b,c}
//
// The intersection between two sets that share no elements is the empty set:
//
//     {a,b,c} INTERSECT {d,e,f} = {}
func (dst *Set) Intersection(s1, s2 *Set) *Set {
	var swap *Set

	if s1 == s2 {
		return dst.Copy(s1)
	}
	if s1 == dst {
		swap = s2
	} else if s2 == dst {
		swap = s1
	} else {
		dst.Clear()

		if len(*s1) > len(*s2) {
			s1, s2 = s2, s1
		}
		s2m := *s2
		d := *dst
		for e := range *s1 {
			if _, ok := s2m[e]; ok {
				d[e] = flag
			}
		}

		return dst
	}

	d := *dst
	s := *swap
	for e := range d {
		if _, ok := s[e]; !ok {
			delete(d, e)
		}
	}

	return dst
}

// Takes the difference (-) of s1 and s2 and stores it in dst.
//
// The difference (-) between two sets, s1 and s2, is all the elements in s1 that are NOT also
// in s2.
//
//     {a,b,c} - {b,c,d} = {a}
//
// The difference between two identical sets is the empty set:
//
//     {a,b,c} - {a,b,c} = {}
//
// The difference between two sets with no overlapping elements is s1:
//
//     {a,b,c} - {d,e,f} = {a,b,c}
//
// Implementation note: if dst == s2 (meaning they have identical pointers), a temporary set must
// be used to store the data and then copied over, thus s2.Diff(s1,s2) has an extra allocation and
// may cause worse performance in some cases.
func (dst *Set) Diff(s1, s2 *Set) *Set {
	if s1 == s2 {
		return dst.Clear()
	}

	if s2 == dst {
		tmp := NewSet()

		tmp.Diff(s1, s2)
		*dst = *tmp
		return dst
	}

	s2m := *s2
	if s1 == dst {
		d := *dst
		for e := range d {
			if _, ok := s2m[e]; ok {
				delete(d, e)
			}
		}
	} else {
		dst.Clear()
		d := *dst
		for e := range *s1 {
			if _, ok := s2m[e]; !ok {
				d[e] = flag
			}
		}
	}

	return dst
}

// Returns true if s1 is an improper subset of s2.
//
// An improper subset occurs when every element in s1 is also in s2 OR s1 and s2 are equal:
//
//     {a,b,c}   SUBSET {a,b,c} = true
//     {a,b}     SUBSET {a,b,c} = true
//     {c,d}     SUBSET {a,b,c} = false
//     {a,b,c,d} SUBSET {a,b,c} = false
//
// Special case: The empty set is a subset of everything:
//
// 	   {} SUBSET {a,b} = true
//     {} SUBSET {}    = true
//
// In the case where one needs to test if s1 is smaller than s2, but not equal, use ProperSubset.
func Subset(s1, s2 *Set) bool {
	if len(*s1) > len(*s2) {
		return false
	}
	if s1 == s2 || len(*s1) == 0 {
		return true
	}

	s2m := *s2
	for e, _ := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Returns true if s1 is a proper subset of s2.
// A proper subset is when every element of s1 is in s2, but s1 is smaller than s2 (i.e. they are
// not equal):
//
//     {a,b,c}   PROPER SUBSET {a,b,c} = false
//     {a,b}     PROPER SUBSET {a,b,c} = true
//     {c,d}     PROPER SUBSET {a,b,c} = false
//     {a,b,c,d} PROPER SUBSET {a,b,c} = false
//
// Special case: The empty set is a proper subset of everything (except itself):
//
//      {} PROPER SUBSET {a,b} = true
//      {} PROPER SUBSET {}    = false
//
// When equality is allowed, use Subset.
func ProperSubset(s1, s2 *Set) bool {
	if len(*s1) >= len(*s2) { // implicitly tests if s1 and s2 are both the empty set
		return false
	} else if len(*s1) == 0 {
		return true
	} // We can eschew the s1 == s2 because if they are the same their lens are equal anyway

	s2m := *s2
	for e, _ := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Returns true if e is an element of s.
func (s *Set) Contains(e int) bool {
	_, ok := (*s)[e]
	return ok
}

// Adds the element e to s1.
func (s1 *Set) Add(e int) {
	(*s1)[e] = flag
}

func (s1 *Set) AddAll(es ...int) {
	for _, e := range es {
		s1.Add(e)
	}
}

// Removes the element e from s1.
func (s1 *Set) Remove(e int) {
	delete(*s1, e)
}

// Returns the number of elements in s1.
func (s1 *Set) Cardinality() int {
	return len(*s1)
}

func (s1 *Set) Elements() []int {
	els := make([]int, 0, len(*s1))
	for e, _ := range *s1 {
		els = append(els, e)
	}

	return els
}
<commit_msg>Use struct{}{} instead of defined var<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package set

// Set is a set of integer identifiers.
type Set map[int]struct{}

func NewSet() *Set {
	s := make(Set)
	return &s
}

func (s1 *Set) Clear() *Set {
	if len(*s1) == 0 {
		return s1
	}

	*s1 = make(Set)

	return s1
}

// Ensures a perfect copy from s1 to dst (meaning the sets will be equal)
func (dst *Set) Copy(src *Set) *Set {
	if src == dst {
		return dst
	}

	d := *dst
	if len(d) > 0 {
		d = make(Set, len(*src))
	}

	for e := range *src {
		d[e] = struct{}{}
	}
	*dst = d

	return dst
}

// If every element in s1 is also in s2 (and vice versa), the sets are deemed equal.
func Equal(s1, s2 *Set) bool {
	if s1 == s2 {
		return true
	}
	s2m := *s2
	if len(*s1) != len(s2m) {
		return false
	}

	for e := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Takes the union of s1 and s2, and stores it in dst.
//
// The union of two sets, s1 and s2, is the set containing all the elements of each, for instance:
//
//     {a,b,c} UNION {d,e,f} = {a,b,c,d,e,f}
//
// Since sets may not have repetition, unions of two sets that overlap do not contain repeat
// elements, that is:
//
//     {a,b,c} UNION {b,c,d} = {a,b,c,d}
func (dst *Set) Union(s1, s2 *Set) *Set {
	if s1 == s2 {
		return dst.Copy(s1)
	}

	if s1 != dst && s2 != dst {
		dst.Clear()
	}

	d := *dst
	if dst != s1 {
		for e := range *s1 {
			d[e] = struct{}{}
		}
	}

	if dst != s2 {
		for e := range *s2 {
			d[e] = struct{}{}
		}
	}

	return dst
}

// Takes the intersection of s1 and s2, and stores it in dst
//
// The intersection of two sets, s1 and s2, is the set containing all the elements shared between
// the two sets, for instance:
//
//     {a,b,c} INTERSECT {b,c,d} = {b,c}
//
// The intersection between a set and itself is itself, and thus effectively a copy operation:
//
//     {a,b,c} INTERSECT {a,b,c} = {a,b,c}
//
// The intersection between two sets that share no elements is the empty set:
//
//     {a,b,c} INTERSECT {d,e,f} = {}
func (dst *Set) Intersection(s1, s2 *Set) *Set {
	var swap *Set

	if s1 == s2 {
		return dst.Copy(s1)
	}
	if s1 == dst {
		swap = s2
	} else if s2 == dst {
		swap = s1
	} else {
		dst.Clear()

		if len(*s1) > len(*s2) {
			s1, s2 = s2, s1
		}
		s2m := *s2
		d := *dst
		for e := range *s1 {
			if _, ok := s2m[e]; ok {
				d[e] = struct{}{}
			}
		}

		return dst
	}

	d := *dst
	s := *swap
	for e := range d {
		if _, ok := s[e]; !ok {
			delete(d, e)
		}
	}

	return dst
}

// Takes the difference (-) of s1 and s2 and stores it in dst.
//
// The difference (-) between two sets, s1 and s2, is all the elements in s1 that are NOT also
// in s2.
//
//     {a,b,c} - {b,c,d} = {a}
//
// The difference between two identical sets is the empty set:
//
//     {a,b,c} - {a,b,c} = {}
//
// The difference between two sets with no overlapping elements is s1:
//
//     {a,b,c} - {d,e,f} = {a,b,c}
//
// Implementation note: if dst == s2 (meaning they have identical pointers), a temporary set must
// be used to store the data and then copied over, thus s2.Diff(s1,s2) has an extra allocation and
// may cause worse performance in some cases.
func (dst *Set) Diff(s1, s2 *Set) *Set {
	if s1 == s2 {
		return dst.Clear()
	}

	if s2 == dst {
		tmp := NewSet()

		tmp.Diff(s1, s2)
		*dst = *tmp
		return dst
	}

	s2m := *s2
	if s1 == dst {
		d := *dst
		for e := range d {
			if _, ok := s2m[e]; ok {
				delete(d, e)
			}
		}
	} else {
		dst.Clear()
		d := *dst
		for e := range *s1 {
			if _, ok := s2m[e]; !ok {
				d[e] = struct{}{}
			}
		}
	}

	return dst
}

// Returns true if s1 is an improper subset of s2.
//
// An improper subset occurs when every element in s1 is also in s2 OR s1 and s2 are equal:
//
//     {a,b,c}   SUBSET {a,b,c} = true
//     {a,b}     SUBSET {a,b,c} = true
//     {c,d}     SUBSET {a,b,c} = false
//     {a,b,c,d} SUBSET {a,b,c} = false
//
// Special case: The empty set is a subset of everything:
//
// 	   {} SUBSET {a,b} = true
//     {} SUBSET {}    = true
//
// In the case where one needs to test if s1 is smaller than s2, but not equal, use ProperSubset.
func Subset(s1, s2 *Set) bool {
	if len(*s1) > len(*s2) {
		return false
	}
	if s1 == s2 || len(*s1) == 0 {
		return true
	}

	s2m := *s2
	for e, _ := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Returns true if s1 is a proper subset of s2.
// A proper subset is when every element of s1 is in s2, but s1 is smaller than s2 (i.e. they are
// not equal):
//
//     {a,b,c}   PROPER SUBSET {a,b,c} = false
//     {a,b}     PROPER SUBSET {a,b,c} = true
//     {c,d}     PROPER SUBSET {a,b,c} = false
//     {a,b,c,d} PROPER SUBSET {a,b,c} = false
//
// Special case: The empty set is a proper subset of everything (except itself):
//
//      {} PROPER SUBSET {a,b} = true
//      {} PROPER SUBSET {}    = false
//
// When equality is allowed, use Subset.
func ProperSubset(s1, s2 *Set) bool {
	if len(*s1) >= len(*s2) { // implicitly tests if s1 and s2 are both the empty set
		return false
	} else if len(*s1) == 0 {
		return true
	} // We can eschew the s1 == s2 because if they are the same their lens are equal anyway

	s2m := *s2
	for e, _ := range *s1 {
		if _, ok := s2m[e]; !ok {
			return false
		}
	}

	return true
}

// Returns true if e is an element of s.
func (s *Set) Contains(e int) bool {
	_, ok := (*s)[e]
	return ok
}

// Adds the element e to s1.
func (s1 *Set) Add(e int) {
	(*s1)[e] = struct{}{}
}

func (s1 *Set) AddAll(es ...int) {
	for _, e := range es {
		s1.Add(e)
	}
}

// Removes the element e from s1.
func (s1 *Set) Remove(e int) {
	delete(*s1, e)
}

// Returns the number of elements in s1.
func (s1 *Set) Cardinality() int {
	return len(*s1)
}

func (s1 *Set) Elements() []int {
	els := make([]int, 0, len(*s1))
	for e, _ := range *s1 {
		els = append(els, e)
	}

	return els
}
<|endoftext|>


<commit_before>package movingmedian

import "container/heap"

type item struct {
	f         float64
	heapIndex int
}

type itemHeap []*item

func (h itemHeap) Len() int { return len(h) }
func (h itemHeap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].heapIndex = i
	h[j].heapIndex = j
}

func (h *itemHeap) Push(x interface{}) {
	e := x.(*item)
	e.heapIndex = len(*h)
	*h = append(*h, e)
}

func (h *itemHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minItemHeap struct {
	itemHeap
}

func (h minItemHeap) Less(i, j int) bool { return h.itemHeap[i].f < h.itemHeap[j].f }

type maxItemHeap struct {
	itemHeap
}

func (h maxItemHeap) Less(i, j int) bool { return h.itemHeap[i].f > h.itemHeap[j].f }

type MovingMedian struct {
	queueIndex int
	nitems     int
	queue      []item
	maxHeap    maxItemHeap
	minHeap    minItemHeap
}

func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]item, size),
		maxHeap: maxItemHeap{},
		minHeap: minItemHeap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

func (m *MovingMedian) Push(v float64) {
	if len(m.queue) == 1 {
		m.queue[0].f = v
		return
	}

	itemPtr := &m.queue[m.queueIndex]
	m.queueIndex++
	if m.queueIndex >= len(m.queue) {
		m.queueIndex = 0
	}

	minHeapLen := m.minHeap.Len()
	if m.nitems == len(m.queue) {
		if itemPtr.heapIndex < minHeapLen && itemPtr == m.minHeap.itemHeap[itemPtr.heapIndex] {
			if v >= m.maxHeap.itemHeap[0].f {
				itemPtr.f = v
				heap.Fix(&m.minHeap, itemPtr.heapIndex)
				return
			}

			moveItem := m.maxHeap.itemHeap[0]
			moveItem.heapIndex = itemPtr.heapIndex
			m.minHeap.itemHeap[itemPtr.heapIndex] = moveItem
			itemPtr.f = v
			m.maxHeap.itemHeap[0] = itemPtr

			heap.Fix(&m.minHeap, itemPtr.heapIndex)
			itemPtr.heapIndex = 0
			heap.Fix(&m.maxHeap, 0)
			return
		} else {
			if v <= m.minHeap.itemHeap[0].f {
				itemPtr.f = v
				heap.Fix(&m.maxHeap, itemPtr.heapIndex)
				return
			}

			moveItem := m.minHeap.itemHeap[0]
			moveItem.heapIndex = itemPtr.heapIndex
			m.maxHeap.itemHeap[itemPtr.heapIndex] = moveItem
			itemPtr.f = v
			m.minHeap.itemHeap[0] = itemPtr

			heap.Fix(&m.maxHeap, itemPtr.heapIndex)
			itemPtr.heapIndex = 0
			heap.Fix(&m.minHeap, 0)
			return
		}
	}

	m.nitems++
	itemPtr.f = v
	if minHeapLen == 0 {
		heap.Push(&m.minHeap, itemPtr)
	} else if v > m.minHeap.itemHeap[0].f {
		heap.Push(&m.minHeap, itemPtr)
		if minHeapLen > m.maxHeap.Len() {
			moveItem := heap.Pop(&m.minHeap)
			heap.Push(&m.maxHeap, moveItem)
		}
	} else {
		heap.Push(&m.maxHeap, itemPtr)
		if m.maxHeap.Len() == (minHeapLen + 2) {
			moveItem := heap.Pop(&m.maxHeap)
			heap.Push(&m.minHeap, moveItem)
		}
	}
}

func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 1 {
		return m.queue[0].f
	}

	if m.maxHeap.Len() == m.minHeap.Len() {
		return (m.maxHeap.itemHeap[0].f + m.minHeap.itemHeap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.itemHeap[0].f
	}

	return m.minHeap.itemHeap[0].f
}
<commit_msg>refactor itemPtr.f = v reduced 1 line of code<commit_after>package movingmedian

import "container/heap"

type item struct {
	f         float64
	heapIndex int
}

type itemHeap []*item

func (h itemHeap) Len() int { return len(h) }
func (h itemHeap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].heapIndex = i
	h[j].heapIndex = j
}

func (h *itemHeap) Push(x interface{}) {
	e := x.(*item)
	e.heapIndex = len(*h)
	*h = append(*h, e)
}

func (h *itemHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minItemHeap struct {
	itemHeap
}

func (h minItemHeap) Less(i, j int) bool { return h.itemHeap[i].f < h.itemHeap[j].f }

type maxItemHeap struct {
	itemHeap
}

func (h maxItemHeap) Less(i, j int) bool { return h.itemHeap[i].f > h.itemHeap[j].f }

type MovingMedian struct {
	queueIndex int
	nitems     int
	queue      []item
	maxHeap    maxItemHeap
	minHeap    minItemHeap
}

func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]item, size),
		maxHeap: maxItemHeap{},
		minHeap: minItemHeap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

func (m *MovingMedian) Push(v float64) {
	if len(m.queue) == 1 {
		m.queue[0].f = v
		return
	}

	itemPtr := &m.queue[m.queueIndex]
	m.queueIndex++
	if m.queueIndex >= len(m.queue) {
		m.queueIndex = 0
	}

	if m.nitems == len(m.queue) {
		minAbove := m.minHeap.itemHeap[0].f
		maxBelow := m.maxHeap.itemHeap[0].f
		itemPtr.f = v
		if itemPtr.heapIndex < m.minHeap.Len() && itemPtr == m.minHeap.itemHeap[itemPtr.heapIndex] {
			if v >= maxBelow {
				heap.Fix(&m.minHeap, itemPtr.heapIndex)
				return
			}

			moveItem := m.maxHeap.itemHeap[0]
			moveItem.heapIndex = itemPtr.heapIndex
			m.minHeap.itemHeap[itemPtr.heapIndex] = moveItem
			m.maxHeap.itemHeap[0] = itemPtr
			heap.Fix(&m.minHeap, itemPtr.heapIndex)
			itemPtr.heapIndex = 0
			heap.Fix(&m.maxHeap, 0)
			return
		}

		if v <= minAbove {
			heap.Fix(&m.maxHeap, itemPtr.heapIndex)
			return
		}

		moveItem := m.minHeap.itemHeap[0]
		moveItem.heapIndex = itemPtr.heapIndex
		m.maxHeap.itemHeap[itemPtr.heapIndex] = moveItem
		m.minHeap.itemHeap[0] = itemPtr
		heap.Fix(&m.maxHeap, itemPtr.heapIndex)
		itemPtr.heapIndex = 0
		heap.Fix(&m.minHeap, 0)
		return
	}

	m.nitems++
	itemPtr.f = v
	minHeapLen := m.minHeap.Len()
	if minHeapLen == 0 {
		heap.Push(&m.minHeap, itemPtr)
	} else if v > m.minHeap.itemHeap[0].f {
		heap.Push(&m.minHeap, itemPtr)
		if minHeapLen > m.maxHeap.Len() {
			moveItem := heap.Pop(&m.minHeap)
			heap.Push(&m.maxHeap, moveItem)
		}
	} else {
		heap.Push(&m.maxHeap, itemPtr)
		if m.maxHeap.Len() == (minHeapLen + 2) {
			moveItem := heap.Pop(&m.maxHeap)
			heap.Push(&m.minHeap, moveItem)
		}
	}
}

func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 1 {
		return m.queue[0].f
	}

	if m.maxHeap.Len() == m.minHeap.Len() {
		return (m.maxHeap.itemHeap[0].f + m.minHeap.itemHeap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.itemHeap[0].f
	}

	return m.minHeap.itemHeap[0].f
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire_test

import (
	"bytes"
	"github.com/conformal/btcwire"
	"github.com/davecgh/go-spew/spew"
	"io"
	"reflect"
	"testing"
)

// TestPongLatest tests the MsgPong API against the latest protocol version.
func TestPongLatest(t *testing.T) {
	pver := btcwire.ProtocolVersion

	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("RandomUint64: error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("NewMsgPong: wrong nonce - got %v, want %v",
			msg.Nonce, nonce)
	}

	// Ensure the command is expected value.
	wantCmd := "pong"
	if cmd := msg.Command(); cmd != wantCmd {
		t.Errorf("NewMsgPong: wrong command - got %v want %v",
			cmd, wantCmd)
	}

	// Ensure max payload is expected value for latest protocol version.
	wantPayload := uint32(8)
	maxPayload := msg.MaxPayloadLength(pver)
	if maxPayload != wantPayload {
		t.Errorf("MaxPayloadLength: wrong max payload length for "+
			"protocol version %d - got %v, want %v", pver,
			maxPayload, wantPayload)
	}

	// Test encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err != nil {
		t.Errorf("encode of MsgPong failed %v err <%v>", msg, err)
	}

	// Test decode with latest protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, pver)
	if err != nil {
		t.Errorf("decode of MsgPong failed [%v] err <%v>", buf, err)
	}

	// Ensure nonce is the same.
	if msg.Nonce != readmsg.Nonce {
		t.Errorf("Should get same nonce for protocol version %d", pver)
	}

	return
}

// TestPongBIP0031 tests the MsgPong API against the protocol version
// BIP0031Version.
func TestPongBIP0031(t *testing.T) {
	// Use the protocol version just prior to BIP0031Version changes.
	pver := btcwire.BIP0031Version

	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("Error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("Should get same nonce back out.")
	}

	// Ensure max payload is expected value for old protocol version.
	size := msg.MaxPayloadLength(pver)
	if size != 0 {
		t.Errorf("Max length should be 0 for pong protocol version %d.",
			pver)
	}

	// Test encode with old protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgPong succeeded when it shouldn't have %v",
			msg)
	}

	// Test decode with old protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, pver)
	if err == nil {
		t.Errorf("decode of MsgPong succeeded when it shouldn't have",
			spew.Sdump(buf))
	}

	// Since this protocol version doesn't support pong, make sure the
	// nonce didn't get encoded and decoded back out.
	if msg.Nonce == readmsg.Nonce {
		t.Errorf("Should not get same nonce for protocol version %d", pver)
	}

	return
}

// TestPongCrossProtocol tests the MsgPong API when encoding with the latest
// protocol version and decoded with BIP0031Version.
func TestPongCrossProtocol(t *testing.T) {
	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("Error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("Should get same nonce back out.")
	}

	// Encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, btcwire.ProtocolVersion)
	if err != nil {
		t.Errorf("encode of MsgPong failed %v err <%v>", msg, err)
	}

	// Decode with old protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
	if err == nil {
		t.Errorf("encode of MsgPong succeeded when it shouldn't have %v",
			msg)
	}

	// Since one of the protocol versions doesn't support the pong message,
	// make  sure the nonce didn't get encoded and decoded back out.
	if msg.Nonce == readmsg.Nonce {
		t.Error("Should not get same nonce for cross protocol")
	}
}

// TestPongWire tests the MsgPong wire encode and decode for various protocol
// versions.
func TestPongWire(t *testing.T) {
	tests := []struct {
		in   btcwire.MsgPong // Message to encode
		out  btcwire.MsgPong // Expected decoded message
		buf  []byte          // Wire encoding
		pver uint32          // Protocol version for wire encoding
	}{
		// Latest protocol version.
		{
			btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3
			btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3
			[]byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
			btcwire.ProtocolVersion,
		},

		// Protocol version BIP0031Version+1
		{
			btcwire.MsgPong{Nonce: 456456}, // 0x6f708
			btcwire.MsgPong{Nonce: 456456}, // 0x6f708
			[]byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00},
			btcwire.BIP0031Version + 1,
		},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		// Encode the message to wire format.
		var buf bytes.Buffer
		err := test.in.BtcEncode(&buf, test.pver)
		if err != nil {
			t.Errorf("BtcEncode #%d error %v", i, err)
			continue
		}
		if !bytes.Equal(buf.Bytes(), test.buf) {
			t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
				spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
			continue
		}

		// Decode the message from wire format.
		var msg btcwire.MsgPong
		rbuf := bytes.NewBuffer(test.buf)
		err = msg.BtcDecode(rbuf, test.pver)
		if err != nil {
			t.Errorf("BtcDecode #%d error %v", i, err)
			continue
		}
		if !reflect.DeepEqual(msg, test.out) {
			t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
				spew.Sdump(msg), spew.Sdump(test.out))
			continue
		}
	}
}

// TestPongWireErrors performs negative tests against wire encode and decode
// of MsgPong to confirm error paths work correctly.
func TestPongWireErrors(t *testing.T) {
	pver := btcwire.ProtocolVersion
	pverNoPong := btcwire.BIP0031Version
	btcwireErr := &btcwire.MessageError{}

	basePong := btcwire.NewMsgPong(123123) // 0x1e0f3
	basePongEncoded := []byte{
		0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
	}

	tests := []struct {
		in       *btcwire.MsgPong // Value to encode
		buf      []byte           // Wire encoding
		pver     uint32           // Protocol version for wire encoding
		max      int              // Max size of fixed buffer to induce errors
		writeErr error            // Expected write error
		readErr  error            // Expected read error
	}{
		// Latest protocol version with intentional read/write errors.
		// Force error in nonce.
		{basePong, basePongEncoded, pver, 0, io.ErrShortWrite, io.EOF},
		// Force error due to unsupported protocol version.
		{basePong, basePongEncoded, pverNoPong, 4, btcwireErr, btcwireErr},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		// Encode to wire format.
		w := newFixedWriter(test.max)
		err := test.in.BtcEncode(w, test.pver)
		if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
			t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
				i, err, test.writeErr)
			continue
		}

		// For errors which are not of type btcwire.MessageError, check
		// them for equality.
		if _, ok := err.(*btcwire.MessageError); !ok {
			if err != test.writeErr {
				t.Errorf("BtcEncode #%d wrong error got: %v, "+
					"want: %v", i, err, test.writeErr)
				continue
			}
		}

		// Decode from wire format.
		var msg btcwire.MsgPong
		r := newFixedReader(test.max, test.buf)
		err = msg.BtcDecode(r, test.pver)
		if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
			t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
				i, err, test.readErr)
			continue
		}

		// For errors which are not of type btcwire.MessageError, check
		// them for equality.
		if _, ok := err.(*btcwire.MessageError); !ok {
			if err != test.readErr {
				t.Errorf("BtcDecode #%d wrong error got: %v, "+
					"want: %v", i, err, test.readErr)
				continue
			}
		}

	}
}
<commit_msg>Add format specifier in pong test error output.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire_test

import (
	"bytes"
	"github.com/conformal/btcwire"
	"github.com/davecgh/go-spew/spew"
	"io"
	"reflect"
	"testing"
)

// TestPongLatest tests the MsgPong API against the latest protocol version.
func TestPongLatest(t *testing.T) {
	pver := btcwire.ProtocolVersion

	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("RandomUint64: error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("NewMsgPong: wrong nonce - got %v, want %v",
			msg.Nonce, nonce)
	}

	// Ensure the command is expected value.
	wantCmd := "pong"
	if cmd := msg.Command(); cmd != wantCmd {
		t.Errorf("NewMsgPong: wrong command - got %v want %v",
			cmd, wantCmd)
	}

	// Ensure max payload is expected value for latest protocol version.
	wantPayload := uint32(8)
	maxPayload := msg.MaxPayloadLength(pver)
	if maxPayload != wantPayload {
		t.Errorf("MaxPayloadLength: wrong max payload length for "+
			"protocol version %d - got %v, want %v", pver,
			maxPayload, wantPayload)
	}

	// Test encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err != nil {
		t.Errorf("encode of MsgPong failed %v err <%v>", msg, err)
	}

	// Test decode with latest protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, pver)
	if err != nil {
		t.Errorf("decode of MsgPong failed [%v] err <%v>", buf, err)
	}

	// Ensure nonce is the same.
	if msg.Nonce != readmsg.Nonce {
		t.Errorf("Should get same nonce for protocol version %d", pver)
	}

	return
}

// TestPongBIP0031 tests the MsgPong API against the protocol version
// BIP0031Version.
func TestPongBIP0031(t *testing.T) {
	// Use the protocol version just prior to BIP0031Version changes.
	pver := btcwire.BIP0031Version

	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("Error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("Should get same nonce back out.")
	}

	// Ensure max payload is expected value for old protocol version.
	size := msg.MaxPayloadLength(pver)
	if size != 0 {
		t.Errorf("Max length should be 0 for pong protocol version %d.",
			pver)
	}

	// Test encode with old protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgPong succeeded when it shouldn't have %v",
			msg)
	}

	// Test decode with old protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, pver)
	if err == nil {
		t.Errorf("decode of MsgPong succeeded when it shouldn't have %v",
			spew.Sdump(buf))
	}

	// Since this protocol version doesn't support pong, make sure the
	// nonce didn't get encoded and decoded back out.
	if msg.Nonce == readmsg.Nonce {
		t.Errorf("Should not get same nonce for protocol version %d", pver)
	}

	return
}

// TestPongCrossProtocol tests the MsgPong API when encoding with the latest
// protocol version and decoded with BIP0031Version.
func TestPongCrossProtocol(t *testing.T) {
	nonce, err := btcwire.RandomUint64()
	if err != nil {
		t.Errorf("Error generating nonce: %v", err)
	}
	msg := btcwire.NewMsgPong(nonce)
	if msg.Nonce != nonce {
		t.Errorf("Should get same nonce back out.")
	}

	// Encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, btcwire.ProtocolVersion)
	if err != nil {
		t.Errorf("encode of MsgPong failed %v err <%v>", msg, err)
	}

	// Decode with old protocol version.
	readmsg := btcwire.NewMsgPong(0)
	err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
	if err == nil {
		t.Errorf("encode of MsgPong succeeded when it shouldn't have %v",
			msg)
	}

	// Since one of the protocol versions doesn't support the pong message,
	// make  sure the nonce didn't get encoded and decoded back out.
	if msg.Nonce == readmsg.Nonce {
		t.Error("Should not get same nonce for cross protocol")
	}
}

// TestPongWire tests the MsgPong wire encode and decode for various protocol
// versions.
func TestPongWire(t *testing.T) {
	tests := []struct {
		in   btcwire.MsgPong // Message to encode
		out  btcwire.MsgPong // Expected decoded message
		buf  []byte          // Wire encoding
		pver uint32          // Protocol version for wire encoding
	}{
		// Latest protocol version.
		{
			btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3
			btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3
			[]byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
			btcwire.ProtocolVersion,
		},

		// Protocol version BIP0031Version+1
		{
			btcwire.MsgPong{Nonce: 456456}, // 0x6f708
			btcwire.MsgPong{Nonce: 456456}, // 0x6f708
			[]byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00},
			btcwire.BIP0031Version + 1,
		},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		// Encode the message to wire format.
		var buf bytes.Buffer
		err := test.in.BtcEncode(&buf, test.pver)
		if err != nil {
			t.Errorf("BtcEncode #%d error %v", i, err)
			continue
		}
		if !bytes.Equal(buf.Bytes(), test.buf) {
			t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
				spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
			continue
		}

		// Decode the message from wire format.
		var msg btcwire.MsgPong
		rbuf := bytes.NewBuffer(test.buf)
		err = msg.BtcDecode(rbuf, test.pver)
		if err != nil {
			t.Errorf("BtcDecode #%d error %v", i, err)
			continue
		}
		if !reflect.DeepEqual(msg, test.out) {
			t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
				spew.Sdump(msg), spew.Sdump(test.out))
			continue
		}
	}
}

// TestPongWireErrors performs negative tests against wire encode and decode
// of MsgPong to confirm error paths work correctly.
func TestPongWireErrors(t *testing.T) {
	pver := btcwire.ProtocolVersion
	pverNoPong := btcwire.BIP0031Version
	btcwireErr := &btcwire.MessageError{}

	basePong := btcwire.NewMsgPong(123123) // 0x1e0f3
	basePongEncoded := []byte{
		0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
	}

	tests := []struct {
		in       *btcwire.MsgPong // Value to encode
		buf      []byte           // Wire encoding
		pver     uint32           // Protocol version for wire encoding
		max      int              // Max size of fixed buffer to induce errors
		writeErr error            // Expected write error
		readErr  error            // Expected read error
	}{
		// Latest protocol version with intentional read/write errors.
		// Force error in nonce.
		{basePong, basePongEncoded, pver, 0, io.ErrShortWrite, io.EOF},
		// Force error due to unsupported protocol version.
		{basePong, basePongEncoded, pverNoPong, 4, btcwireErr, btcwireErr},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		// Encode to wire format.
		w := newFixedWriter(test.max)
		err := test.in.BtcEncode(w, test.pver)
		if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
			t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
				i, err, test.writeErr)
			continue
		}

		// For errors which are not of type btcwire.MessageError, check
		// them for equality.
		if _, ok := err.(*btcwire.MessageError); !ok {
			if err != test.writeErr {
				t.Errorf("BtcEncode #%d wrong error got: %v, "+
					"want: %v", i, err, test.writeErr)
				continue
			}
		}

		// Decode from wire format.
		var msg btcwire.MsgPong
		r := newFixedReader(test.max, test.buf)
		err = msg.BtcDecode(r, test.pver)
		if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
			t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
				i, err, test.readErr)
			continue
		}

		// For errors which are not of type btcwire.MessageError, check
		// them for equality.
		if _, ok := err.(*btcwire.MessageError); !ok {
			if err != test.readErr {
				t.Errorf("BtcDecode #%d wrong error got: %v, "+
					"want: %v", i, err, test.readErr)
				continue
			}
		}

	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 enhancers

import (
	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/packet"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	graph.DefaultGraphListener
	Graph    *graph.Graph
	tidCache *tidCache
}

func (gfe *GraphFlowEnhancer) getNodeTID(mac string) string {
	if packet.IsBroadcastMac(mac) || packet.IsMulticastMac(mac) {
		return "*"
	}

	var ce *tidCacheEntry

	if gfe.tidCache != nil {
		var f bool
		if ce, f = gfe.tidCache.get(mac); f {
			return ce.tid
		}
	}

	gfe.Graph.RLock()
	defer gfe.Graph.RUnlock()

	var tid string

	intfs := gfe.Graph.GetNodes(graph.Metadata{"MAC": mac})
	if len(intfs) > 1 {
		logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
	} else if len(intfs) == 1 {
		tid, _ = intfs[0].GetFieldString("TID")
	}

	if gfe.tidCache != nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer set cache %s: %s", mac, tid)
		gfe.tidCache.set(ce, mac, tid)
	}

	return tid
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.Link == nil {
		return
	}
	if f.ANodeTID == "" {
		f.ANodeTID = gfe.getNodeTID(f.Link.A)
	}
	if f.BNodeTID == "" {
		f.BNodeTID = gfe.getNodeTID(f.Link.B)
	}
}

func (gfe *GraphFlowEnhancer) OnNodeDeleted(n *graph.Node) {
	if mac, err := n.GetFieldString("MAC"); err == nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer node event del cache %s", mac)
		gfe.tidCache.del(mac)
	}
}

func (gfe *GraphFlowEnhancer) OnEdgeDeleted(e *graph.Edge) {
	// need to reset the entry as edge event of type RelationType means TID update
	if rt, _ := e.GetFieldString("RelationType"); rt == topology.OwnershipLink {
		_, children := gfe.Graph.GetEdgeNodes(e, nil, nil)
		for _, child := range children {
			if mac, err := child.GetFieldString("MAC"); err == nil {
				logging.GetLogger().Debugf("GraphFlowEnhancer edge event del cache %s", mac)
				gfe.tidCache.del(mac)
			}
		}
	}
}

func NewGraphFlowEnhancer(g *graph.Graph, cache *cache.Cache) *GraphFlowEnhancer {
	fe := &GraphFlowEnhancer{
		Graph: g,
	}
	g.AddEventListener(fe)

	if cache != nil {
		fe.tidCache = &tidCache{cache}
	}

	return fe
}
<commit_msg>flow: enhancer check mac not empty instead of key existing<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 enhancers

import (
	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/packet"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	graph.DefaultGraphListener
	Graph    *graph.Graph
	tidCache *tidCache
}

func (gfe *GraphFlowEnhancer) getNodeTID(mac string) string {
	if packet.IsBroadcastMac(mac) || packet.IsMulticastMac(mac) {
		return "*"
	}

	var ce *tidCacheEntry

	if gfe.tidCache != nil {
		var f bool
		if ce, f = gfe.tidCache.get(mac); f {
			return ce.tid
		}
	}

	gfe.Graph.RLock()
	defer gfe.Graph.RUnlock()

	var tid string

	intfs := gfe.Graph.GetNodes(graph.Metadata{"MAC": mac})
	if len(intfs) > 1 {
		logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
	} else if len(intfs) == 1 {
		tid, _ = intfs[0].GetFieldString("TID")
	}

	if gfe.tidCache != nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer set cache %s: %s", mac, tid)
		gfe.tidCache.set(ce, mac, tid)
	}

	return tid
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.Link == nil {
		return
	}
	if f.ANodeTID == "" {
		f.ANodeTID = gfe.getNodeTID(f.Link.A)
	}
	if f.BNodeTID == "" {
		f.BNodeTID = gfe.getNodeTID(f.Link.B)
	}
}

func (gfe *GraphFlowEnhancer) OnNodeDeleted(n *graph.Node) {
	if mac, _ := n.GetFieldString("MAC"); mac != "" {
		logging.GetLogger().Debugf("GraphFlowEnhancer node event del cache %s", n.String())
		gfe.tidCache.del(mac)
	}
}

func (gfe *GraphFlowEnhancer) OnEdgeDeleted(e *graph.Edge) {
	// need to reset the entry as edge event of type RelationType means TID update
	if rt, _ := e.GetFieldString("RelationType"); rt == topology.OwnershipLink {
		_, children := gfe.Graph.GetEdgeNodes(e, nil, nil)
		for _, child := range children {
			if mac, _ := child.GetFieldString("MAC"); mac != "" {
				logging.GetLogger().Debugf("GraphFlowEnhancer edge event del cache %s", child.String())
				gfe.tidCache.del(mac)
			}
		}
	}
}

func NewGraphFlowEnhancer(g *graph.Graph, cache *cache.Cache) *GraphFlowEnhancer {
	fe := &GraphFlowEnhancer{
		Graph: g,
	}
	g.AddEventListener(fe)

	if cache != nil {
		fe.tidCache = &tidCache{cache}
	}

	return fe
}
<|endoftext|>


<commit_before>package currency

import (
	"encoding/xml"
	"github.com/mbanzon/simplehttp"
	"time"
)

const (
	ecbResourceUrl = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
	dateFormat     = "2006-01-02"
)

type currencyEnvelope struct {
	Sender string `xml:"Sender>name"`
	Cube   []cube `xml:"Cube>Cube>Cube"`
}

type timeEnvelope struct {
	Time timeCube `xml:"Cube>Cube"`
}

// structure used for parsing the time.
type timeCube struct {
	Time string `xml:"time,attr"`
}

// structure used for parsing the currencies.
type cube struct {
	Name string  `xml:"currency,attr"`
	Rate float64 `xml:"rate,attr"`
}

func parseEcbData() (time.Time, map[string]float64, error) {
	r := simplehttp.NewGetRequest(ecbResourceUrl)
	data, err := r.MakeRequest()
	if err != nil {
		return time.Time{}, nil, err
	}

	var c currencyEnvelope
	err = xml.Unmarshal(data, &c) // first unmarshal to get currencies
	if err != nil {
		return time.Time{}, nil, err
	}

	var t timeEnvelope
	err = xml.Unmarshal(data, &t) // second unmarshal to get time
	if err != nil {
		return time.Time{}, nil, err
	}

	currencyTime, err := time.Parse(dateFormat, t.Time.Time)
	if err != nil {
		return time.Time{}, nil, err
	}

	currencies := make(map[string]float64)

	currencies[eur] = 1

	for _, currency := range c.Cube {
		currencies[currency.Name] = currency.Rate
	}

	return currencyTime, currencies, nil
}
<commit_msg>Comment.<commit_after>package currency

import (
	"encoding/xml"
	"github.com/mbanzon/simplehttp"
	"time"
)

const (
	ecbResourceUrl = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
	dateFormat     = "2006-01-02"
)

// Structure for getting the currencies out of the nested cube elements.
type currencyEnvelope struct {
	Sender string `xml:"Sender>name"`
	Cube   []cube `xml:"Cube>Cube>Cube"`
}

type timeEnvelope struct {
	Time timeCube `xml:"Cube>Cube"`
}

// structure used for parsing the time.
type timeCube struct {
	Time string `xml:"time,attr"`
}

// structure used for parsing the currencies.
type cube struct {
	Name string  `xml:"currency,attr"`
	Rate float64 `xml:"rate,attr"`
}

func parseEcbData() (time.Time, map[string]float64, error) {
	r := simplehttp.NewGetRequest(ecbResourceUrl)
	data, err := r.MakeRequest()
	if err != nil {
		return time.Time{}, nil, err
	}

	var c currencyEnvelope
	err = xml.Unmarshal(data, &c) // first unmarshal to get currencies
	if err != nil {
		return time.Time{}, nil, err
	}

	var t timeEnvelope
	err = xml.Unmarshal(data, &t) // second unmarshal to get time
	if err != nil {
		return time.Time{}, nil, err
	}

	currencyTime, err := time.Parse(dateFormat, t.Time.Time)
	if err != nil {
		return time.Time{}, nil, err
	}

	currencies := make(map[string]float64)

	currencies[eur] = 1

	for _, currency := range c.Cube {
		currencies[currency.Name] = currency.Rate
	}

	return currencyTime, currencies, nil
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"

	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"
)

type ServiceInstancesSummaries struct {
	Apps             []ServiceInstanceSummaryApp
	ServiceInstances []ServiceInstanceSummary `json:"services"`
}

func (resource ServiceInstancesSummaries) ToModels() (instances []models.ServiceInstance) {
	for _, instanceSummary := range resource.ServiceInstances {
		applicationNames := resource.findApplicationNamesForInstance(instanceSummary.Name)

		planSummary := instanceSummary.ServicePlan
		servicePlan := models.ServicePlanFields{}
		servicePlan.Name = planSummary.Name
		servicePlan.GUID = planSummary.GUID

		offeringSummary := planSummary.ServiceOffering
		serviceOffering := models.ServiceOfferingFields{}
		serviceOffering.Label = offeringSummary.Label
		serviceOffering.Provider = offeringSummary.Provider
		serviceOffering.Version = offeringSummary.Version

		instance := models.ServiceInstance{}
		instance.Name = instanceSummary.Name
		instance.LastOperation.Type = instanceSummary.LastOperation.Type
		instance.LastOperation.State = instanceSummary.LastOperation.State
		instance.LastOperation.Description = instanceSummary.LastOperation.Description
		instance.ApplicationNames = applicationNames
		instance.ServicePlan = servicePlan
		instance.ServiceOffering = serviceOffering

		instances = append(instances, instance)
	}

	return
}

func (resource ServiceInstancesSummaries) findApplicationNamesForInstance(instanceName string) (applicationNames []string) {
	for _, app := range resource.Apps {
		for _, name := range app.ServiceNames {
			if name == instanceName {
				applicationNames = append(applicationNames, app.Name)
			}
		}
	}

	return
}

type ServiceInstanceSummaryApp struct {
	Name         string
	ServiceNames []string `json:"service_names"`
}

type LastOperationSummary struct {
	Type        string `json:"type"`
	State       string `json:"state"`
	Description string `json:"description"`
}

type ServiceInstanceSummary struct {
	Name          string
	LastOperation LastOperationSummary `json:"last_operation"`
	ServicePlan   ServicePlanSummary   `json:"service_plan"`
}

type ServicePlanSummary struct {
	Name            string
	GUID            string
	ServiceOffering ServiceOfferingSummary `json:"service"`
}

type ServiceOfferingSummary struct {
	Label    string
	Provider string
	Version  string
}

//go:generate counterfeiter . ServiceSummaryRepository

type ServiceSummaryRepository interface {
	GetSummariesInCurrentSpace() (instances []models.ServiceInstance, apiErr error)
}

type CloudControllerServiceSummaryRepository struct {
	config  coreconfig.Reader
	gateway net.Gateway
}

func NewCloudControllerServiceSummaryRepository(config coreconfig.Reader, gateway net.Gateway) (repo CloudControllerServiceSummaryRepository) {
	repo.config = config
	repo.gateway = gateway
	return
}

func (repo CloudControllerServiceSummaryRepository) GetSummariesInCurrentSpace() (instances []models.ServiceInstance, apiErr error) {
	path := fmt.Sprintf("%s/v2/spaces/%s/summary", repo.config.APIEndpoint(), repo.config.SpaceFields().GUID)
	resource := new(ServiceInstancesSummaries)

	apiErr = repo.gateway.GetResource(path, resource)
	if apiErr != nil {
		return
	}

	instances = resource.ToModels()

	return
}
<commit_msg>Remove naked returns<commit_after>package api

import (
	"fmt"

	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"
)

type ServiceInstancesSummaries struct {
	Apps             []ServiceInstanceSummaryApp
	ServiceInstances []ServiceInstanceSummary `json:"services"`
}

func (resource ServiceInstancesSummaries) ToModels() []models.ServiceInstance {
	var instances []models.ServiceInstance
	for _, instanceSummary := range resource.ServiceInstances {
		applicationNames := resource.findApplicationNamesForInstance(instanceSummary.Name)

		planSummary := instanceSummary.ServicePlan
		servicePlan := models.ServicePlanFields{}
		servicePlan.Name = planSummary.Name
		servicePlan.GUID = planSummary.GUID

		offeringSummary := planSummary.ServiceOffering
		serviceOffering := models.ServiceOfferingFields{}
		serviceOffering.Label = offeringSummary.Label
		serviceOffering.Provider = offeringSummary.Provider
		serviceOffering.Version = offeringSummary.Version

		instance := models.ServiceInstance{}
		instance.Name = instanceSummary.Name
		instance.LastOperation.Type = instanceSummary.LastOperation.Type
		instance.LastOperation.State = instanceSummary.LastOperation.State
		instance.LastOperation.Description = instanceSummary.LastOperation.Description
		instance.ApplicationNames = applicationNames
		instance.ServicePlan = servicePlan
		instance.ServiceOffering = serviceOffering

		instances = append(instances, instance)
	}

	return instances
}

func (resource ServiceInstancesSummaries) findApplicationNamesForInstance(instanceName string) []string {
	var applicationNames []string
	for _, app := range resource.Apps {
		for _, name := range app.ServiceNames {
			if name == instanceName {
				applicationNames = append(applicationNames, app.Name)
			}
		}
	}

	return applicationNames
}

type ServiceInstanceSummaryApp struct {
	Name         string
	ServiceNames []string `json:"service_names"`
}

type LastOperationSummary struct {
	Type        string `json:"type"`
	State       string `json:"state"`
	Description string `json:"description"`
}

type ServiceInstanceSummary struct {
	Name          string
	LastOperation LastOperationSummary `json:"last_operation"`
	ServicePlan   ServicePlanSummary   `json:"service_plan"`
}

type ServicePlanSummary struct {
	Name            string
	GUID            string
	ServiceOffering ServiceOfferingSummary `json:"service"`
}

type ServiceOfferingSummary struct {
	Label    string
	Provider string
	Version  string
}

//go:generate counterfeiter . ServiceSummaryRepository

type ServiceSummaryRepository interface {
	GetSummariesInCurrentSpace() ([]models.ServiceInstance, error)
}

type CloudControllerServiceSummaryRepository struct {
	config  coreconfig.Reader
	gateway net.Gateway
}

func NewCloudControllerServiceSummaryRepository(config coreconfig.Reader, gateway net.Gateway) CloudControllerServiceSummaryRepository {
	return CloudControllerServiceSummaryRepository{
		config:  config,
		gateway: gateway,
	}
}

func (repo CloudControllerServiceSummaryRepository) GetSummariesInCurrentSpace() ([]models.ServiceInstance, error) {
	var instances []models.ServiceInstance
	path := fmt.Sprintf("%s/v2/spaces/%s/summary", repo.config.APIEndpoint(), repo.config.SpaceFields().GUID)
	resource := new(ServiceInstancesSummaries)

	err := repo.gateway.GetResource(path, resource)
	if err != nil {
		return nil, err
	}

	instances = resource.ToModels()

	return instances, nil
}
<|endoftext|>


<commit_before>package chart

import (
	"bytes"
	"errors"
	"fmt"
	helm_chart "helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"
	"strings"
)

var (
	// Optr is a global chart operator instance
	Optr = NewOperator()
)

const (
	readmeFileName = "README.MD"
	valuesFileName = "VALUES.YAML"
)

// Operator ...
type Operator interface {
	// GetChartDetails parse the details from the provided content bytes
	GetDetails(content []byte) (*VersionDetails, error)
	// FetchLayer the content of layer under the repository
	GetData(content []byte) (*helm_chart.Chart, error)
}

var _ Operator = &operator{}

// ChartOperator is designed to process the contents of
// the specified chart version to get more details
type operator struct{}

// NewOperator returns an instance of the default chart opertaor
func NewOperator() Operator {
	return &operator{}
}

// GetDetails parse the details from the provided content bytes
func (cho *operator) GetDetails(content []byte) (*VersionDetails, error) {
	chartData, err := cho.GetData(content)
	if err != nil {
		return nil, err
	}

	// Parse the dependencies of chart
	depts := make([]*helm_chart.Dependency, 0)

	// for APIVersionV2, the dependency is in the Chart.yaml
	if chartData.Metadata.APIVersion == helm_chart.APIVersionV1 {
		depts = chartData.Metadata.Dependencies
	}

	var values map[string]interface{}
	files := make(map[string]string)
	// Parse values
	if chartData.Values != nil {
		readValue(values, "", chartData.Values)
	}

	// Append other files like 'README.md' 'values.yaml'
	for _, v := range chartData.Raw {
		if strings.ToUpper(v.Name) == readmeFileName {
			files[readmeFileName] = string(v.Data)
			break
		}
		if strings.ToUpper(v.Name) == valuesFileName {
			files[valuesFileName] = string(v.Data)
			break
		}
	}

	theChart := &VersionDetails{
		Dependencies: depts,
		Values:       values,
		Files:        files,
	}

	return theChart, nil
}

// GetData returns raw data of chart
func (cho *operator) GetData(content []byte) (*helm_chart.Chart, error) {
	if content == nil || len(content) == 0 {
		return nil, errors.New("zero content")
	}

	reader := bytes.NewReader(content)
	chartData, err := loader.LoadArchive(reader)
	if err != nil {
		return nil, err
	}

	return chartData, nil
}

// Recursively read value
func readValue(values map[string]interface{}, keyPrefix string, valueMap map[string]interface{}) {
	for key, value := range values {
		longKey := key
		if keyPrefix != "" {
			longKey = fmt.Sprintf("%s.%s", keyPrefix, key)
		}

		if subValues, ok := value.(map[string]interface{}); ok {
			readValue(subValues, longKey, valueMap)
		} else {
			valueMap[longKey] = value
		}
	}
}
<commit_msg>Fix bug when reading the readme.md of helm chart (#11059)<commit_after>package chart

import (
	"bytes"
	"errors"
	"fmt"
	helm_chart "helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"
	"strings"
)

var (
	// Optr is a global chart operator instance
	Optr = NewOperator()
)

const (
	readmeFileName = "README.MD"
	valuesFileName = "VALUES.YAML"
)

// Operator ...
type Operator interface {
	// GetChartDetails parse the details from the provided content bytes
	GetDetails(content []byte) (*VersionDetails, error)
	// FetchLayer the content of layer under the repository
	GetData(content []byte) (*helm_chart.Chart, error)
}

var _ Operator = &operator{}

// ChartOperator is designed to process the contents of
// the specified chart version to get more details
type operator struct{}

// NewOperator returns an instance of the default chart opertaor
func NewOperator() Operator {
	return &operator{}
}

// GetDetails parse the details from the provided content bytes
func (cho *operator) GetDetails(content []byte) (*VersionDetails, error) {
	chartData, err := cho.GetData(content)
	if err != nil {
		return nil, err
	}

	// Parse the dependencies of chart
	depts := make([]*helm_chart.Dependency, 0)

	// for APIVersionV2, the dependency is in the Chart.yaml
	if chartData.Metadata.APIVersion == helm_chart.APIVersionV1 {
		depts = chartData.Metadata.Dependencies
	}

	var values map[string]interface{}
	files := make(map[string]string)
	// Parse values
	if chartData.Values != nil {
		readValue(values, "", chartData.Values)
	}

	// Append other files like 'README.md' 'values.yaml'
	for _, v := range chartData.Raw {
		if strings.ToUpper(v.Name) == readmeFileName {
			files[readmeFileName] = string(v.Data)
			continue
		}
		if strings.ToUpper(v.Name) == valuesFileName {
			files[valuesFileName] = string(v.Data)
			continue
		}
	}

	theChart := &VersionDetails{
		Dependencies: depts,
		Values:       values,
		Files:        files,
	}

	return theChart, nil
}

// GetData returns raw data of chart
func (cho *operator) GetData(content []byte) (*helm_chart.Chart, error) {
	if content == nil || len(content) == 0 {
		return nil, errors.New("zero content")
	}

	reader := bytes.NewReader(content)
	chartData, err := loader.LoadArchive(reader)
	if err != nil {
		return nil, err
	}

	return chartData, nil
}

// Recursively read value
func readValue(values map[string]interface{}, keyPrefix string, valueMap map[string]interface{}) {
	for key, value := range values {
		longKey := key
		if keyPrefix != "" {
			longKey = fmt.Sprintf("%s.%s", keyPrefix, key)
		}

		if subValues, ok := value.(map[string]interface{}); ok {
			readValue(subValues, longKey, valueMap)
		} else {
			valueMap[longKey] = value
		}
	}
}
<|endoftext|>