<commit_before>package transition

import (
	"errors"
	"fmt"
	"time"

	"github.com/jinzhu/gorm"
)

type StateChangeLog struct {
	Id         uint64
	ReferTable string
	ReferId    string
	State      string
	Note       string
	CreatedAt  time.Time
	UpdatedAt  time.Time
	DeletedAt  time.Time
}

type Stater interface {
	SetState(name string)
	GetState() string
}

func New(value interface{}) *StateMachine {
	return &StateMachine{
		states: map[string]*State{},
		events: map[string]*Event{},
	}
}

type StateMachine struct {
	initialState string
	states       map[string]*State
	events       map[string]*Event
}

func (sm *StateMachine) Initial(name string) *StateMachine {
	sm.initialState = name
	return sm
}

func (sm *StateMachine) State(name string) *State {
	event := &State{Name: name}
	sm.states[name] = event
	return event
}

func (sm *StateMachine) Event(name string) *Event {
	event := &Event{Name: name}
	sm.events[name] = event
	return event
}

func (sm *StateMachine) To(name string, value Stater, tx *gorm.DB) error {
	stateWas := value.GetState()
	if stateWas == "" {
		stateWas = sm.initialState
	}

	newTx := tx.New()
	if event := sm.events[name]; event != nil {
		var matchedTransitions []*EventTransition
		for _, transition := range event.transitions {
			var validFrom = len(transition.froms) == 0
			if len(transition.froms) > 0 {
				for _, from := range transition.froms {
					if from == stateWas {
						validFrom = true
					}
				}
			}

			if validFrom {
				matchedTransitions = append(matchedTransitions, transition)
			}
		}

		if len(matchedTransitions) == 1 {
			transition := matchedTransitions[0]

			// State: exit
			if state, ok := sm.states[stateWas]; ok {
				for _, exit := range state.exits {
					if err := exit(value, newTx); err != nil {
						return err
					}
				}
			}

			// Transition: before
			for _, before := range transition.befores {
				if err := before(value, newTx); err != nil {
					return err
				}
			}

			value.SetState(name)

			// Transition: after
			for _, after := range transition.afters {
				if err := after(value, newTx); err != nil {
					return err
				}
			}

			scope := newTx.NewScope(value)
			primaryKey := fmt.Sprintf("%v", scope.PrimaryKeyValue())
			log := StateChangeLog{ReferTable: scope.TableName(), ReferId: primaryKey, State: name}
			return newTx.Save(&log).Error
		}
	}
	return errors.New("failed to perform")
}

type State struct {
	Name   string
	enters []func(value interface{}, tx *gorm.DB) error
	exits  []func(value interface{}, tx *gorm.DB) error
}

func (state *State) Enter(fc func(value interface{}, tx *gorm.DB) error) *State {
	state.enters = append(state.enters, fc)
	return state
}

func (state *State) Exit(fc func(value interface{}, tx *gorm.DB) error) *State {
	state.exits = append(state.exits, fc)
	return state
}

type Event struct {
	Name        string
	transitions []*EventTransition
}

func (event *Event) To(name string) *EventTransition {
	transition := &EventTransition{to: name}
	event.transitions = append(event.transitions, transition)
	return transition
}

type EventTransition struct {
	to      string
	froms   []string
	befores []func(value interface{}, tx *gorm.DB) error
	afters  []func(value interface{}, tx *gorm.DB) error
}

func (transition *EventTransition) From(states ...string) *EventTransition {
	transition.froms = states
	return transition
}

func (transition *EventTransition) Before(fc func(value interface{}, tx *gorm.DB) error) *EventTransition {
	transition.befores = append(transition.befores, fc)
	return transition
}

func (transition *EventTransition) After(fc func(value interface{}, tx *gorm.DB) error) *EventTransition {
	transition.afters = append(transition.afters, fc)
	return transition
}
<commit_msg>Add transition.Transition back<commit_after>package transition

import (
	"errors"
	"fmt"
	"time"

	"github.com/jinzhu/gorm"
)

type Transition struct {
	State           string
	StateChangeLogs []StateChangeLog `sql:"-"`
}

func (transition *Transition) SetState(name string) {
	transition.State = name
}

func (transition Transition) GetState() string {
	return transition.State
}

type StateChangeLog struct {
	Id         uint64
	ReferTable string
	ReferId    string
	State      string
	Note       string
	CreatedAt  time.Time
	UpdatedAt  time.Time
	DeletedAt  time.Time
}

type Stater interface {
	SetState(name string)
	GetState() string
}

func New(value interface{}) *StateMachine {
	return &StateMachine{
		states: map[string]*State{},
		events: map[string]*Event{},
	}
}

type StateMachine struct {
	initialState string
	states       map[string]*State
	events       map[string]*Event
}

func (sm *StateMachine) Initial(name string) *StateMachine {
	sm.initialState = name
	return sm
}

func (sm *StateMachine) State(name string) *State {
	event := &State{Name: name}
	sm.states[name] = event
	return event
}

func (sm *StateMachine) Event(name string) *Event {
	event := &Event{Name: name}
	sm.events[name] = event
	return event
}

func (sm *StateMachine) To(name string, value Stater, tx *gorm.DB) error {
	stateWas := value.GetState()
	if stateWas == "" {
		stateWas = sm.initialState
	}

	newTx := tx.New()
	if event := sm.events[name]; event != nil {
		var matchedTransitions []*EventTransition
		for _, transition := range event.transitions {
			var validFrom = len(transition.froms) == 0
			if len(transition.froms) > 0 {
				for _, from := range transition.froms {
					if from == stateWas {
						validFrom = true
					}
				}
			}

			if validFrom {
				matchedTransitions = append(matchedTransitions, transition)
			}
		}

		if len(matchedTransitions) == 1 {
			transition := matchedTransitions[0]

			// State: exit
			if state, ok := sm.states[stateWas]; ok {
				for _, exit := range state.exits {
					if err := exit(value, newTx); err != nil {
						return err
					}
				}
			}

			// Transition: before
			for _, before := range transition.befores {
				if err := before(value, newTx); err != nil {
					return err
				}
			}

			value.SetState(name)

			// Transition: after
			for _, after := range transition.afters {
				if err := after(value, newTx); err != nil {
					return err
				}
			}

			scope := newTx.NewScope(value)
			primaryKey := fmt.Sprintf("%v", scope.PrimaryKeyValue())
			log := StateChangeLog{ReferTable: scope.TableName(), ReferId: primaryKey, State: name}
			return newTx.Save(&log).Error
		}
	}
	return errors.New("failed to perform")
}

type State struct {
	Name   string
	enters []func(value interface{}, tx *gorm.DB) error
	exits  []func(value interface{}, tx *gorm.DB) error
}

func (state *State) Enter(fc func(value interface{}, tx *gorm.DB) error) *State {
	state.enters = append(state.enters, fc)
	return state
}

func (state *State) Exit(fc func(value interface{}, tx *gorm.DB) error) *State {
	state.exits = append(state.exits, fc)
	return state
}

type Event struct {
	Name        string
	transitions []*EventTransition
}

func (event *Event) To(name string) *EventTransition {
	transition := &EventTransition{to: name}
	event.transitions = append(event.transitions, transition)
	return transition
}

type EventTransition struct {
	to      string
	froms   []string
	befores []func(value interface{}, tx *gorm.DB) error
	afters  []func(value interface{}, tx *gorm.DB) error
}

func (transition *EventTransition) From(states ...string) *EventTransition {
	transition.froms = states
	return transition
}

func (transition *EventTransition) Before(fc func(value interface{}, tx *gorm.DB) error) *EventTransition {
	transition.befores = append(transition.befores, fc)
	return transition
}

func (transition *EventTransition) After(fc func(value interface{}, tx *gorm.DB) error) *EventTransition {
	transition.afters = append(transition.afters, fc)
	return transition
}
<|endoftext|>


<commit_before>package libp2pquic

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"

	ic "github.com/libp2p/go-libp2p-crypto"
	peer "github.com/libp2p/go-libp2p-peer"
	tpt "github.com/libp2p/go-libp2p-transport"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
	"github.com/whyrusleeping/mafmt"
)

var quicConfig = &quic.Config{
	MaxReceiveStreamFlowControlWindow:     3 * (1 << 20),   // 3 MB
	MaxReceiveConnectionFlowControlWindow: 4.5 * (1 << 20), // 4.5 MB
	Versions: []quic.VersionNumber{101},
	AcceptCookie: func(clientAddr net.Addr, cookie *quic.Cookie) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
}

var quicDialAddr = quic.DialAddr

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey   ic.PrivKey
	localPeer peer.ID
	tlsConf   *tls.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey) (tpt.Transport, error) {
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	tlsConf, err := generateConfig(key)
	if err != nil {
		return nil, err
	}
	return &transport{
		privKey:   key,
		localPeer: localPeer,
		tlsConf:   tlsConf,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.Conn, error) {
	_, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	var remotePubKey ic.PubKey
	tlsConf := t.tlsConf.Clone()
	// We need to check the peer ID in the VerifyPeerCertificate callback.
	// The tls.Config it is also used for listening, and we might also have concurrent dials.
	// Clone it so we can check for the specific peer ID we're dialing here.
	tlsConf.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
		chain := make([]*x509.Certificate, len(rawCerts))
		for i := 0; i < len(rawCerts); i++ {
			cert, err := x509.ParseCertificate(rawCerts[i])
			if err != nil {
				return err
			}
			chain[i] = cert
		}
		var err error
		remotePubKey, err = getRemotePubKey(chain)
		if err != nil {
			return err
		}
		if !p.MatchesPublicKey(remotePubKey) {
			return errors.New("peer IDs don't match")
		}
		return nil
	}
	sess, err := quicDialAddr(host, tlsConf, quicConfig)
	if err != nil {
		return nil, err
	}
	localMultiaddr, err := quicMultiaddr(sess.LocalAddr())
	if err != nil {
		return nil, err
	}
	return &conn{
		sess:            sess,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: raddr,
	}, nil
}

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.QUIC.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	return newListener(addr, t, t.localPeer, t.privKey, t.tlsConf)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<commit_msg>use the context for dialing<commit_after>package libp2pquic

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"

	ic "github.com/libp2p/go-libp2p-crypto"
	peer "github.com/libp2p/go-libp2p-peer"
	tpt "github.com/libp2p/go-libp2p-transport"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
	"github.com/whyrusleeping/mafmt"
)

var quicConfig = &quic.Config{
	MaxReceiveStreamFlowControlWindow:     3 * (1 << 20),   // 3 MB
	MaxReceiveConnectionFlowControlWindow: 4.5 * (1 << 20), // 4.5 MB
	Versions: []quic.VersionNumber{101},
	AcceptCookie: func(clientAddr net.Addr, cookie *quic.Cookie) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
}

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey   ic.PrivKey
	localPeer peer.ID
	tlsConf   *tls.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey) (tpt.Transport, error) {
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	tlsConf, err := generateConfig(key)
	if err != nil {
		return nil, err
	}
	return &transport{
		privKey:   key,
		localPeer: localPeer,
		tlsConf:   tlsConf,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.Conn, error) {
	_, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	var remotePubKey ic.PubKey
	tlsConf := t.tlsConf.Clone()
	// We need to check the peer ID in the VerifyPeerCertificate callback.
	// The tls.Config it is also used for listening, and we might also have concurrent dials.
	// Clone it so we can check for the specific peer ID we're dialing here.
	tlsConf.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
		chain := make([]*x509.Certificate, len(rawCerts))
		for i := 0; i < len(rawCerts); i++ {
			cert, err := x509.ParseCertificate(rawCerts[i])
			if err != nil {
				return err
			}
			chain[i] = cert
		}
		var err error
		remotePubKey, err = getRemotePubKey(chain)
		if err != nil {
			return err
		}
		if !p.MatchesPublicKey(remotePubKey) {
			return errors.New("peer IDs don't match")
		}
		return nil
	}
	sess, err := quic.DialAddrContext(ctx, host, tlsConf, quicConfig)
	if err != nil {
		return nil, err
	}
	localMultiaddr, err := quicMultiaddr(sess.LocalAddr())
	if err != nil {
		return nil, err
	}
	return &conn{
		sess:            sess,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: raddr,
	}, nil
}

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.QUIC.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	return newListener(addr, t, t.localPeer, t.privKey, t.tlsConf)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<|endoftext|>


<commit_before>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// Cross-compiles gh
//
// Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	t.Log("Removing build target...")
	err = os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	t.Log("Cross-compiling gh...")
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<commit_msg>Add task to cross compile on darwin and linux<commit_after>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// Cross-compiles gh for all supported platforms.
//
// Cross-compiles gh for all supported platforms. The build artifacts
// will be in target/VERSION. This only works on darwin with Vagrant setup.
func TaskCrossCompileAll(t *tasking.T) {
	t.Log("Removing build target...")
	err := os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	// for darwin
	t.Log("Compiling for darwin...")
	TaskCrossCompile(t)
	if t.Failed() {
		return
	}

	// for linux
	t.Log("Compiling for linux...")
	err = t.Exec("vagrant ssh -c 'cd ~/src/github.com/jingweno/gh && git pull origin master && gotask cross-compile'")
	if err != nil {
		t.Errorf("Can't compile on linux: %s\n", err)
		return
	}
}

// Cross-compiles gh for current operating system.
//
// Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	t.Log("Cross-compiling gh for mac...")
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<|endoftext|>


<commit_before>// +build gotask

package main

import (
	"fmt"
	"github.com/jingweno/gotask/tasking"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
)

// NAME
//    install-deps - install dependencies with go get
//
// DESCRIPTION
//    Install dependencies with go get.
func TaskInstallDeps(t *tasking.T) {
	deps := []string{
		"github.com/laher/goxc",
	}

	for _, dep := range deps {
		t.Logf("Installing %s\n", dep)
		err := t.Exec("go get", dep)
		if err != nil {
			t.Fatalf("Can't download dependency %s", err)
		}
	}
}

// NAME
//    package - cross compile gh and package it
//
// DESCRIPTION
//    Cross compile gh and package it into PWD/target
func TaskPackage(t *tasking.T) {
	gopath, err := ioutil.TempDir("", "gh-build")
	os.Setenv("GOPATH", gopath)
	t.Logf("GOPATH=%s\n", gopath)

	path := fmt.Sprintf("%s%c%s", filepath.Join(gopath, "bin"), os.PathListSeparator, os.Getenv("PATH"))
	os.Setenv("PATH", path)
	t.Logf("PATH=%s\n", path)

	t.Logf("Packaging for %s...\n", runtime.GOOS)

	t.Log("Installing dependencies...")
	TaskInstallDeps(t)

	pwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}
	ghPath := filepath.Join(gopath, "src", "github.com", "jingweno", "gh")
	t.Logf("Copying source from %s to %s\n", pwd, ghPath)
	err = copyDir(pwd, ghPath)
	if err != nil {
		t.Fatal(err)
	}
	err = os.Chdir(ghPath)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Cross-compiling...")
	godepPath := filepath.Join(ghPath, "Godeps", "_workspace")
	gopath = fmt.Sprintf("%s%c%s", gopath, os.PathListSeparator, godepPath)
	os.Setenv("GOPATH", gopath)
	TaskCrossCompile(t)

	source := filepath.Join(ghPath, "target")
	target := filepath.Join(pwd, "target")
	t.Logf("Copying build artifacts from %s to %s...\n", source, target)
	_, err = os.Stat(target)
	if err != nil {
		err = os.Mkdir(target, 0777)
		if err != nil {
			t.Fatal(err)
		}
	}
	err = copyBuildArtifacts(source, target)
	if err != nil {
		t.Fatal(err)
	}
}

// NAME
//    cross-compile - cross-compiles gh for current platform.
//
// DESCRIPTION
//    Cross-compiles gh for current platform. Build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS)
	t.Logf("GOPATH=%s\n", os.Getenv("GOPATH"))
	err := t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Fatalf("Can't cross-compile gh: %s\n", err)
	}
}

func copyBuildArtifacts(srcDir, destDir string) error {
	artifacts := findBuildArtifacts(srcDir)
	for _, artifact := range artifacts {
		target := filepath.Join(destDir, filepath.Base(artifact))
		fmt.Printf("Copying %s to %s\n", artifact, target)
		err := copyFile(artifact, target)
		if err != nil {
			return err
		}
	}

	return nil
}

func copyFile(source, dest string) error {
	sf, err := os.Open(source)
	if err != nil {
		return err
	}
	defer sf.Close()

	df, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer df.Close()

	_, err = io.Copy(df, sf)

	if err == nil {
		si, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, si.Mode())
		}
	}

	return err
}

func copyDir(source, dest string) (err error) {
	fi, err := os.Stat(source)
	if err != nil {
		return err
	}

	if !fi.IsDir() {
		return fmt.Errorf("Source is not a directory")
	}

	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return fmt.Errorf("Destination already exists")
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	entries, err := ioutil.ReadDir(source)
	for _, entry := range entries {
		sfp := filepath.Join(source, entry.Name())
		dfp := filepath.Join(dest, entry.Name())
		if entry.IsDir() {
			err = copyDir(sfp, dfp)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sfp, dfp)
			if err != nil {
				return err
			}
		}
	}

	return
}

func findBuildArtifacts(root string) (artifacts []string) {
	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		ext := filepath.Ext(path)
		if ext == ".deb" || ext == ".zip" || ext == ".gz" {
			artifacts = append(artifacts, path)
		}

		return nil
	})

	return
}
<commit_msg>Build homebrew bottle<commit_after>// +build gotask

package main

import (
	"fmt"
	"github.com/jingweno/gotask/tasking"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
)

// NAME
//    install-deps - install dependencies with go get
//
// DESCRIPTION
//    Install dependencies with go get.
func TaskInstallDeps(t *tasking.T) {
	deps := []string{
		"github.com/laher/goxc",
	}

	for _, dep := range deps {
		t.Logf("Installing %s\n", dep)
		err := t.Exec("go get", dep)
		if err != nil {
			t.Fatalf("Can't download dependency %s", err)
		}
	}
}

// NAME
//    package - cross compile gh and package it
//
// DESCRIPTION
//    Cross compile gh and package it into PWD/target
func TaskPackage(t *tasking.T) {
	gopath, err := ioutil.TempDir("", "gh-build")
	os.Setenv("GOPATH", gopath)
	t.Logf("GOPATH=%s\n", gopath)

	path := fmt.Sprintf("%s%c%s", filepath.Join(gopath, "bin"), os.PathListSeparator, os.Getenv("PATH"))
	os.Setenv("PATH", path)
	t.Logf("PATH=%s\n", path)

	t.Logf("Packaging for %s...\n", runtime.GOOS)

	t.Log("Installing dependencies...")
	TaskInstallDeps(t)

	pwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}

	ghPath := filepath.Join(gopath, "src", "github.com", "jingweno", "gh")
	t.Logf("Copying source from %s to %s\n", pwd, ghPath)
	err = copyDir(pwd, ghPath)
	if err != nil {
		t.Fatal(err)
	}
	err = os.Chdir(ghPath)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Cross-compiling...")
	godepPath := filepath.Join(ghPath, "Godeps", "_workspace")
	gopath = fmt.Sprintf("%s%c%s", gopath, os.PathListSeparator, godepPath)
	os.Setenv("GOPATH", gopath)
	TaskCrossCompile(t)

	source := filepath.Join(ghPath, "target")
	target := filepath.Join(pwd, "target")
	t.Logf("Copying build artifacts from %s to %s...\n", source, target)
	_, err = os.Stat(target)
	if err != nil {
		err = os.Mkdir(target, 0777)
		if err != nil {
			t.Fatal(err)
		}
	}
	err = copyBuildArtifacts(source, target)
	if err != nil {
		t.Fatal(err)
	}

	buildHomebrewBottle(t, target)
}

func buildHomebrewBottle(t *tasking.T, target string) {
	err := t.Exec("brew", "list", "gh")
	if err == nil {
		err := t.Exec("brew", "uninstall", "gh")
		if err != nil {
			t.Fatal(err)
		}
	}

	err = t.Exec("brew", "install", "--build-from-source", "--build-bottle", "gh")
	if err != nil {
		t.Fatal(err)
	}

	err = os.Chdir(target)
	if err != nil {
		t.Fatal(err)
	}

	err = t.Exec("brew", "bottle", "gh")
	if err != nil {
		t.Fatal(err)
	}
}

// NAME
//    cross-compile - cross-compiles gh for current platform.
//
// DESCRIPTION
//    Cross-compiles gh for current platform. Build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS)
	t.Logf("GOPATH=%s\n", os.Getenv("GOPATH"))
	err := t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Fatalf("Can't cross-compile gh: %s\n", err)
	}
}

func copyBuildArtifacts(srcDir, destDir string) error {
	artifacts := findBuildArtifacts(srcDir)
	for _, artifact := range artifacts {
		target := filepath.Join(destDir, filepath.Base(artifact))
		fmt.Printf("Copying %s to %s\n", artifact, target)
		err := copyFile(artifact, target)
		if err != nil {
			return err
		}
	}

	return nil
}

func copyFile(source, dest string) error {
	sf, err := os.Open(source)
	if err != nil {
		return err
	}
	defer sf.Close()

	df, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer df.Close()

	_, err = io.Copy(df, sf)

	if err == nil {
		si, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, si.Mode())
		}
	}

	return err
}

func copyDir(source, dest string) (err error) {
	fi, err := os.Stat(source)
	if err != nil {
		return err
	}

	if !fi.IsDir() {
		return fmt.Errorf("Source is not a directory")
	}

	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return fmt.Errorf("Destination already exists")
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	entries, err := ioutil.ReadDir(source)
	for _, entry := range entries {
		sfp := filepath.Join(source, entry.Name())
		dfp := filepath.Join(dest, entry.Name())
		if entry.IsDir() {
			err = copyDir(sfp, dfp)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sfp, dfp)
			if err != nil {
				return err
			}
		}
	}

	return
}

func findBuildArtifacts(root string) (artifacts []string) {
	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		ext := filepath.Ext(path)
		if ext == ".deb" || ext == ".zip" || ext == ".gz" {
			artifacts = append(artifacts, path)
		}

		return nil
	})

	return
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

// StorageVolumeSnapshotAction represents a lifecycle event action for storage volume snapshots.
type StorageVolumeSnapshotAction string

// All supported lifecycle events for storage volume snapshots.
const (
	StorageVolumeSnapshotCreated = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotCreated)
	StorageVolumeSnapshotDeleted = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotDeleted)
	StorageVolumeSnapshotUpdated = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotUpdated)
	StorageVolumeSnapshotRenamed = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotRenamed)
)

// Event creates the lifecycle event for an action on a storage volume snapshot.
func (a StorageVolumeSnapshotAction) Event(v volume, volumeType string, projectName string, op *operations.Operation, ctx map[string]any) api.EventLifecycle {
	parentName, snapshotName, _ := shared.InstanceGetParentAndSnapshotName(v.Name())

	u := fmt.Sprintf("/1.0/storage-pools/%s/volumes/%s/%s/snapshots", url.PathEscape(v.Pool()), url.PathEscape(volumeType), url.PathEscape(parentName))
	if snapshotName != "" {
		u = fmt.Sprintf("%s/%s", u, snapshotName)
	}

	if projectName != project.Default {
		u = fmt.Sprintf("%s?project=%s", u, url.QueryEscape(projectName))
	}

	var requestor *api.EventLifecycleRequestor
	if op != nil {
		requestor = op.Requestor()
	}

	return api.EventLifecycle{
		Action:    string(a),
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<commit_msg>lxd/lifecycle/storage/volume/snapshot: Updates StorageVolumeSnapshotAction.Event to expect snapshot volume<commit_after>package lifecycle

import (
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

// StorageVolumeSnapshotAction represents a lifecycle event action for storage volume snapshots.
type StorageVolumeSnapshotAction string

// All supported lifecycle events for storage volume snapshots.
const (
	StorageVolumeSnapshotCreated = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotCreated)
	StorageVolumeSnapshotDeleted = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotDeleted)
	StorageVolumeSnapshotUpdated = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotUpdated)
	StorageVolumeSnapshotRenamed = StorageVolumeSnapshotAction(api.EventLifecycleStorageVolumeSnapshotRenamed)
)

// Event creates the lifecycle event for an action on a storage volume snapshot.
func (a StorageVolumeSnapshotAction) Event(v volume, volumeType string, projectName string, op *operations.Operation, ctx map[string]any) api.EventLifecycle {
	parentName, snapshotName, _ := shared.InstanceGetParentAndSnapshotName(v.Name())

	u := api.NewURL().Path(version.APIVersion, "storage-pools", v.Pool(), "volumes", volumeType, parentName, "snapshots", snapshotName).Project(projectName)

	var requestor *api.EventLifecycleRequestor
	if op != nil {
		requestor = op.Requestor()
	}

	return api.EventLifecycle{
		Action:    string(a),
		Source:    u.String(),
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>


<commit_before>package completion

import (
	"os"
	"regexp"
	"strings"

	"github.com/zetamatta/go-findfile"

	"../dos"
)

const (
	STD_SLASH = string(os.PathSeparator)
	OPT_SLASH = "/"
)

var rxEnvPattern = regexp.MustCompile("%[^%]+%")

func replaceEnv(str string) string {
	str = rxEnvPattern.ReplaceAllStringFunc(str, func(p string) string {
		if len(p) == 2 {
			return "%"
		}
		name := p[1 : len(p)-1]
		for _, env := range PercentVariables {
			if value := env.Lookup(name); value != "" {
				return value
			}
		}
		return p
	})

	if len(str) >= 2 && str[0] == '~' && os.IsPathSeparator(str[1]) {
		if home := dos.GetHome(); home != "" {
			str = home + str[1:]
		}
	}
	return str
}

func listUpFiles(str string) ([]Element, error) {
	orgSlash := STD_SLASH[0]
	if pos := strings.IndexAny(str, STD_SLASH+OPT_SLASH); pos >= 0 {
		orgSlash = str[pos]
	}
	str = strings.Replace(strings.Replace(str, OPT_SLASH, STD_SLASH, -1), `"`, "", -1)
	directory := DirName(str)
	wildcard := dos.Join(replaceEnv(directory), "*")

	// Drive letter
	cutprefix := 0
	if strings.HasPrefix(directory, STD_SLASH) {
		wd, _ := os.Getwd()
		directory = wd[0:2] + directory
		cutprefix = 2
	}
	commons := make([]Element, 0)
	STR := strings.ToUpper(str)
	fdErr := findfile.Walk(wildcard, func(fd *findfile.FileInfo) bool {
		if fd.Name() == "." || fd.Name() == ".." || fd.IsHidden() {
			return true
		}
		listname := fd.Name()
		name := dos.Join(directory, fd.Name())
		if fd.IsDir() {
			name += STD_SLASH
			listname += OPT_SLASH
		}
		if cutprefix > 0 {
			name = name[2:]
		}
		nameUpr := strings.ToUpper(name)
		if strings.HasPrefix(nameUpr, STR) {
			if orgSlash != STD_SLASH[0] {
				name = strings.Replace(name, STD_SLASH, OPT_SLASH, -1)
			}
			element := Element{InsertStr: name, ListupStr: listname}
			commons = append(commons, element)
		}
		return true
	})
	return commons, fdErr
}
<commit_msg>Internal. Add variable: completion.IncludeHidden for #201<commit_after>package completion

import (
	"os"
	"regexp"
	"strings"

	"github.com/zetamatta/go-findfile"

	"../dos"
)

const (
	STD_SLASH = string(os.PathSeparator)
	OPT_SLASH = "/"
)

var IncludeHidden = false

var rxEnvPattern = regexp.MustCompile("%[^%]+%")

func replaceEnv(str string) string {
	str = rxEnvPattern.ReplaceAllStringFunc(str, func(p string) string {
		if len(p) == 2 {
			return "%"
		}
		name := p[1 : len(p)-1]
		for _, env := range PercentVariables {
			if value := env.Lookup(name); value != "" {
				return value
			}
		}
		return p
	})

	if len(str) >= 2 && str[0] == '~' && os.IsPathSeparator(str[1]) {
		if home := dos.GetHome(); home != "" {
			str = home + str[1:]
		}
	}
	return str
}

func listUpFiles(str string) ([]Element, error) {
	orgSlash := STD_SLASH[0]
	if pos := strings.IndexAny(str, STD_SLASH+OPT_SLASH); pos >= 0 {
		orgSlash = str[pos]
	}
	str = strings.Replace(strings.Replace(str, OPT_SLASH, STD_SLASH, -1), `"`, "", -1)
	directory := DirName(str)
	wildcard := dos.Join(replaceEnv(directory), "*")

	// Drive letter
	cutprefix := 0
	if strings.HasPrefix(directory, STD_SLASH) {
		wd, _ := os.Getwd()
		directory = wd[0:2] + directory
		cutprefix = 2
	}
	commons := make([]Element, 0)
	STR := strings.ToUpper(str)
	fdErr := findfile.Walk(wildcard, func(fd *findfile.FileInfo) bool {
		if fd.Name() == "." || fd.Name() == ".." {
			return true
		}
		if !IncludeHidden && fd.IsHidden() {
			return true
		}
		listname := fd.Name()
		name := dos.Join(directory, fd.Name())
		if fd.IsDir() {
			name += STD_SLASH
			listname += OPT_SLASH
		}
		if cutprefix > 0 {
			name = name[2:]
		}
		nameUpr := strings.ToUpper(name)
		if strings.HasPrefix(nameUpr, STR) {
			if orgSlash != STD_SLASH[0] {
				name = strings.Replace(name, STD_SLASH, OPT_SLASH, -1)
			}
			element := Element{InsertStr: name, ListupStr: listname}
			commons = append(commons, element)
		}
		return true
	})
	return commons, fdErr
}
<|endoftext|>


<commit_before>package miner

import (
	"fmt"
	"math/big"
	"sort"
	"sync"
	"sync/atomic"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/pow"
	"gopkg.in/fatih/set.v0"
)

var jsonlogger = logger.NewJsonLogger()

type environment struct {
	totalUsedGas *big.Int
	state        *state.StateDB
	coinbase     *state.StateObject
	block        *types.Block
	family       *set.Set
	uncles       *set.Set
}

func env(block *types.Block, eth core.Backend) *environment {
	state := state.New(block.Root(), eth.StateDb())
	env := &environment{
		totalUsedGas: new(big.Int),
		state:        state,
		block:        block,
		family:       set.New(),
		uncles:       set.New(),
		coinbase:     state.GetOrNewStateObject(block.Coinbase()),
	}

	return env
}

type Work struct {
	Number    uint64
	Nonce     uint64
	MixDigest []byte
	SeedHash  []byte
}

type Agent interface {
	Work() chan<- *types.Block
	SetReturnCh(chan<- *types.Block)
	Stop()
	Start()
	GetHashRate() int64
}

type worker struct {
	mu sync.Mutex

	agents []Agent
	recv   chan *types.Block
	mux    *event.TypeMux
	quit   chan struct{}
	pow    pow.PoW
	atWork int64

	eth      core.Backend
	chain    *core.ChainManager
	proc     *core.BlockProcessor
	coinbase common.Address

	current *environment

	uncleMu        sync.Mutex
	possibleUncles map[common.Hash]*types.Block

	mining bool
}

func newWorker(coinbase common.Address, eth core.Backend) *worker {
	return &worker{
		eth:            eth,
		mux:            eth.EventMux(),
		recv:           make(chan *types.Block),
		chain:          eth.ChainManager(),
		proc:           eth.BlockProcessor(),
		possibleUncles: make(map[common.Hash]*types.Block),
		coinbase:       coinbase,
	}
}

func (self *worker) start() {
	self.mining = true

	self.quit = make(chan struct{})

	// spin up agents
	for _, agent := range self.agents {
		agent.Start()
	}

	go self.update()
	go self.wait()
}

func (self *worker) stop() {
	self.mining = false
	atomic.StoreInt64(&self.atWork, 0)

	close(self.quit)
}

func (self *worker) register(agent Agent) {
	self.agents = append(self.agents, agent)
	agent.SetReturnCh(self.recv)
}

func (self *worker) update() {
	events := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{})

	timer := time.NewTicker(2 * time.Second)

out:
	for {
		select {
		case event := <-events.Chan():
			switch ev := event.(type) {
			case core.ChainHeadEvent:
				self.commitNewWork()
			case core.ChainSideEvent:
				self.uncleMu.Lock()
				self.possibleUncles[ev.Block.Hash()] = ev.Block
				self.uncleMu.Unlock()
			}

		case <-self.quit:
			// stop all agents
			for _, agent := range self.agents {
				agent.Stop()
			}
			break out
		case <-timer.C:
			minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")

			// XXX In case all mined a possible uncle
			if atomic.LoadInt64(&self.atWork) == 0 {
				self.commitNewWork()
			}
		}
	}

	events.Unsubscribe()
}

func (self *worker) wait() {
	for {
		for block := range self.recv {
			atomic.AddInt64(&self.atWork, -1)

			if block == nil {
				continue
			}

			if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
				for _, uncle := range block.Uncles() {
					delete(self.possibleUncles, uncle.Hash())
				}
				self.mux.Post(core.NewMinedBlockEvent{block})

				minerlogger.Infof("🔨 Mined block #%v", block.Number())

				jsonlogger.LogJson(&logger.EthMinerNewBlock{
					BlockHash:     block.Hash().Hex(),
					BlockNumber:   block.Number(),
					ChainHeadHash: block.ParentHeaderHash.Hex(),
					BlockPrevHash: block.ParentHeaderHash.Hex(),
				})
			} else {
				self.commitNewWork()
			}
		}
	}
}

func (self *worker) push() {
	if self.mining {
		self.current.block.Header().GasUsed = self.current.totalUsedGas
		self.current.block.SetRoot(self.current.state.Root())

		// push new work to agents
		for _, agent := range self.agents {
			atomic.AddInt64(&self.atWork, 1)

			agent.Work() <- self.current.block.Copy()
		}
	}
}

func (self *worker) commitNewWork() {
	self.mu.Lock()
	defer self.mu.Unlock()
	self.uncleMu.Lock()
	defer self.uncleMu.Unlock()

	block := self.chain.NewBlock(self.coinbase)

	self.current = env(block, self.eth)
	for _, ancestor := range self.chain.GetAncestors(block, 7) {
		self.current.family.Add(ancestor.Hash())
	}

	parent := self.chain.GetBlock(self.current.block.ParentHash())
	self.current.coinbase.SetGasPool(core.CalcGasLimit(parent, self.current.block))

	transactions := self.eth.TxPool().GetTransactions()
	sort.Sort(types.TxByNonce{transactions})

	// Keep track of transactions which return errors so they can be removed
	var (
		remove types.Transactions
		tcount = 0
	)
gasLimit:
	for i, tx := range transactions {
		err := self.commitTransaction(tx)
		switch {
		case core.IsNonceErr(err):
			fallthrough
		case core.IsInvalidTxErr(err):
			// Remove invalid transactions
			from, _ := tx.From()
			self.chain.TxState().RemoveNonce(from, tx.Nonce())
			remove = append(remove, tx)
			minerlogger.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
			minerlogger.Infoln(tx)
		case state.IsGasLimitErr(err):
			minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
			// Break on gas limit
			break gasLimit
		default:
			tcount++
		}
	}
	self.eth.TxPool().RemoveSet(remove)

	var (
		uncles    []*types.Header
		badUncles []common.Hash
	)
	for hash, uncle := range self.possibleUncles {
		if len(uncles) == 2 {
			break
		}

		if err := self.commitUncle(uncle.Header()); err != nil {
			minerlogger.Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
			minerlogger.Debugln(uncle)
			badUncles = append(badUncles, hash)
		} else {
			minerlogger.Infof("commiting %x as uncle\n", hash[:4])
			uncles = append(uncles, uncle.Header())
		}
	}
	minerlogger.Infof("commit new work on block %v with %d txs & %d uncles\n", self.current.block.Number(), tcount, len(uncles))
	for _, hash := range badUncles {
		delete(self.possibleUncles, hash)
	}

	self.current.block.SetUncles(uncles)

	core.AccumulateRewards(self.current.state, self.current.block)

	self.current.state.Update()
	self.push()
}

var (
	inclusionReward = new(big.Int).Div(core.BlockReward, big.NewInt(32))
	_uncleReward    = new(big.Int).Mul(core.BlockReward, big.NewInt(15))
	uncleReward     = new(big.Int).Div(_uncleReward, big.NewInt(16))
)

func (self *worker) commitUncle(uncle *types.Header) error {
	if self.current.uncles.Has(uncle.Hash()) {
		// Error not unique
		return core.UncleError("Uncle not unique")
	}
	self.current.uncles.Add(uncle.Hash())

	if !self.current.family.Has(uncle.ParentHash) {
		return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
	}

	if self.current.family.Has(uncle.Hash()) {
		return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
	}

	return nil
}

func (self *worker) commitTransaction(tx *types.Transaction) error {
	snap := self.current.state.Copy()
	receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
	if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
		self.current.state.Set(snap)
		return err
	}

	self.current.block.AddTransaction(tx)
	self.current.block.AddReceipt(receipt)

	return nil
}

func (self *worker) HashRate() int64 {
	var tot int64
	for _, agent := range self.agents {
		tot += agent.GetHashRate()
	}

	return tot
}
<commit_msg>Make sure we're not mining on an invalid TS<commit_after>package miner

import (
	"fmt"
	"math/big"
	"sort"
	"sync"
	"sync/atomic"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/pow"
	"gopkg.in/fatih/set.v0"
)

var jsonlogger = logger.NewJsonLogger()

type environment struct {
	totalUsedGas *big.Int
	state        *state.StateDB
	coinbase     *state.StateObject
	block        *types.Block
	family       *set.Set
	uncles       *set.Set
}

func env(block *types.Block, eth core.Backend) *environment {
	state := state.New(block.Root(), eth.StateDb())
	env := &environment{
		totalUsedGas: new(big.Int),
		state:        state,
		block:        block,
		family:       set.New(),
		uncles:       set.New(),
		coinbase:     state.GetOrNewStateObject(block.Coinbase()),
	}

	return env
}

type Work struct {
	Number    uint64
	Nonce     uint64
	MixDigest []byte
	SeedHash  []byte
}

type Agent interface {
	Work() chan<- *types.Block
	SetReturnCh(chan<- *types.Block)
	Stop()
	Start()
	GetHashRate() int64
}

type worker struct {
	mu sync.Mutex

	agents []Agent
	recv   chan *types.Block
	mux    *event.TypeMux
	quit   chan struct{}
	pow    pow.PoW
	atWork int64

	eth      core.Backend
	chain    *core.ChainManager
	proc     *core.BlockProcessor
	coinbase common.Address

	current *environment

	uncleMu        sync.Mutex
	possibleUncles map[common.Hash]*types.Block

	mining bool
}

func newWorker(coinbase common.Address, eth core.Backend) *worker {
	return &worker{
		eth:            eth,
		mux:            eth.EventMux(),
		recv:           make(chan *types.Block),
		chain:          eth.ChainManager(),
		proc:           eth.BlockProcessor(),
		possibleUncles: make(map[common.Hash]*types.Block),
		coinbase:       coinbase,
	}
}

func (self *worker) start() {
	self.mining = true

	self.quit = make(chan struct{})

	// spin up agents
	for _, agent := range self.agents {
		agent.Start()
	}

	go self.update()
	go self.wait()
}

func (self *worker) stop() {
	self.mining = false
	atomic.StoreInt64(&self.atWork, 0)

	close(self.quit)
}

func (self *worker) register(agent Agent) {
	self.agents = append(self.agents, agent)
	agent.SetReturnCh(self.recv)
}

func (self *worker) update() {
	events := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{})

	timer := time.NewTicker(2 * time.Second)

out:
	for {
		select {
		case event := <-events.Chan():
			switch ev := event.(type) {
			case core.ChainHeadEvent:
				self.commitNewWork()
			case core.ChainSideEvent:
				self.uncleMu.Lock()
				self.possibleUncles[ev.Block.Hash()] = ev.Block
				self.uncleMu.Unlock()
			}

		case <-self.quit:
			// stop all agents
			for _, agent := range self.agents {
				agent.Stop()
			}
			break out
		case <-timer.C:
			minerlogger.Infoln("Hash rate:", self.HashRate(), "Khash")

			// XXX In case all mined a possible uncle
			if atomic.LoadInt64(&self.atWork) == 0 {
				self.commitNewWork()
			}
		}
	}

	events.Unsubscribe()
}

func (self *worker) wait() {
	for {
		for block := range self.recv {
			atomic.AddInt64(&self.atWork, -1)

			if block == nil {
				continue
			}

			if err := self.chain.InsertChain(types.Blocks{block}); err == nil {
				for _, uncle := range block.Uncles() {
					delete(self.possibleUncles, uncle.Hash())
				}
				self.mux.Post(core.NewMinedBlockEvent{block})

				minerlogger.Infof("🔨 Mined block #%v", block.Number())

				jsonlogger.LogJson(&logger.EthMinerNewBlock{
					BlockHash:     block.Hash().Hex(),
					BlockNumber:   block.Number(),
					ChainHeadHash: block.ParentHeaderHash.Hex(),
					BlockPrevHash: block.ParentHeaderHash.Hex(),
				})
			} else {
				self.commitNewWork()
			}
		}
	}
}

func (self *worker) push() {
	if self.mining {
		self.current.block.Header().GasUsed = self.current.totalUsedGas
		self.current.block.SetRoot(self.current.state.Root())

		// push new work to agents
		for _, agent := range self.agents {
			atomic.AddInt64(&self.atWork, 1)

			agent.Work() <- self.current.block.Copy()
		}
	}
}

func (self *worker) commitNewWork() {
	self.mu.Lock()
	defer self.mu.Unlock()
	self.uncleMu.Lock()
	defer self.uncleMu.Unlock()

	block := self.chain.NewBlock(self.coinbase)
	if block.Time() == self.chain.CurrentBlock().Time() {
		block.Header().Time++
	}

	self.current = env(block, self.eth)
	for _, ancestor := range self.chain.GetAncestors(block, 7) {
		self.current.family.Add(ancestor.Hash())
	}

	parent := self.chain.GetBlock(self.current.block.ParentHash())
	self.current.coinbase.SetGasPool(core.CalcGasLimit(parent, self.current.block))

	transactions := self.eth.TxPool().GetTransactions()
	sort.Sort(types.TxByNonce{transactions})

	// Keep track of transactions which return errors so they can be removed
	var (
		remove types.Transactions
		tcount = 0
	)
gasLimit:
	for i, tx := range transactions {
		err := self.commitTransaction(tx)
		switch {
		case core.IsNonceErr(err):
			fallthrough
		case core.IsInvalidTxErr(err):
			// Remove invalid transactions
			from, _ := tx.From()
			self.chain.TxState().RemoveNonce(from, tx.Nonce())
			remove = append(remove, tx)
			minerlogger.Infof("TX (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err)
			minerlogger.Infoln(tx)
		case state.IsGasLimitErr(err):
			minerlogger.Infof("Gas limit reached for block. %d TXs included in this block\n", i)
			// Break on gas limit
			break gasLimit
		default:
			tcount++
		}
	}
	self.eth.TxPool().RemoveSet(remove)

	var (
		uncles    []*types.Header
		badUncles []common.Hash
	)
	for hash, uncle := range self.possibleUncles {
		if len(uncles) == 2 {
			break
		}

		if err := self.commitUncle(uncle.Header()); err != nil {
			minerlogger.Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
			minerlogger.Debugln(uncle)
			badUncles = append(badUncles, hash)
		} else {
			minerlogger.Infof("commiting %x as uncle\n", hash[:4])
			uncles = append(uncles, uncle.Header())
		}
	}
	minerlogger.Infof("commit new work on block %v with %d txs & %d uncles\n", self.current.block.Number(), tcount, len(uncles))
	for _, hash := range badUncles {
		delete(self.possibleUncles, hash)
	}

	self.current.block.SetUncles(uncles)

	core.AccumulateRewards(self.current.state, self.current.block)

	self.current.state.Update()
	self.push()
}

var (
	inclusionReward = new(big.Int).Div(core.BlockReward, big.NewInt(32))
	_uncleReward    = new(big.Int).Mul(core.BlockReward, big.NewInt(15))
	uncleReward     = new(big.Int).Div(_uncleReward, big.NewInt(16))
)

func (self *worker) commitUncle(uncle *types.Header) error {
	if self.current.uncles.Has(uncle.Hash()) {
		// Error not unique
		return core.UncleError("Uncle not unique")
	}
	self.current.uncles.Add(uncle.Hash())

	if !self.current.family.Has(uncle.ParentHash) {
		return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
	}

	if self.current.family.Has(uncle.Hash()) {
		return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", uncle.Hash()))
	}

	return nil
}

func (self *worker) commitTransaction(tx *types.Transaction) error {
	snap := self.current.state.Copy()
	receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
	if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
		self.current.state.Set(snap)
		return err
	}

	self.current.block.AddTransaction(tx)
	self.current.block.AddReceipt(receipt)

	return nil
}

func (self *worker) HashRate() int64 {
	var tot int64
	for _, agent := range self.agents {
		tot += agent.GetHashRate()
	}

	return tot
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "fmt"
    "sync"

    "github.com/stamp/goADS"

    "os"
    "os/signal"
    "syscall"
 //   "time"

    log "github.com/cihub/seelog"

//    "bytes"
//    "encoding/hex"
//    "encoding/binary"
)

var WaitGroup sync.WaitGroup

func main() {
    defer log.Flush()

	// Flags/*{{{*/
    debug := flag.Bool("debug", false, "print debugging messages.")
    ip := flag.String("ip","","the address to the AMS router")
    netid := flag.String("netid","","AMS NetID of the target")
    port := flag.Int("port",801,"AMS Port of the target")

    flag.Parse()
    fmt.Println(*debug,*ip,*netid,*port);/*}}}*/

    // Start the logger/*{{{*/
    logger, err := log.LoggerFromConfigAsFile("logconfig.xml")
    if err != nil {
        panic(err)
    }
    log.ReplaceLogger(logger)
    goADS.UseLogger(logger)/*}}}*/
    // Startup the connection/*{{{*/
    connection,e := goADS.Dial(*ip,*netid,*port)
    defer connection.Close(); // Close the connection when we are done
    if e != nil {
        logger.Critical(e)
        os.Exit(1)
    }/*}}}*/
    // Add a handler for Ctrl^C,  soft shutdown/*{{{*/
    go shutdownRoutine(connection)/*}}}*/

    // Check what device are we connected to/*{{{*/
    data, e := connection.ReadDeviceInfo();
    if e != nil {
        log.Critical(e)
        os.Exit(1)
    }
    log.Infof("Successfully conncected to \"%s\" version %d.%d (build %d)", data.DeviceName, data.MajorVersion, data.MinorVersion, data.BuildVersion)/*}}}*/

	symbols,_ := connection.UploadSymbolInfo()

	//for _, segment := range symbols {
		//segment.Walk()
	//}
    log.Warn("Count: ",len(symbols));

	//pd,ok := symbols[".RECIPE"]
	pd,ok := symbols[".PD"]
	//pd,ok := symbols[".SYSTEMTASKINFOARR"]
	if ok {
		pd.AddDeviceNotification(func(symbol *goADS.ADSSymbol) {
			val := connection.Value(".PD.TEST1BOOL")
			if val=="True" {
				connection.Set(".PD.TEST1WORD","1")
			} else {
				connection.Set(".PD.TEST1WORD","0")
			}
			symbol.Walk()
		})
//		pd.DebugWalk()
	}

	select{}

    // Do some work/*{{{*/
    /*for i := 0; i < 100; i++ {
        WaitGroup.Add(1)
        go func() {
            _, e = connection.ReadDeviceInfo();
            if e != nil {
                log.Critical(e)
                //connection.Close()
            }
            WaitGroup.Done()
        }()
    }*//*}}}*/

    // Wait for all routines to finish/*{{{*/
    WaitGroup.Wait()
	connection.Wait()

    log.Info("MAIN Done :)");/*}}}*/
}

func shutdownRoutine( conn goADS.Connection ){/*{{{*/
    sigchan := make(chan os.Signal, 2)
    signal.Notify(sigchan, os.Interrupt)
    signal.Notify(sigchan, syscall.SIGTERM)
    <-sigchan

    conn.Close()
}/*}}}*/
<commit_msg>Change to the new connect/new connection syntax<commit_after>package main

import (
	"flag"
	"fmt"
	"sync"

	"github.com/stamp/goADS"

	"os"
	"os/signal"
	"syscall"

	//   "time"

	log "github.com/cihub/seelog"
	//    "bytes"
	//    "encoding/hex"
	//    "encoding/binary"
)

var WaitGroup sync.WaitGroup

func main() {
	defer log.Flush()

	// Flags/*{{{*/
	debug := flag.Bool("debug", false, "print debugging messages.")
	ip := flag.String("ip", "172.16.21.10", "the address to the AMS router")
	netid := flag.String("netid", "172.16.21.10.1.1", "AMS NetID of the target")
	port := flag.Int("port", 801, "AMS Port of the target")

	flag.Parse()
	fmt.Println(*debug, *ip, *netid, *port) /*}}}*/

	// Start the logger/*{{{*/
	logger, err := log.LoggerFromConfigAsFile("logconfig.xml")
	if err != nil {
		panic(err)
	}
	log.ReplaceLogger(logger)
	goADS.UseLogger(logger) /*}}}*/
	// Startup the connection/*{{{*/
	connection, e := goADS.NewConnection(*ip, *netid, *port)
	connection.Connect()
	defer connection.Close() // Close the connection when we are done
	if e != nil {
		logger.Critical(e)
		os.Exit(1)
	} /*}}}*/
	// Add a handler for Ctrl^C,  soft shutdown/*{{{*/
	go shutdownRoutine(connection) /*}}}*/

	// Check what device are we connected to/*{{{*/
	data, e := connection.ReadDeviceInfo()
	if e != nil {
		log.Critical(e)
		os.Exit(1)
	}
	log.Infof("Successfully conncected to \"%s\" version %d.%d (build %d)", data.DeviceName, data.MajorVersion, data.MinorVersion, data.BuildVersion) /*}}}*/

	symbols, _ := connection.UploadSymbolInfo()

	//for _, segment := range symbols {
	//segment.Walk()
	//}
	log.Warn("Count: ", len(symbols))

	//pd,ok := symbols[".RECIPE"]
	pd, ok := symbols[".PD"]
	//pd,ok := symbols[".SYSTEMTASKINFOARR"]
	if ok {
		pd.AddDeviceNotification(func(symbol *goADS.ADSSymbol) {
			val := connection.Value(".PD.TEST1BOOL")
			if val == "True" {
				connection.Set(".PD.TEST1WORD", "1")
			} else {
				connection.Set(".PD.TEST1WORD", "0")
			}
			symbol.Walk()
		})
		//		pd.DebugWalk()
	}

	// Do some work/*{{{*/
	/*for i := 0; i < 100; i++ {
	    WaitGroup.Add(1)
	    go func() {
	        _, e = connection.ReadDeviceInfo();
	        if e != nil {
	            log.Critical(e)
	            //connection.Close()
	        }
	        WaitGroup.Done()
	    }()
	}*/ /*}}}*/

	// Wait for all routines to finish/*{{{*/
	WaitGroup.Wait()
	connection.Wait()

	log.Info("MAIN Done :)") /*}}}*/
}

func shutdownRoutine(conn *goADS.Connection) { /*{{{*/
	sigchan := make(chan os.Signal, 2)
	signal.Notify(sigchan, os.Interrupt)
	signal.Notify(sigchan, syscall.SIGTERM)
	<-sigchan

	conn.Close()
} /*}}}*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

func main() {
	// Fail if not enough parameters
	if len(os.Args) < 2 {
		log.Fatal("I don't know what you want me to do.")
	}

	var client http.Client

	resp, err := client.Get("http://gerrit.dev.returnpath.net/a/changes/?q=status:open")
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest("GET", "http://gerrit.dev.returnpath.net/a/changes/?q=status:open", nil)
	if err != nil {
		log.Fatal(err)
	}

	resp, err = client.Do(req)

	user := getConfigValue("gerrit.user")
	pass := getConfigValue("gerrit.pass")

	auth := GetAuthorization(user, pass, resp)
	digest := GetAuthString(auth, req.URL, req.Method, 1)
	fmt.Println(digest)
	req.Header.Add("Authorization", digest)

	resp, err = client.Do(req)

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(body))

	switch os.Args[1] {
	case "branch":
		Branch()
	case "push":
		fallthrough
	case "pull":
		// Check for changeset in params yet
		// If not, do push and get changeset back
		//
		fallthrough
	default:
		fmt.Printf("You have chosen to \"%s\".\n", os.Args[1])
		break
	}
}

func execCommand(command []string) string {
	cmd := exec.Command(command[0], command[0:]...)
	out, err := cmd.CombinedOutput()

	if err != nil {
		log.Fatal(fmt.Sprint(err) + ": " + string(out))
	}
	output := strings.TrimSpace(string(out))

	return output
}

func getCurrentBranch() string {
	return execCommand([]string{
		"git",
		"symbolic-ref",
		"--short",
		"HEAD",
	})
}

func getConfigValue(name string) string {
	name = "\"" + name + "\""
	val := execCommand([]string{
		"git",
		"config",
		"--get",
		name,
	})

	return val
}

func setConfigValue(name, value string) {
	execCommand([]string{
		"git",
		"config",
		"set",
		name,
		value,
	})
}
<commit_msg>Debugged getConfigValue<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

func main() {
	// Fail if not enough parameters
	if len(os.Args) < 2 {
		log.Fatal("I don't know what you want me to do.")
	}

	var client http.Client

	resp, err := client.Get("http://gerrit.dev.returnpath.net/a/changes/?q=status:open")
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest("GET", "http://gerrit.dev.returnpath.net/a/changes/?q=status:open", nil)
	if err != nil {
		log.Fatal(err)
	}

	resp, err = client.Do(req)
	user := getConfigValue("gerrit.user")
	pass := getConfigValue("gerrit.pass")

	auth := GetAuthorization(user, pass, resp)
	digest := GetAuthString(auth, req.URL, req.Method, 1)
	fmt.Println(digest)
	req.Header.Add("Authorization", digest)

	resp, err = client.Do(req)

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(body))

	switch os.Args[1] {
	case "branch":
		Branch()
	case "push":
		fallthrough
	case "pull":
		// Check for changeset in params yet
		// If not, do push and get changeset back
		//
		fallthrough
	default:
		fmt.Printf("You have chosen to \"%s\".\n", os.Args[1])
		break
	}
}

func execCommand(command []string) string {
	cmd := exec.Command(command[0], command[1:]...)
	out, err := cmd.CombinedOutput()

	if err != nil {
		log.Fatal(fmt.Sprint(err) + ": " + string(out))
	}
	output := strings.TrimSpace(string(out))

	return output
}

func getCurrentBranch() string {
	return execCommand([]string{
		"git",
		"symbolic-ref",
		"--short",
		"HEAD",
	})
}

func getConfigValue(name string) string {
	val := execCommand([]string{
		"git",
		"config",
		name,
	})
	return val
}

func setConfigValue(name, value string) {
	execCommand([]string{
		"git",
		"config",
		"set",
		name,
		value,
	})
}
<|endoftext|>


<commit_before>package s3_test

import (
	"fmt"
	"github.com/kr/s3"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func ExampleSign() {
	keys := s3.Keys{
		os.Getenv("S3_ACCESS_KEY"),
		os.Getenv("S3_SECRET_KEY"),
	}
	data := strings.NewReader("hello, world")
	r, _ := http.NewRequest("PUT", "https://example.s3.amazonaws.com/foo", data)
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	r.Header.Set("Content-Length", strconv.Itoa(data.Len()))
	r.Header.Set("X-Amz-Acl", "public-read")
	s3.Sign(r, keys)
	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp.StatusCode)
}
<commit_msg>correctly set content length in example code<commit_after>package s3_test

import (
	"fmt"
	"github.com/kr/s3"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

func ExampleSign() {
	keys := s3.Keys{
		os.Getenv("S3_ACCESS_KEY"),
		os.Getenv("S3_SECRET_KEY"),
	}
	data := strings.NewReader("hello, world")
	r, _ := http.NewRequest("PUT", "https://example.s3.amazonaws.com/foo", data)
	r.ContentLength = int64(data.Len())
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	r.Header.Set("X-Amz-Acl", "public-read")
	s3.Sign(r, keys)
	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp.StatusCode)
}
<|endoftext|>


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

package btcdb_test

import (
	"fmt"
	"github.com/conformal/btcdb"
	_ "github.com/conformal/btcdb/memdb"
	"github.com/conformal/btcnet"
	"github.com/conformal/btcutil"
)

// This example demonstrates creating a new database and inserting the genesis
// block into it.
func ExampleCreateDB() {
	// Create a database and schedule it to be closed on exit.  This example
	// uses a memory-only database to avoid needing to write anything to
	// the disk.  Typically, you would specify a persistent database driver
	// such as "leveldb" and give it a database name as the second
	// parameter.
	db, err := btcdb.CreateDB("memdb")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer db.Close()

	// Insert the main network genesis block.
	genesis := btcutil.NewBlock(btcnet.MainNetParams.GenesisBlock)
	newHeight, err := db.InsertBlock(genesis)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("New height:", newHeight)

	// Output:
	// New height: 0
}
<commit_msg>Add commented imports to the example.<commit_after>// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcdb_test

import (
	"fmt"
	"github.com/conformal/btcdb"
	_ "github.com/conformal/btcdb/memdb"
	"github.com/conformal/btcnet"
	"github.com/conformal/btcutil"
)

// This example demonstrates creating a new database and inserting the genesis
// block into it.
func ExampleCreateDB() {
	// Notice in these example imports that the memdb driver is loaded.
	// Ordinarily this would be whatever driver(s) your application
	// requires.
	// import (
	//	"github.com/conformal/btcdb"
	// 	_ "github.com/conformal/btcdb/memdb"
	// )

	// Create a database and schedule it to be closed on exit.  This example
	// uses a memory-only database to avoid needing to write anything to
	// the disk.  Typically, you would specify a persistent database driver
	// such as "leveldb" and give it a database name as the second
	// parameter.
	db, err := btcdb.CreateDB("memdb")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer db.Close()

	// Insert the main network genesis block.
	genesis := btcutil.NewBlock(btcnet.MainNetParams.GenesisBlock)
	newHeight, err := db.InsertBlock(genesis)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("New height:", newHeight)

	// Output:
	// New height: 0
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package gostrftime_test

import (
	"fmt"
	"time"

	"github.com/cactus/gostrftime"
)

func ExampleFormat() {
	t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	fmt.Println(gostrftime.Format("%Y-%m-%d", t))
	// Output:
	// 2009-11-10
}
<commit_msg>modify test<commit_after>// Copyright (c) 2014-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package gostrftime

import (
	"fmt"
	"time"
)

func ExampleFormat() {
	t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	fmt.Println(Strftime("%Y-%m-%d", t))
	// Output:
	// 2009-11-10
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package logger

import (
	"errors"
	"fmt"
	"time"
)

func ExampleTags_String() {
	tags := Tags{"tag1", "tag2"}
	fmt.Print(tags.String())
	// Output:
	// tag1, tag2
}

func ExampleMsg_String() {
	t, _ := time.Parse("2006-01-02 15:04:05", "2015-05-24 17:39:50")
	msg := Msg{Error, "My message", Tags{"tag1", "tag2"}, t}
	fmt.Print(msg.String())
	// Output:
	// 2015-05-24 17:39:50 [Error] tag1, tag2: My message
}

func ExampleLogger_Fatal() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	defer func() {
		if recv := recover(); recv != nil {
			log.Fatal(Tags{"file.go", "main"}, recv)
		}
	}()
	panic("Oh no!")
	// Logs:
	// 2015-03-01 17:20:52 [FATAL] file.go, main: Oh no!
	// goroutine 1 [running]:
	// github.com/Thomasdezeeuw/logger.(*Logger).Fatal(0xc08200a200,0xc08201fe00)
	// 	/go/src/github.com/Thomasdezeeuw/logger/logger.go:97 +0x8d
	// main.func·001()
	// 	/go/src/github.com/Thomasdezeeuw/logger/_examples/file.go:35 +0xc4
	// main.main()
	// 	/go/src/github.com/Thomasdezeeuw/logger/_examples/file.go:53 +0x2a9
}

func ExampleLogger_Error() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	err = errors.New("Some error")
	log.Error(Tags{"file.go", "main"}, err)
	// Logs some like:
	// 2015-03-01 17:20:52 [Error] file.go, main: Some error
}

func ExampleLogger_Info() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	log.Info(Tags{"file.go", "main"}, "my %s message", "info")
	// Logs:
	// 2015-03-01 17:20:52 [info] file.go, main: My info message
}

func ExampleLogger_Debug() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	log.Debug(Tags{"file.go", "main"}, "my %s message", "debug")
	// Logs:
	// 2015-03-01 17:20:52 [debug] file.go, main: My debug message
}

func ExampleGet() {
	// First create a logger, for example in the main init function.
	log1, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	// Then get the logger somewhere else.
	log2, err := Get("App")
	if err != nil {
		panic(err)
	}

	log1.Info(Tags{"main"}, "Both these messages")
	log2.Info(Tags{"main"}, "are writting to the same logger")
}
<commit_msg>Add examples for LogLevel<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package logger

import (
	"errors"
	"fmt"
	"time"
)

func ExampleTags_String() {
	tags := Tags{"tag1", "tag2"}
	fmt.Print(tags.String())
	// Output:
	// tag1, tag2
}

func ExampleMsg_String() {
	t, _ := time.Parse("2006-01-02 15:04:05", "2015-05-24 17:39:50")
	msg := Msg{Error, "My message", Tags{"tag1", "tag2"}, t}
	fmt.Print(msg.String())
	// Output:
	// 2015-05-24 17:39:50 [Error] tag1, tag2: My message
}

func ExampleNewLogLevel() {
	myLogLevel := NewLogLevel("myLogLevel")
	myLogLevel2 := NewLogLevel("myLogLevel2")
	fmt.Println(myLogLevel.String())
	fmt.Println(myLogLevel2.String())
	// Output:
	// myLogLevel
	// myLogLevel2
}

func ExampleLogLevel_String() {
	fmt.Println(Debug.String())
	fmt.Println(Error.String())
	fmt.Println(Info.String())
	fmt.Println(Fatal.String())
	// Output:
	// Debug
	// Error
	// Info
	// Fatal
}

func ExampleLogger_Fatal() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	defer func() {
		if recv := recover(); recv != nil {
			log.Fatal(Tags{"file.go", "main"}, recv)
		}
	}()
	panic("Oh no!")
	// Logs:
	// 2015-03-01 17:20:52 [FATAL] file.go, main: Oh no!
	// goroutine 1 [running]:
	// github.com/Thomasdezeeuw/logger.(*Logger).Fatal(0xc08200a200,0xc08201fe00)
	// 	/go/src/github.com/Thomasdezeeuw/logger/logger.go:97 +0x8d
	// main.func·001()
	// 	/go/src/github.com/Thomasdezeeuw/logger/_examples/file.go:35 +0xc4
	// main.main()
	// 	/go/src/github.com/Thomasdezeeuw/logger/_examples/file.go:53 +0x2a9
}

func ExampleLogger_Error() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	err = errors.New("Some error")
	log.Error(Tags{"file.go", "main"}, err)
	// Logs some like:
	// 2015-03-01 17:20:52 [Error] file.go, main: Some error
}

func ExampleLogger_Info() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	log.Info(Tags{"file.go", "main"}, "my %s message", "info")
	// Logs:
	// 2015-03-01 17:20:52 [info] file.go, main: My info message
}

func ExampleLogger_Debug() {
	log, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	log.Debug(Tags{"file.go", "main"}, "my %s message", "debug")
	// Logs:
	// 2015-03-01 17:20:52 [debug] file.go, main: My debug message
}

func ExampleGet() {
	// First create a logger, for example in the main init function.
	log1, err := NewConsole("App")
	if err != nil {
		panic(err)
	}

	// Then get the logger somewhere else.
	log2, err := Get("App")
	if err != nil {
		panic(err)
	}

	log1.Info(Tags{"main"}, "Both these messages")
	log2.Info(Tags{"main"}, "are writting to the same logger")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
	"log"
	"net/http"
	"sync"
)

type CommandHandlerFunc func(conn *websocket.Conn, id string, message map[string]interface{})
type TreeNode struct {
	conn     *websocket.Conn
	id       string
	children []*TreeNode
	parent   *TreeNode
}

var (
	port         = flag.Int("port", 8081, "Port the server listens on")
	maxListeners = flag.Int("max-listeners", 3, "Max number of listeners (WebRTC peers) for a single client")
	upgrader     = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	commandHandlers = map[string]CommandHandlerFunc{
		"START_BROADCAST":          commandStartBroadcast,
		"JOIN_BROADCAST":           commandJoinBroadcast,
		"RELAY_BROADCAST_RECEIVED": commandRelayBroadCastReceived,
		"ICE_CANDIDATES":           commandIceCandidates,
		"ICE_CANDIDATES_RECEIVED":  commandIceCandidatesReceived,
	}
	broadcasts  = map[string]*TreeNode{}
	connections = map[string]*websocket.Conn{}
	globalLock  = new(sync.Mutex) // FIXME: yeah, I know it's horrible, but we'll fix it later
)

func main() {
	http.HandleFunc("/api/ws", handleWebSocket)
	log.Println("Server starting on port", *port)
	log.Fatal("ListenAndServe:", http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	log.Println("Incoming", r.Method, "message")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Failed to upgrade:", err)
		return
	}

	id := uuid.NewV4().String()

	for {
		var rawMessage interface{}
		if err := conn.ReadJSON(&rawMessage); err != nil {
			log.Printf("Read error: %v\n", err)
			conn.Close()
			return
		}

		messageObject, ok := rawMessage.(map[string]interface{})
		if !ok {
			sendErrorMessage(conn, "Message is not a JSON object")
			continue
		}

		command, ok := messageObject["command"].(string)
		if !ok {
			sendErrorMessage(conn, "Message is lacking a command property")
			continue
		}

		log.Printf("Received command: %v\n", command)
		if commandHandler, ok := commandHandlers[command]; ok {
			commandHandler(conn, id, messageObject)
		} else {
			sendErrorMessage(conn, fmt.Sprintf("Unknown command: %v", command))
			continue
		}
	}
}

func commandStartBroadcast(conn *websocket.Conn, id string, message map[string]interface{}) {
	if name, ok := stringProp(message, "name"); ok {
		log.Printf("Starting broadcast: %v", name)

		globalLock.Lock()
		defer globalLock.Unlock()

		broadcasts[name] = &TreeNode{
			conn: conn,
			id:   id,
		}
		connections[id] = conn

		conn.WriteJSON(struct {
			Command string `json:"command"`
		}{
			"START_BROADCAST_RECEIVED",
		})
		return
	}

	sendErrorMessage(conn, "No \"name\" property not specified or not a string in START_BROADCAST message")
}

func commandJoinBroadcast(conn *websocket.Conn, id string, message map[string]interface{}) {
	var name string
	var offer map[string]interface{}
	var ok bool

	if name, ok = stringProp(message, "name"); !ok {
		sendErrorMessage(conn, "No \"name\" property not specified or not a string in JOIN_BROADCAST message")
	}

	if offer, ok = objectProp(message, "offer"); !ok {
		sendErrorMessage(conn, "No \"offer\" property not specified or not an object in JOIN_BROADCAST message")
	}

	if broadcast, ok := broadcasts[name]; ok {

		// FIXME: need to actually build a proper tree and insert this new connection into the right place.
		// For now everyone just connects directly to the broadcaster.
		globalLock.Lock()
		defer globalLock.Unlock()

		parent := broadcast
		node := TreeNode{
			conn:   conn,
			id:     id,
			parent: parent,
		}
		connections[id] = conn
		parent.children = append(node.parent.children, &node)

		parent.conn.WriteJSON(struct {
			Command string                 `json:"command"`
			Peer    string                 `json:"peer"`
			Offer   map[string]interface{} `json:"offer"`
		}{
			"RELAY_BROADCAST",
			id,
			offer,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown broadcast: %v", name))
}

func commandRelayBroadCastReceived(conn *websocket.Conn, id string, message map[string]interface{}) {
	var peer string
	var answer map[string]interface{}
	var ok bool

	if peer, ok = stringProp(message, "peer"); !ok {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in RELAY_BROADCAST_RECEIVED message")
	}

	if answer, ok = objectProp(message, "answer"); !ok {
		sendErrorMessage(conn, "No \"answer\" property not specified or not an object in RELAY_BROADCAST_RECEIVED message")
	}

	if peerConnection, ok := connections[peer]; ok {
		peerConnection.WriteJSON(struct {
			Command string                 `json:"command"`
			Peer    string                 `json:"peer"`
			Answer  map[string]interface{} `json:"answer"`
		}{
			"JOIN_BROADCAST_RECEIVED",
			id,
			answer,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
}

func commandIceCandidates(conn *websocket.Conn, id string, message map[string]interface{}) {
	var peer string
	var candidates []interface{}
	var ok bool

	if peer, ok = stringProp(message, "peer"); !ok {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in ICE_CANDIDATE message")
	}

	if candidates, ok = arrayProp(message, "candidates"); !ok {
		sendErrorMessage(conn, "No \"candidates\" property not specified or not an array in ICE_CANDIDATE message")
	}

	if peerConnection, ok := connections[peer]; ok {
		peerConnection.WriteJSON(struct {
			Command    string        `json:"command"`
			Peer       string        `json:"peer"`
			Candidates []interface{} `json:"candidates"`
		}{
			"ICE_CANDIDATES",
			id,
			candidates,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
}

func commandIceCandidatesReceived(conn *websocket.Conn, id string, message map[string]interface{}) {
	if peer, ok := stringProp(message, "peer"); ok {
		if peerConnection, ok := connections[peer]; ok {
			peerConnection.WriteJSON(struct {
				Command string `json:"command"`
				Peer    string `json:"peer"`
			}{
				"ICE_CANDIDATES_RECEIVED",
				id,
			})
			return
		}

		sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
	} else {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in ICE_CANDIDATE message")
	}
}

func sendErrorMessage(conn *websocket.Conn, message string) {
	log.Println(message)
	conn.WriteJSON(struct {
		Message string `json:"message"`
	}{message})
}

func sendErrorMessageAndCode(conn *websocket.Conn, message string, errorCode int) {
	log.Println(message)
	conn.WriteJSON(struct {
		Message string `json:"message"`
		Code    int    `json:"code"`
	}{
		message,
		errorCode,
	})
}
<commit_msg>There is now a proper tree structure for the peers<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/satori/go.uuid"
	"log"
	"net/http"
	"sync"
)

type CommandHandlerFunc func(conn *websocket.Conn, id string, message map[string]interface{})
type TreeNode struct {
	conn     *websocket.Conn
	id       string
	children []*TreeNode
	parent   *TreeNode
}

var (
	port         = flag.Int("port", 8081, "Port the server listens on")
	maxListeners = flag.Int("max-listeners", 3, "Max number of listeners (WebRTC peers) for a single client")
	upgrader     = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	commandHandlers = map[string]CommandHandlerFunc{
		"START_BROADCAST":          commandStartBroadcast,
		"JOIN_BROADCAST":           commandJoinBroadcast,
		"RELAY_BROADCAST_RECEIVED": commandRelayBroadCastReceived,
		"ICE_CANDIDATES":           commandIceCandidates,
		"ICE_CANDIDATES_RECEIVED":  commandIceCandidatesReceived,
	}
	broadcasts  = map[string]*TreeNode{}
	connections = map[string]*websocket.Conn{}
	globalLock  = new(sync.Mutex) // FIXME: yeah, I know it's horrible, but we'll fix it later
)

func main() {
	http.HandleFunc("/api/ws", handleWebSocket)
	log.Println("Server starting on port", *port)
	log.Fatal("ListenAndServe:", http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	log.Println("Incoming", r.Method, "message")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Failed to upgrade:", err)
		return
	}

	id := uuid.NewV4().String()

	for {
		var rawMessage interface{}
		if err := conn.ReadJSON(&rawMessage); err != nil {
			log.Printf("Read error: %v\n", err)
			conn.Close()
			return
		}

		messageObject, ok := rawMessage.(map[string]interface{})
		if !ok {
			sendErrorMessage(conn, "Message is not a JSON object")
			continue
		}

		command, ok := messageObject["command"].(string)
		if !ok {
			sendErrorMessage(conn, "Message is lacking a command property")
			continue
		}

		log.Printf("Received command: %v\n", command)
		if commandHandler, ok := commandHandlers[command]; ok {
			commandHandler(conn, id, messageObject)
		} else {
			sendErrorMessage(conn, fmt.Sprintf("Unknown command: %v", command))
			continue
		}
	}
}

func commandStartBroadcast(conn *websocket.Conn, id string, message map[string]interface{}) {
	if name, ok := stringProp(message, "name"); ok {
		log.Printf("Peer %v starting broadcast: %v", id, name)

		globalLock.Lock()
		defer globalLock.Unlock()

		broadcasts[name] = &TreeNode{
			conn: conn,
			id:   id,
		}
		connections[id] = conn

		conn.WriteJSON(struct {
			Command string `json:"command"`
		}{
			"START_BROADCAST_RECEIVED",
		})
		return
	}

	sendErrorMessage(conn, "No \"name\" property not specified or not a string in START_BROADCAST message")
}

func commandJoinBroadcast(conn *websocket.Conn, id string, message map[string]interface{}) {
	var name string
	var offer map[string]interface{}
	var ok bool

	if name, ok = stringProp(message, "name"); !ok {
		sendErrorMessage(conn, "No \"name\" property not specified or not a string in JOIN_BROADCAST message")
	}

	if offer, ok = objectProp(message, "offer"); !ok {
		sendErrorMessage(conn, "No \"offer\" property not specified or not an object in JOIN_BROADCAST message")
	}

	if broadcast, ok := broadcasts[name]; ok {
		globalLock.Lock()
		defer globalLock.Unlock()

		parent := findNodeWithSpareCapacity(broadcast)
		if parent == nil {
			log.Panic("Received a nil node when inserting: %+v", broadcast)
		}

		node := TreeNode{
			conn:   conn,
			id:     id,
			parent: parent,
		}
		connections[id] = conn
		parent.children = append(node.parent.children, &node)

		log.Printf("Peer %v joining broadcast %v as a child of %v which now has %d child(ren)\n",
			id, name, parent.id, len(parent.children))

		parent.conn.WriteJSON(struct {
			Command string                 `json:"command"`
			Peer    string                 `json:"peer"`
			Offer   map[string]interface{} `json:"offer"`
		}{
			"RELAY_BROADCAST",
			id,
			offer,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown broadcast: %v", name))
}

func commandRelayBroadCastReceived(conn *websocket.Conn, id string, message map[string]interface{}) {
	var peer string
	var answer map[string]interface{}
	var ok bool

	if peer, ok = stringProp(message, "peer"); !ok {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in RELAY_BROADCAST_RECEIVED message")
	}

	if answer, ok = objectProp(message, "answer"); !ok {
		sendErrorMessage(conn, "No \"answer\" property not specified or not an object in RELAY_BROADCAST_RECEIVED message")
	}

	log.Printf("Peer %v responding to %p with answer: %+v\n", id, peer, answer)

	if peerConnection, ok := connections[peer]; ok {
		peerConnection.WriteJSON(struct {
			Command string                 `json:"command"`
			Peer    string                 `json:"peer"`
			Answer  map[string]interface{} `json:"answer"`
		}{
			"JOIN_BROADCAST_RECEIVED",
			id,
			answer,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
}

func commandIceCandidates(conn *websocket.Conn, id string, message map[string]interface{}) {
	var peer string
	var candidates []interface{}
	var ok bool

	if peer, ok = stringProp(message, "peer"); !ok {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in ICE_CANDIDATE message")
	}

	if candidates, ok = arrayProp(message, "candidates"); !ok {
		sendErrorMessage(conn, "No \"candidates\" property not specified or not an array in ICE_CANDIDATE message")
	}

	log.Printf("Peer %v sending ICE candidates to peer %v: %+v", id, peer, candidates)

	if peerConnection, ok := connections[peer]; ok {
		peerConnection.WriteJSON(struct {
			Command    string        `json:"command"`
			Peer       string        `json:"peer"`
			Candidates []interface{} `json:"candidates"`
		}{
			"ICE_CANDIDATES",
			id,
			candidates,
		})
		return
	}

	sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
}

func commandIceCandidatesReceived(conn *websocket.Conn, id string, message map[string]interface{}) {
	if peer, ok := stringProp(message, "peer"); ok {
		if peerConnection, ok := connections[peer]; ok {

			log.Printf("Peer %v ack-ing ICE candidates from peer %v", id, peer)

			peerConnection.WriteJSON(struct {
				Command string `json:"command"`
				Peer    string `json:"peer"`
			}{
				"ICE_CANDIDATES_RECEIVED",
				id,
			})
			return
		}

		sendErrorMessage(conn, fmt.Sprintf("Unknown peer: %v", peer))
	} else {
		sendErrorMessage(conn, "No \"peer\" property not specified or not a string in ICE_CANDIDATE message")
	}
}

func findNodeWithSpareCapacity(root *TreeNode) *TreeNode {
	queue := []*TreeNode{root}
	var node *TreeNode

	for len(queue) > 0 {
		node, queue = queue[0], queue[1:]

		// FIXME: we can be more clever here in order to spread the load between the children better
		if len(node.children) < *maxListeners {
			return node
		}

		queue = append(queue, node.children...)
	}

	return nil
}

func sendErrorMessage(conn *websocket.Conn, message string) {
	log.Println(message)
	conn.WriteJSON(struct {
		Message string `json:"message"`
	}{message})
}

func sendErrorMessageAndCode(conn *websocket.Conn, message string, errorCode int) {
	log.Println(message)
	conn.WriteJSON(struct {
		Message string `json:"message"`
		Code    int    `json:"code"`
	}{
		message,
		errorCode,
	})
}
<|endoftext|>


<commit_before>package haaasd

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"os/exec"
	"time"
)

func NewHaproxy(role string, properties *Config, version string, context Context) *Haproxy {
	if version == "" {
		version = "1.4.22"
	}
	return &Haproxy{
		Role:             role,
		properties:  properties,
		Version:     version,
		Context: context,
	}
}

type Haproxy struct {
	Role        string
	Version     string
	properties  *Config
	State       int
	Context     Context
}

const (
	SUCCESS int = iota
	UNCHANGED int = iota
	ERR_SYSLOG int = iota
	ERR_CONF int = iota
	ERR_RELOAD int = iota
)

// ApplyConfiguration write the new configuration and reload
// A rollback is called on failure
func (hap *Haproxy) ApplyConfiguration(data *EventMessage) (int, error) {
	hap.createSkeleton(data.CorrelationId)

	newConf := data.Conf
	path := hap.confPath()

	// Check conf diff
	oldConf, err := ioutil.ReadFile(path)
	if log.GetLevel() == log.DebugLevel {
		hap.dumpConfiguration(hap.NewDebugPath(), newConf, data)
	}
	if bytes.Equal(oldConf, newConf) {
		log.WithFields(hap.Context.Fields()).WithFields(
			log.Fields{"role": hap.Role,
			}).Debug("Unchanged configuration")
		return UNCHANGED, nil
	}

	// Archive previous configuration
	archivePath := hap.confArchivePath()
	os.Rename(path, archivePath)
	log.WithFields(hap.Context.Fields()).WithFields(
		log.Fields{
			"role": hap.Role,
			"archivePath": archivePath,
		}).Info("Old configuration saved")
	err = ioutil.WriteFile(path, newConf, 0644)
	if err != nil {
		return ERR_CONF, err
	}

	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"path": path,
	}).Info("New configuration written")

	// Reload haproxy
	err = hap.reload(data.CorrelationId)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Reload failed")
		hap.dumpConfiguration(hap.NewErrorPath(), newConf, data)
		errRollback := hap.rollback(data.CorrelationId)
		if errRollback != nil {
			log.WithError(errRollback).Error("error in rollback in addition to error of the reload")
		} else {
			log.WithFields(hap.Context.Fields()).Debug("rollback done")
		}
		return ERR_RELOAD, err
	}
	// Write syslog fragment
	fragmentPath := hap.syslogFragmentPath()
	err = ioutil.WriteFile(fragmentPath, data.SyslogFragment, 0644)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Failed to write syslog fragment")
		// TODO Should we rollback on syslog error ?
		return ERR_SYSLOG, err
	}
	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"content" : string(data.SyslogFragment),
		"filename": fragmentPath,
	}).Debug("Write syslog fragment")

	return SUCCESS, nil
}

// dumpConfiguration dumps the new configuration file with context for debugging purpose
func (hap *Haproxy) dumpConfiguration(filename string, newConf []byte, data *EventMessage) {
	f, err2 := os.Create(filename)
	defer f.Close()
	if err2 == nil {
		f.WriteString("================================================================\n")
		f.WriteString(fmt.Sprintf("application: %s\n", data.Application))
		f.WriteString(fmt.Sprintf("platform: %s\n", data.Platform))
		f.WriteString(fmt.Sprintf("correlationId: %s\n", data.CorrelationId))
		f.WriteString("================================================================\n")
		f.Write(newConf)
		f.Sync()

		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
			"filename": filename,
		}).Info("Dump configuration")
	}
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) confPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/Config"
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// confPath give the path of the archived configuration file given an application context
func (hap *Haproxy) confArchivePath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/version-1"
	// It returns the absolute path to the file
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// NewErrorPath gives a unique path the error file given the hap context
// It returns the full path to the file
func (hap *Haproxy) NewErrorPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/errors"
	os.MkdirAll(baseDir, 0755)
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

func (hap *Haproxy) NewDebugPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/dump"
	os.MkdirAll(baseDir, 0755)
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

// reload calls external shell script to reload haproxy
// It returns error if the reload fails
func (hap *Haproxy) reload(correlationId string) error {

	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "reload", "-y").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error reloading")
	}
	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"reloadScript": reloadScript,
		"cmd": string(output[:]),
	}).Debug("Reload succeeded")
	return err
}

// rollback reverts configuration files and call for reload
func (hap *Haproxy) rollback(correlationId string) error {
	lastConf := hap.confArchivePath()
	if _, err := os.Stat(lastConf); os.IsNotExist(err) {
		return errors.New("No configuration file to rollback")
	}
	// TODO remove current hap.confPath() ?
	os.Rename(lastConf, hap.confPath())
	hap.reload(correlationId)
	return nil
}

// createSkeleton creates the directory tree for a new haproxy context
func (hap *Haproxy) createSkeleton(correlationId string) error {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application

	createDirectory(hap.Context, correlationId, baseDir + "/Config")
	createDirectory(hap.Context, correlationId, baseDir + "/logs/" + hap.Context.Application + hap.Context.Platform)
	createDirectory(hap.Context, correlationId, baseDir + "/scripts")
	createDirectory(hap.Context, correlationId, baseDir + "/version-1")

	updateSymlink(hap.Context, correlationId, hap.getHapctlFilename(), hap.getReloadScript())
	updateSymlink(hap.Context, correlationId, hap.getHapBinary(), baseDir + "/Config/haproxy")

	return nil
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) syslogFragmentPath() string {
	baseDir := hap.properties.HapHome + "/SYSLOG/Config/syslog.conf.d"
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/syslog" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// updateSymlink create or update a symlink
func updateSymlink(context Context, correlationId, oldname, newname string) {
	newLink := true
	if _, err := os.Stat(newname); err == nil {
		os.Remove(newname)
		newLink = false
	}
	err := os.Symlink(oldname, newname)
	if err != nil {
		log.WithFields(context.Fields()).WithError(err).WithFields(log.Fields{
			"path": newname,
		}).Error("Symlink failed")
	}

	if newLink {
		log.WithFields(context.Fields()).WithFields(log.Fields{
			"path": newname,
		}).Info("Symlink created")
	}
}

// createDirectory recursively creates directory if it doesn't exists
func createDirectory(context Context, correlationId string, dir string) {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			log.WithError(err).WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Error("Failed to create")
		} else {
			log.WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Info("Directory created")
		}
	}
}

// getHapctlFilename return the path to the vsc hapctl shell script
// This script is provided
func (hap *Haproxy) getHapctlFilename() string {
	return "/HOME/uxwadm/scripts/hapctl_unif"
}

// getReloadScript calculates reload script path given the hap context
// It returns the full script path
func (hap *Haproxy) getReloadScript() string {
	return fmt.Sprintf("%s/%s/scripts/hapctl%s%s", hap.properties.HapHome, hap.Context.Application, hap.Context.Application, hap.Context.Platform)
}

// getHapBinary calculates the haproxy binary to use given the expected version
// It returns the full path to the haproxy binary
func (hap *Haproxy) getHapBinary() string {
	return fmt.Sprintf("/export/product/haproxy/product/%s/bin/haproxy", hap.Version)
}
<commit_msg>remove extra mkdirAll and added missing ones in createSkeleton<commit_after>package haaasd

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"os/exec"
	"time"
)

func NewHaproxy(role string, properties *Config, version string, context Context) *Haproxy {
	if version == "" {
		version = "1.4.22"
	}
	return &Haproxy{
		Role:             role,
		properties:  properties,
		Version:     version,
		Context: context,
	}
}

type Haproxy struct {
	Role       string
	Version    string
	properties *Config
	State      int
	Context    Context
}

const (
	SUCCESS int = iota
	UNCHANGED int = iota
	ERR_SYSLOG int = iota
	ERR_CONF int = iota
	ERR_RELOAD int = iota
)

// ApplyConfiguration write the new configuration and reload
// A rollback is called on failure
func (hap *Haproxy) ApplyConfiguration(data *EventMessage) (int, error) {
	hap.createSkeleton(data.CorrelationId)

	newConf := data.Conf
	path := hap.confPath()

	// Check conf diff
	oldConf, err := ioutil.ReadFile(path)
	if log.GetLevel() == log.DebugLevel {
		hap.dumpConfiguration(hap.NewDebugPath(), newConf, data)
	}
	if bytes.Equal(oldConf, newConf) {
		log.WithFields(hap.Context.Fields()).WithFields(
			log.Fields{"role": hap.Role,
			}).Debug("Unchanged configuration")
		return UNCHANGED, nil
	}

	// Archive previous configuration
	archivePath := hap.confArchivePath()
	os.Rename(path, archivePath)
	log.WithFields(hap.Context.Fields()).WithFields(
		log.Fields{
			"role": hap.Role,
			"archivePath": archivePath,
		}).Info("Old configuration saved")
	err = ioutil.WriteFile(path, newConf, 0644)
	if err != nil {
		return ERR_CONF, err
	}

	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"path": path,
	}).Info("New configuration written")

	// Reload haproxy
	err = hap.reload(data.CorrelationId)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Reload failed")
		hap.dumpConfiguration(hap.NewErrorPath(), newConf, data)
		errRollback := hap.rollback(data.CorrelationId)
		if errRollback != nil {
			log.WithError(errRollback).Error("error in rollback in addition to error of the reload")
		} else {
			log.WithFields(hap.Context.Fields()).Debug("rollback done")
		}
		return ERR_RELOAD, err
	}
	// Write syslog fragment
	fragmentPath := hap.syslogFragmentPath()
	err = ioutil.WriteFile(fragmentPath, data.SyslogFragment, 0644)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Failed to write syslog fragment")
		// TODO Should we rollback on syslog error ?
		return ERR_SYSLOG, err
	}
	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"content" : string(data.SyslogFragment),
		"filename": fragmentPath,
	}).Debug("Write syslog fragment")

	return SUCCESS, nil
}

// dumpConfiguration dumps the new configuration file with context for debugging purpose
func (hap *Haproxy) dumpConfiguration(filename string, newConf []byte, data *EventMessage) {
	f, err2 := os.Create(filename)
	defer f.Close()
	if err2 == nil {
		f.WriteString("================================================================\n")
		f.WriteString(fmt.Sprintf("application: %s\n", data.Application))
		f.WriteString(fmt.Sprintf("platform: %s\n", data.Platform))
		f.WriteString(fmt.Sprintf("correlationId: %s\n", data.CorrelationId))
		f.WriteString("================================================================\n")
		f.Write(newConf)
		f.Sync()

		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
			"filename": filename,
		}).Info("Dump configuration")
	}
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) confPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/Config"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// confPath give the path of the archived configuration file given an application context
func (hap *Haproxy) confArchivePath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/version-1"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// NewErrorPath gives a unique path the error file given the hap context
// It returns the full path to the file
func (hap *Haproxy) NewErrorPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/errors"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

func (hap *Haproxy) NewDebugPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/dump"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

// reload calls external shell script to reload haproxy
// It returns error if the reload fails
func (hap *Haproxy) reload(correlationId string) error {
	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "reload", "-y").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error reloading")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
			"reloadScript": reloadScript,
			"cmd": string(output[:]),
		}).Debug("Reload succeeded")
	}
	return err
}

// rollback reverts configuration files and call for reload
func (hap *Haproxy) rollback(correlationId string) error {
	lastConf := hap.confArchivePath()
	if _, err := os.Stat(lastConf); os.IsNotExist(err) {
		return errors.New("No configuration file to rollback")
	}
	// TODO remove current hap.confPath() ?
	os.Rename(lastConf, hap.confPath())
	hap.reload(correlationId)
	return nil
}

// createSkeleton creates the directory tree for a new haproxy context
func (hap *Haproxy) createSkeleton(correlationId string) error {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application

	createDirectory(hap.Context, correlationId, baseDir + "/Config")
	createDirectory(hap.Context, correlationId, baseDir + "/logs/" + hap.Context.Application + hap.Context.Platform)
	createDirectory(hap.Context, correlationId, baseDir + "/scripts")
	createDirectory(hap.Context, correlationId, baseDir + "/version-1")
	createDirectory(hap.Context, correlationId, baseDir + "/errors")
	createDirectory(hap.Context, correlationId, baseDir + "/dump")

	updateSymlink(hap.Context, correlationId, hap.getHapctlFilename(), hap.getReloadScript())
	updateSymlink(hap.Context, correlationId, hap.getHapBinary(), baseDir + "/Config/haproxy")

	return nil
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) syslogFragmentPath() string {
	baseDir := hap.properties.HapHome + "/SYSLOG/Config/syslog.conf.d"
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/syslog" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// updateSymlink create or update a symlink
func updateSymlink(context Context, correlationId, oldname, newname string) {
	newLink := true
	if _, err := os.Stat(newname); err == nil {
		os.Remove(newname)
		newLink = false
	}
	err := os.Symlink(oldname, newname)
	if err != nil {
		log.WithFields(context.Fields()).WithError(err).WithFields(log.Fields{
			"path": newname,
		}).Error("Symlink failed")
	}

	if newLink {
		log.WithFields(context.Fields()).WithFields(log.Fields{
			"path": newname,
		}).Info("Symlink created")
	}
}

// createDirectory recursively creates directory if it doesn't exists
func createDirectory(context Context, correlationId string, dir string) {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			log.WithError(err).WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Error("Failed to create")
		} else {
			log.WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Info("Directory created")
		}
	}
}

// getHapctlFilename return the path to the vsc hapctl shell script
// This script is provided
func (hap *Haproxy) getHapctlFilename() string {
	return "/HOME/uxwadm/scripts/hapctl_unif"
}

// getReloadScript calculates reload script path given the hap context
// It returns the full script path
func (hap *Haproxy) getReloadScript() string {
	return fmt.Sprintf("%s/%s/scripts/hapctl%s%s", hap.properties.HapHome, hap.Context.Application, hap.Context.Application, hap.Context.Platform)
}

// getHapBinary calculates the haproxy binary to use given the expected version
// It returns the full path to the haproxy binary
func (hap *Haproxy) getHapBinary() string {
	return fmt.Sprintf("/export/product/haproxy/product/%s/bin/haproxy", hap.Version)
}
<|endoftext|>