<commit_before>package manager

import (
	"fmt"
	"github.com/ChaosXu/nerv/lib/log"
	"github.com/ChaosXu/nerv/lib/lock"
	"github.com/ChaosXu/nerv/lib/deploy/model/topology"
	"time"
	"github.com/ChaosXu/nerv/lib/db"
	templaterep "github.com/ChaosXu/nerv/lib/deploy/repository"
	classrep "github.com/ChaosXu/nerv/lib/resource/repository"
	"github.com/ChaosXu/nerv/lib/resource/executor"
	"k8s.io/kubernetes/pkg/util/json"
)

// Deployer execute the deployment task.
type Deployer struct {
	DBService   *db.DBService `inject:""`
	TemplateRep templaterep.TemplateRepository `inject:""`
	ClassRep    classrep.ClassRepository `inject:""`
	Executor    executor.Executor `inject:""`
}

//Install the topology and start to serve
func (p *Deployer) Install(topoName string, templatePath string) error {
	log.LogCodeLine()
	template, err := p.TemplateRep.GetTemplate(templatePath)
	if err != nil {
		return err
	}
	topo := template.NewTopology(topoName)
	if err := p.dump(topo); err != nil {
		return err
	}
	p.DBService.GetDB().Save(topo)
	return p.postTraverse(topo, "contained", "Create")
}

func (p *Deployer) dump(topo *topology.Topology) error {
	data, err := json.Marshal(topo)
	if err != nil {
		return err
	}

	fmt.Println(string(data))
	return nil
}

//Uninstall the topology
func (p *Deployer) Uninstall(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.preTraverse(topology, "contained", "Delete")
}

//Configure the topology for start
func (p *Deployer) Configure(topology *topology.Topology) error {
	return fmt.Errorf("TBD")
}

//Start the Topology
func (p *Deployer) Start(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.postTraverse(topology, "contained", "Start")
}

//Stop the Topology
func (p *Deployer) Stop(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.preTraverse(topology, "contained", "Stop")
}

func (p *Deployer) preTraverse(topo *topology.Topology, depType string, operation string) error {
	lock := lock.GetLock("Topology", topo.ID)
	if !lock.TryLock() {
		return fmt.Errorf("topology is doing. ID=%d", topo.ID)
	}
	defer lock.Unlock()

	tnodes := []*topology.Node{}
	p.DBService.GetDB().Where("topology_id =?", topo.ID).Preload("Links").Find(&tnodes)
	topo.Nodes = tnodes

	template := topology.ServiceTemplate{}
	if err := p.DBService.GetDB().Where("name=? and version=?", topo.Template, topo.Version).Preload("Nodes").Preload("Nodes.Parameters").First(&template).Error; err != nil {
		return err
	}

	dones := []<-chan error{}
	timeouts := []<-chan bool{}

	for _, node := range topo.Nodes {
		done, timeout := p.preTraverseNode(topo, depType, node, &template, operation)
		dones = append(dones, done)
		timeouts = append(timeouts, timeout)
	}

	var err error = nil
	for i, done := range dones {
		select {
		case e := <-done:
			if e != nil {
				err = e
			}
		case <-timeouts[i]:
			fmt.Println("timeout")
		}
	}

	if err == nil {
		topo.RunStatus = topology.RunStatusGreen
	} else {
		topo.Error = err.Error()
		topo.RunStatus = topology.RunStatusRed
	}
	p.DBService.GetDB().Save(topo)
	return err
}

func (p *Deployer) postTraverse(topo *topology.Topology, depType string, operation string) error {
	lock := lock.GetLock("Topology", topo.ID)
	if !lock.TryLock() {
		return fmt.Errorf("topology is doing. ID=%d", topo.ID)
	}
	defer lock.Unlock()

	tnodes := []*topology.Node{}
	p.DBService.GetDB().Where("topology_id =?", topo.ID).Preload("Links").Find(&tnodes)
	topo.Nodes = tnodes

	template, err := p.TemplateRep.GetTemplate(topo.Template)
	if err != nil {
		return err
	}

	dones := []<-chan error{}
	timeouts := []<-chan bool{}

	for _, node := range topo.Nodes {
		done, timeout := p.postTraverseNode(topo, depType, node, template, operation)
		dones = append(dones, done)
		timeouts = append(timeouts, timeout)
	}

	for i, done := range dones {
		select {
		case e := <-done:
			if e != nil {
				err = e
			}
		case <-timeouts[i]:
			fmt.Println("timeout")
		}
	}

	if err == nil {
		topo.RunStatus = topology.RunStatusGreen
	} else {
		topo.Error = err.Error()
		topo.RunStatus = topology.RunStatusRed
	}
	p.DBService.GetDB().Save(topo)
	return err
}

func (p *Deployer) preTraverseNode(topo *topology.Topology, depType string, parent *topology.Node, template *topology.ServiceTemplate, operation string) (<-chan error, <-chan bool) {
	err, timeout := p.executeNode(operation, parent, template)
	select {
	case e := <-err:
		ec := make(chan error, 1)
		ec <- e
		return ec, timeout
	case <-timeout:
		fmt.Println("timeout")
	}

	var childErr error = nil
	var childTimeout bool

	links := parent.FindLinksByType(depType)
	if links != nil && len(links) > 0 {
		dones := []<-chan error{}
		timeouts := []<-chan bool{}
		for _, link := range links {
			node := topo.GetNode(link.Target)
			done, timeout := p.preTraverseNode(topo, depType, node, template, operation)
			dones = append(dones, done)
			timeouts = append(timeouts, timeout)
		}

		for i, done := range dones {
			select {
			case e := <-done:
				if e != nil {
					childErr = e
				}
			case t := <-timeouts[i]:
				if t {
					childTimeout = t
					fmt.Println("timeout")
				}
			}
		}
	}

	dc := make(chan error, 1)
	tc := make(chan bool, 1)

	if err == nil {
		dc <- childErr
	}
	if timeout == nil {
		tc <- childTimeout
	}
	return dc, tc
}

func (p *Deployer) postTraverseNode(topo *topology.Topology, depType string, parent *topology.Node, template *topology.ServiceTemplate, operation string) (<-chan error, <-chan bool) {
	links := parent.FindLinksByType(depType)
	if links != nil && len(links) > 0 {
		dones := []<-chan error{}
		timeouts := []<-chan bool{}
		for _, link := range links {
			node := topo.GetNode(link.Target)
			done, timeout := p.postTraverseNode(topo, depType, node, template, operation)
			dones = append(dones, done)
			timeouts = append(timeouts, timeout)
		}

		var err error = nil
		for i, done := range dones {
			select {
			case e := <-done:
				if e != nil {
					err = e
				}
			case <-timeouts[i]:
				fmt.Println("timeout")
			}
		}

		if err == nil {
			return p.executeNode(operation, parent, template)
		} else {
			done := make(chan error, 1)
			timeout := make(chan bool, 1)
			done <- err
			return done, timeout
		}
	} else {
		return p.executeNode(operation, parent, template)
	}
}

func (p *Deployer) executeNode(operation string, node *topology.Node, template *topology.ServiceTemplate) (<-chan error, <-chan bool) {

	if node.Done == nil {
		node.Done = make(chan error, 1)
		node.Timeout = make(chan bool, 1)

		go func() {
			time.Sleep(30 * time.Second)
			node.Timeout <- true
			close(node.Timeout)
		}()

		go func() {
			if err := p.invoke(node, operation, template); err != nil {
				node.Done <- err

			} else {
				node.Done <- nil
			}
			close(node.Done)
		}()
	} else {
		fmt.Println("doing")
	}

	return node.Done, node.Timeout
}

// invoke the operation
func (p *Deployer) invoke(node *topology.Node, operation string, template *topology.ServiceTemplate) error {
	log.LogCodeLine()

	nodeTemplate := template.FindTemplate(node.Template)

	if nodeTemplate == nil {
		node.RunStatus = topology.RunStatusRed
		err := fmt.Errorf("template %s of node %s isn't exist", node.Template, node.Name)
		return err
	}
	node.RunStatus = topology.RunStatusGreen

	args := map[string]string{}
	for _, param := range nodeTemplate.Parameters {
		args[param.Name] = param.Value
	}

	class, err := p.ClassRep.Get(nodeTemplate.Type)
	if err != nil {
		return err
	}

	err = p.Executor.Perform(class, operation, args)
	if err != nil {
		node.RunStatus = topology.RunStatusRed
		node.Error = fmt.Errorf("%s execute %s error:%s", node.Name, operation, err.Error()).Error()

	} else {
		node.RunStatus = topology.RunStatusGreen
	}

	p.DBService.GetDB().Save(node)
	return err
}

<commit_msg>fix executeNode: check error when done<commit_after>package manager

import (
	"fmt"
	"github.com/ChaosXu/nerv/lib/log"
	"github.com/ChaosXu/nerv/lib/lock"
	"github.com/ChaosXu/nerv/lib/deploy/model/topology"
	"time"
	"github.com/ChaosXu/nerv/lib/db"
	templaterep "github.com/ChaosXu/nerv/lib/deploy/repository"
	classrep "github.com/ChaosXu/nerv/lib/resource/repository"
	"github.com/ChaosXu/nerv/lib/resource/executor"
	"k8s.io/kubernetes/pkg/util/json"
)

// PerformStatus trace the status of node executing
type PerformStatus struct {
	Node    *topology.Node
	Done    <-chan error
	Timeout <-chan bool
}

// Deployer execute the deployment task.
type Deployer struct {
	DBService   *db.DBService `inject:""`
	TemplateRep templaterep.TemplateRepository `inject:""`
	ClassRep    classrep.ClassRepository `inject:""`
	Executor    executor.Executor `inject:""`
}

//Install the topology and start to serve
func (p *Deployer) Install(topoName string, templatePath string) error {
	log.LogCodeLine()
	template, err := p.TemplateRep.GetTemplate(templatePath)
	if err != nil {
		return err
	}
	topo := template.NewTopology(topoName)
	if err := p.dump(topo); err != nil {
		return err
	}
	p.DBService.GetDB().Save(topo)
	return p.postTraverse(topo, "contained", "Create")
}

func (p *Deployer) dump(topo *topology.Topology) error {
	data, err := json.Marshal(topo)
	if err != nil {
		return err
	}

	fmt.Println(string(data))
	return nil
}

//Uninstall the topology
func (p *Deployer) Uninstall(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.preTraverse(topology, "contained", "Delete")
}

//Configure the topology for start
func (p *Deployer) Configure(topology *topology.Topology) error {
	return fmt.Errorf("TBD")
}

//Start the Topology
func (p *Deployer) Start(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.postTraverse(topology, "contained", "Start")
}

//Stop the Topology
func (p *Deployer) Stop(topology *topology.Topology) error {
	log.LogCodeLine()
	return p.preTraverse(topology, "contained", "Stop")
}

func (p *Deployer) preTraverse(topo *topology.Topology, depType string, operation string) error {
	lock := lock.GetLock("Topology", topo.ID)
	if !lock.TryLock() {
		return fmt.Errorf("topology is doing. ID=%d", topo.ID)
	}
	defer lock.Unlock()

	tnodes := []*topology.Node{}
	p.DBService.GetDB().Where("topology_id =?", topo.ID).Preload("Links").Find(&tnodes)
	topo.Nodes = tnodes

	template := topology.ServiceTemplate{}
	if err := p.DBService.GetDB().Where("name=? and version=?", topo.Template, topo.Version).Preload("Nodes").Preload("Nodes.Parameters").First(&template).Error; err != nil {
		return err
	}

	dones := []<-chan error{}
	timeouts := []<-chan bool{}

	for _, node := range topo.Nodes {
		done, timeout := p.preTraverseNode(topo, depType, node, &template, operation)
		dones = append(dones, done)
		timeouts = append(timeouts, timeout)
	}

	var err error = nil
	for i, done := range dones {
		select {
		case e := <-done:
			if e != nil {
				err = e
			}
		case <-timeouts[i]:
			fmt.Println("timeout")
		}
	}

	if err == nil {
		topo.RunStatus = topology.RunStatusGreen
	} else {
		topo.Error = err.Error()
		topo.RunStatus = topology.RunStatusRed
	}
	p.DBService.GetDB().Save(topo)
	return err
}

func (p *Deployer) postTraverse(topo *topology.Topology, depType string, operation string) error {
	lock := lock.GetLock("Topology", topo.ID)
	if !lock.TryLock() {
		return fmt.Errorf("topology is doing. ID=%d", topo.ID)
	}
	defer lock.Unlock()

	tnodes := []*topology.Node{}
	p.DBService.GetDB().Where("topology_id =?", topo.ID).Preload("Links").Find(&tnodes)
	topo.Nodes = tnodes

	template, err := p.TemplateRep.GetTemplate(topo.Template)
	if err != nil {
		return err
	}

	dones := []<-chan error{}
	timeouts := []<-chan bool{}

	for _, node := range topo.Nodes {
		done, timeout := p.postTraverseNode(topo, depType, node, template, operation)
		dones = append(dones, done)
		timeouts = append(timeouts, timeout)
	}

	for i, done := range dones {
		select {
		case e := <-done:
			if e != nil {
				err = e
			}
		case <-timeouts[i]:
			fmt.Println("timeout")
		}
	}

	if err == nil {
		topo.RunStatus = topology.RunStatusGreen
	} else {
		topo.Error = err.Error()
		topo.RunStatus = topology.RunStatusRed
	}
	p.DBService.GetDB().Save(topo)
	return err
}

func (p *Deployer) preTraverseNode(topo *topology.Topology, depType string, parent *topology.Node, template *topology.ServiceTemplate, operation string) (<-chan error, <-chan bool) {
	err, timeout := p.executeNode(operation, parent, template)
	select {
	case e := <-err:
		ec := make(chan error, 1)
		ec <- e
		return ec, timeout
	case <-timeout:
		fmt.Println("timeout")
	}

	var childErr error = nil
	var childTimeout bool

	links := parent.FindLinksByType(depType)
	if links != nil && len(links) > 0 {
		dones := []<-chan error{}
		timeouts := []<-chan bool{}
		for _, link := range links {
			node := topo.GetNode(link.Target)
			done, timeout := p.preTraverseNode(topo, depType, node, template, operation)
			dones = append(dones, done)
			timeouts = append(timeouts, timeout)
		}

		for i, done := range dones {
			select {
			case e := <-done:
				if e != nil {
					childErr = e
				}
			case t := <-timeouts[i]:
				if t {
					childTimeout = t
					fmt.Println("timeout")
				}
			}
		}
	}

	dc := make(chan error, 1)
	tc := make(chan bool, 1)

	if err == nil {
		dc <- childErr
	}
	if timeout == nil {
		tc <- childTimeout
	}
	return dc, tc
}

func (p *Deployer) postTraverseNode(topo *topology.Topology, depType string, parent *topology.Node, template *topology.ServiceTemplate, operation string) (<-chan error, <-chan bool) {
	links := parent.FindLinksByType(depType)
	if links != nil && len(links) > 0 {
		dones := []PerformStatus{}
		for _, link := range links {
			node := topo.GetNode(link.Target)
			done, timeout := p.postTraverseNode(topo, depType, node, template, operation)
			dones = append(dones, PerformStatus{Node:node, Done:done, Timeout:timeout})
		}

		var err error = nil
		for _, status := range dones {
			select {
			case <-status.Done:
				if status.Node.Error != "" {
					err = fmt.Errorf(status.Node.Error)
				}
			case <-status.Timeout:
				fmt.Println("timeout")
			}
		}

		if err == nil {
			return p.executeNode(operation, parent, template)
		} else {
			done := make(chan error, 1)
			timeout := make(chan bool, 1)
			done <- err
			return done, timeout
		}
	} else {
		return p.executeNode(operation, parent, template)
	}
}

func (p *Deployer) executeNode(operation string, node *topology.Node, template *topology.ServiceTemplate) (<-chan error, <-chan bool) {

	if node.Done == nil {
		node.Done = make(chan error, 1)
		node.Timeout = make(chan bool, 1)

		go func() {
			time.Sleep(30 * time.Second)
			node.Timeout <- true
			close(node.Timeout)
		}()

		go func() {
			if err := p.invoke(node, operation, template); err != nil {
				node.Done <- err

			} else {
				node.Done <- nil
			}
			close(node.Done)
		}()
	} else {
		fmt.Println("doing")
	}

	return node.Done, node.Timeout
}

// invoke the operation
func (p *Deployer) invoke(node *topology.Node, operation string, template *topology.ServiceTemplate) error {
	log.LogCodeLine()

	nodeTemplate := template.FindTemplate(node.Template)

	if nodeTemplate == nil {
		node.RunStatus = topology.RunStatusRed
		err := fmt.Errorf("template %s of node %s isn't exist", node.Template, node.Name)
		return err
	}
	node.RunStatus = topology.RunStatusGreen

	args := map[string]string{}
	for _, param := range nodeTemplate.Parameters {
		args[param.Name] = param.Value
	}

	class, err := p.ClassRep.Get(nodeTemplate.Type)
	if err != nil {
		return err
	}

	err = p.Executor.Perform(class, operation, args)
	if err != nil {
		node.RunStatus = topology.RunStatusRed
		node.Error = fmt.Errorf("%s execute %s error:%s", node.Name, operation, err.Error()).Error()

	} else {
		node.RunStatus = topology.RunStatusGreen
	}

	p.DBService.GetDB().Save(node)
	return err
}

<|endoftext|>


<commit_before>package jwt

import (
	"crypto/rsa"
	"net/http"
	"sync"
)

type (
	// Key represents a public key used to validate the incoming token signatures.
	// The value must be of type *rsa.PublicKey, []byte or string.
	// Keys of type []byte or string are interpreted depending on the incoming request JWT token
	// method (HMAC, RSA, etc.).
	Key interface{}

	// KeyResolver allows the management of keys used by the middleware to verify the signature of
	// incoming requests. Keys are grouped by name allowing the authorization algorithm to select a
	// group depending on the incoming request state (e.g. a header). The use of groups enables key
	// rotation.
	KeyResolver interface {
		// SelectKeys returns the group of keys to be used for the incoming request.
		SelectKeys(req *http.Request) []Key
	}

	// GroupResolver is a key resolver that switches on the value of a specified request header
	// for selecting the key group used to authorize the incoming request.
	GroupResolver struct {
		*sync.RWMutex
		keyHeader string
		keyMap    map[string][]Key
	}

	// simpleResolver uses a single immutable key group.
	simpleResolver []Key
)

// NewResolver returns a GroupResolver that uses the value of the request header with the given name
// to select the key group used for authorization. keys contains the initial set of key groups
// indexed by name.
func NewResolver(keys map[string][]Key, header string) (*GroupResolver, error) {
	if header == "" {
		return nil, ErrEmptyHeaderName
	}
	keyMap := make(map[string][]Key)
	for name := range keys {
		for _, keys := range keys[name] {
			switch keys := keys.(type) {
			case *rsa.PublicKey, string, []byte:
				keyMap[name] = append(keyMap[name], keys)
			case []*rsa.PublicKey:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			case [][]byte:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			case []string:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			default:
				return nil, ErrInvalidKey
			}
		}
	}
	return &GroupResolver{
		RWMutex:   &sync.RWMutex{},
		keyMap:    keyMap,
		keyHeader: header,
	}, nil
}

// NewSimpleResolver returns a simple resolver.
func NewSimpleResolver(keys []Key) (KeyResolver, error) {
	return simpleResolver(keys), nil
}

// AddKeys can be used to add keys to the resolver which will be referenced
// by the provided name. Acceptable types for keys include string, []string,
// *rsa.PublicKey or []*rsa.PublicKey. Multiple keys are allowed for a single
// key name to allow for key rotation.
func (kr *GroupResolver) AddKeys(name string, keys Key) error {
	kr.Lock()
	defer kr.Unlock()
	switch keys := keys.(type) {
	case *rsa.PublicKey, []byte, string:
		kr.keyMap[name] = append(kr.keyMap[name], keys)
	case []*rsa.PublicKey:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	case [][]byte:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	case []string:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	default:
		return ErrInvalidKey
	}
	return nil
}

// RemoveAllKeys removes all keys from the resolver.
func (kr *GroupResolver) RemoveAllKeys() {
	kr.Lock()
	defer kr.Unlock()
	kr.keyMap = make(map[string][]Key)
	return
}

// RemoveKeys removes all keys from the resolver stored under the provided name.
func (kr *GroupResolver) RemoveKeys(name string) {
	kr.Lock()
	defer kr.Unlock()
	delete(kr.keyMap, name)
	return
}

// RemoveKey removes only the provided key stored under the provided name from
// the resolver.
func (kr *GroupResolver) RemoveKey(name string, key Key) {
	kr.Lock()
	defer kr.Unlock()
	if keys, ok := kr.keyMap[name]; ok {
		for i, keyItem := range keys {
			if keyItem == key {
				kr.keyMap[name] = append(keys[:i], keys[i+1:]...)
			}
		}
	}
	return
}

// GetAllKeys returns a list of all the keys stored in the resolver.
func (kr *GroupResolver) GetAllKeys() []Key {
	kr.RLock()
	defer kr.RUnlock()
	var keys []Key
	for name := range kr.keyMap {
		for _, key := range kr.keyMap[name] {
			keys = append(keys, key)
		}
	}
	return keys
}

// GetKeys returns a list of all the keys stored in the resolver under the
// provided name.
func (kr *GroupResolver) GetKeys(name string) ([]Key, error) {
	kr.RLock()
	defer kr.RUnlock()
	if keys, ok := kr.keyMap[name]; ok {
		return keys, nil
	}
	return nil, ErrKeyDoesNotExist
}

// SelectKeys returns the keys in the group with the name identified by the request key selection
// header. If the header does value does not match a specific group then all keys are returned.
func (kr *GroupResolver) SelectKeys(req *http.Request) []Key {
	keyName := req.Header.Get(kr.keyHeader)
	kr.RLock()
	defer kr.RUnlock()
	if keyName != "" {
		return kr.keyMap[keyName]
	}
	var keys []Key
	for _, ks := range kr.keyMap {
		keys = append(keys, ks...)
	}
	return keys
}

// SelectKeys returns the keys used to create the simple resolver.
func (sr simpleResolver) SelectKeys(req *http.Request) []Key {
	return []Key(sr)
}
<commit_msg>Simplify jwt middleware NewSimpleResolver<commit_after>package jwt

import (
	"crypto/rsa"
	"net/http"
	"sync"
)

type (
	// Key represents a public key used to validate the incoming token signatures.
	// The value must be of type *rsa.PublicKey, []byte or string.
	// Keys of type []byte or string are interpreted depending on the incoming request JWT token
	// method (HMAC, RSA, etc.).
	Key interface{}

	// KeyResolver allows the management of keys used by the middleware to verify the signature of
	// incoming requests. Keys are grouped by name allowing the authorization algorithm to select a
	// group depending on the incoming request state (e.g. a header). The use of groups enables key
	// rotation.
	KeyResolver interface {
		// SelectKeys returns the group of keys to be used for the incoming request.
		SelectKeys(req *http.Request) []Key
	}

	// GroupResolver is a key resolver that switches on the value of a specified request header
	// for selecting the key group used to authorize the incoming request.
	GroupResolver struct {
		*sync.RWMutex
		keyHeader string
		keyMap    map[string][]Key
	}

	// simpleResolver uses a single immutable key group.
	simpleResolver []Key
)

// NewResolver returns a GroupResolver that uses the value of the request header with the given name
// to select the key group used for authorization. keys contains the initial set of key groups
// indexed by name.
func NewResolver(keys map[string][]Key, header string) (*GroupResolver, error) {
	if header == "" {
		return nil, ErrEmptyHeaderName
	}
	keyMap := make(map[string][]Key)
	for name := range keys {
		for _, keys := range keys[name] {
			switch keys := keys.(type) {
			case *rsa.PublicKey, string, []byte:
				keyMap[name] = append(keyMap[name], keys)
			case []*rsa.PublicKey:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			case [][]byte:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			case []string:
				for _, key := range keys {
					keyMap[name] = append(keyMap[name], key)
				}
			default:
				return nil, ErrInvalidKey
			}
		}
	}
	return &GroupResolver{
		RWMutex:   &sync.RWMutex{},
		keyMap:    keyMap,
		keyHeader: header,
	}, nil
}

// NewSimpleResolver returns a simple resolver.
func NewSimpleResolver(keys []Key) KeyResolver {
	return simpleResolver(keys)
}

// AddKeys can be used to add keys to the resolver which will be referenced
// by the provided name. Acceptable types for keys include string, []string,
// *rsa.PublicKey or []*rsa.PublicKey. Multiple keys are allowed for a single
// key name to allow for key rotation.
func (kr *GroupResolver) AddKeys(name string, keys Key) error {
	kr.Lock()
	defer kr.Unlock()
	switch keys := keys.(type) {
	case *rsa.PublicKey, []byte, string:
		kr.keyMap[name] = append(kr.keyMap[name], keys)
	case []*rsa.PublicKey:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	case [][]byte:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	case []string:
		for _, key := range keys {
			kr.keyMap[name] = append(kr.keyMap[name], key)
		}
	default:
		return ErrInvalidKey
	}
	return nil
}

// RemoveAllKeys removes all keys from the resolver.
func (kr *GroupResolver) RemoveAllKeys() {
	kr.Lock()
	defer kr.Unlock()
	kr.keyMap = make(map[string][]Key)
	return
}

// RemoveKeys removes all keys from the resolver stored under the provided name.
func (kr *GroupResolver) RemoveKeys(name string) {
	kr.Lock()
	defer kr.Unlock()
	delete(kr.keyMap, name)
	return
}

// RemoveKey removes only the provided key stored under the provided name from
// the resolver.
func (kr *GroupResolver) RemoveKey(name string, key Key) {
	kr.Lock()
	defer kr.Unlock()
	if keys, ok := kr.keyMap[name]; ok {
		for i, keyItem := range keys {
			if keyItem == key {
				kr.keyMap[name] = append(keys[:i], keys[i+1:]...)
			}
		}
	}
	return
}

// GetAllKeys returns a list of all the keys stored in the resolver.
func (kr *GroupResolver) GetAllKeys() []Key {
	kr.RLock()
	defer kr.RUnlock()
	var keys []Key
	for name := range kr.keyMap {
		for _, key := range kr.keyMap[name] {
			keys = append(keys, key)
		}
	}
	return keys
}

// GetKeys returns a list of all the keys stored in the resolver under the
// provided name.
func (kr *GroupResolver) GetKeys(name string) ([]Key, error) {
	kr.RLock()
	defer kr.RUnlock()
	if keys, ok := kr.keyMap[name]; ok {
		return keys, nil
	}
	return nil, ErrKeyDoesNotExist
}

// SelectKeys returns the keys in the group with the name identified by the request key selection
// header. If the header does value does not match a specific group then all keys are returned.
func (kr *GroupResolver) SelectKeys(req *http.Request) []Key {
	keyName := req.Header.Get(kr.keyHeader)
	kr.RLock()
	defer kr.RUnlock()
	if keyName != "" {
		return kr.keyMap[keyName]
	}
	var keys []Key
	for _, ks := range kr.keyMap {
		keys = append(keys, ks...)
	}
	return keys
}

// SelectKeys returns the keys used to create the simple resolver.
func (sr simpleResolver) SelectKeys(req *http.Request) []Key {
	return []Key(sr)
}
<|endoftext|>


<commit_before>package scanner

import (
	"crypto/sha512"
	"errors"
	"fmt"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/filter"
	"github.com/Symantec/Dominator/lib/fsrateio"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/wsyscall"
	"io"
	"os"
	"path"
	"runtime"
	"sort"
	"syscall"
)

var myCountGC int

func myGC() {
	if myCountGC > 1000 {
		runtime.GC()
		myCountGC = 0
	}
	myCountGC++
}

type defaultHasher bool

func makeRegularInode(stat *wsyscall.Stat_t) *filesystem.RegularInode {
	var inode filesystem.RegularInode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	inode.MtimeSeconds = stat.Mtim.Sec
	inode.MtimeNanoSeconds = int32(stat.Mtim.Nsec)
	inode.Size = uint64(stat.Size)
	return &inode
}

func makeSymlinkInode(stat *wsyscall.Stat_t) *filesystem.SymlinkInode {
	var inode filesystem.SymlinkInode
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	return &inode
}

func makeSpecialInode(stat *wsyscall.Stat_t) *filesystem.SpecialInode {
	var inode filesystem.SpecialInode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	inode.MtimeSeconds = stat.Mtim.Sec
	inode.MtimeNanoSeconds = int32(stat.Mtim.Nsec)
	inode.Rdev = stat.Rdev
	return &inode
}

func scanFileSystem(rootDirectoryName string,
	fsScanContext *fsrateio.ReaderContext, scanFilter *filter.Filter,
	checkScanDisableRequest func() bool, hasher Hasher, oldFS *FileSystem) (
	*FileSystem, error) {
	var fileSystem FileSystem
	fileSystem.rootDirectoryName = rootDirectoryName
	fileSystem.fsScanContext = fsScanContext
	fileSystem.scanFilter = scanFilter
	fileSystem.checkScanDisableRequest = checkScanDisableRequest
	if hasher == nil {
		fileSystem.hasher = new(defaultHasher)
	} else {
		fileSystem.hasher = hasher
	}
	var stat wsyscall.Stat_t
	if err := wsyscall.Lstat(rootDirectoryName, &stat); err != nil {
		return nil, err
	}
	fileSystem.InodeTable = make(filesystem.InodeTable)
	fileSystem.dev = stat.Dev
	fileSystem.inodeNumber = stat.Ino
	fileSystem.Mode = filesystem.FileMode(stat.Mode)
	fileSystem.Uid = stat.Uid
	fileSystem.Gid = stat.Gid
	fileSystem.DirectoryCount++
	var tmpInode filesystem.RegularInode
	if sha512.New().Size() != len(tmpInode.Hash) {
		return nil, errors.New("incompatible hash size")
	}
	var oldDirectory *filesystem.DirectoryInode
	if oldFS != nil && oldFS.InodeTable != nil {
		oldDirectory = &oldFS.DirectoryInode
	}
	err, _ := scanDirectory(&fileSystem.FileSystem.DirectoryInode, oldDirectory,
		&fileSystem, oldFS, "/")
	oldFS = nil
	oldDirectory = nil
	if err != nil {
		return nil, err
	}
	fileSystem.ComputeTotalDataBytes()
	if err = fileSystem.RebuildInodePointers(); err != nil {
		panic(err)
	}
	return &fileSystem, nil
}

func scanDirectory(directory, oldDirectory *filesystem.DirectoryInode,
	fileSystem, oldFS *FileSystem, myPathName string) (error, bool) {
	file, err := os.Open(path.Join(fileSystem.rootDirectoryName, myPathName))
	if err != nil {
		return err, false
	}
	names, err := file.Readdirnames(-1)
	file.Close()
	if err != nil {
		return err, false
	}
	sort.Strings(names)
	entryList := make([]*filesystem.DirectoryEntry, 0, len(names))
	var copiedDirents int
	for _, name := range names {
		if directory == &fileSystem.DirectoryInode && name == ".subd" {
			continue
		}
		filename := path.Join(myPathName, name)
		if fileSystem.scanFilter != nil &&
			fileSystem.scanFilter.Match(filename) {
			continue
		}
		var stat wsyscall.Stat_t
		err := wsyscall.Lstat(path.Join(fileSystem.rootDirectoryName, filename),
			&stat)
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err, false
		}
		if stat.Dev != fileSystem.dev {
			continue
		}
		if fileSystem.checkScanDisableRequest != nil &&
			fileSystem.checkScanDisableRequest() {
			return errors.New("DisableScan"), false
		}
		myGC()
		dirent := new(filesystem.DirectoryEntry)
		dirent.Name = name
		dirent.InodeNumber = stat.Ino
		var oldDirent *filesystem.DirectoryEntry
		if oldDirectory != nil {
			index := len(entryList)
			if len(oldDirectory.EntryList) > index &&
				oldDirectory.EntryList[index].Name == name {
				oldDirent = oldDirectory.EntryList[index]
			}
		}
		if stat.Mode&syscall.S_IFMT == syscall.S_IFDIR {
			err = addDirectory(dirent, oldDirent, fileSystem, oldFS, myPathName,
				&stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFREG {
			err = addRegularFile(dirent, fileSystem, oldFS, myPathName, &stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
			err = addSymlink(dirent, fileSystem, oldFS, myPathName, &stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFSOCK {
			continue
		} else {
			err = addSpecialFile(dirent, fileSystem, oldFS, &stat)
		}
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err, false
		}
		if oldDirent != nil && *dirent == *oldDirent {
			dirent = oldDirent
			copiedDirents++
		}
		entryList = append(entryList, dirent)
	}
	if oldDirectory != nil && len(entryList) == copiedDirents &&
		len(entryList) == len(oldDirectory.EntryList) {
		directory.EntryList = oldDirectory.EntryList
		return nil, true
	} else {
		directory.EntryList = entryList
		return nil, false
	}
}

func addDirectory(dirent, oldDirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	myPathName := path.Join(directoryPathName, dirent.Name)
	if stat.Ino == fileSystem.inodeNumber {
		return errors.New("recursive directory: " + myPathName)
	}
	if _, ok := fileSystem.InodeTable[stat.Ino]; ok {
		return errors.New("hardlinked directory: " + myPathName)
	}
	inode := new(filesystem.DirectoryInode)
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	var oldInode *filesystem.DirectoryInode
	if oldDirent != nil {
		if oi, ok := oldDirent.Inode().(*filesystem.DirectoryInode); ok {
			oldInode = oi
		}
	}
	err, copied := scanDirectory(inode, oldInode, fileSystem, oldFS, myPathName)
	if err != nil {
		return err
	}
	if copied && filesystem.CompareDirectoriesMetadata(inode, oldInode, nil) {
		dirent.SetInode(oldInode)
		fileSystem.InodeTable[stat.Ino] = oldInode
	}
	fileSystem.DirectoryCount++
	return nil
}

func addRegularFile(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeRegularInode(stat)
	if inode.Size > 0 {
		err := scanRegularInode(inode, fileSystem,
			path.Join(directoryPathName, dirent.Name))
		if err != nil {
			return err
		}
	}
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.RegularInode); ok {
				if filesystem.CompareRegularInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func addSymlink(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.SymlinkInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeSymlinkInode(stat)
	err := scanSymlinkInode(inode, fileSystem,
		path.Join(directoryPathName, dirent.Name))
	if err != nil {
		return err
	}
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.SymlinkInode); ok {
				if filesystem.CompareSymlinkInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func addSpecialFile(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.SpecialInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeSpecialInode(stat)
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.SpecialInode); ok {
				if filesystem.CompareSpecialInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func (*defaultHasher) Hash(reader io.Reader, length uint64) (hash.Hash, error) {
	hasher := sha512.New()
	var hashVal hash.Hash
	nCopied, err := io.Copy(hasher, reader)
	if err != nil {
		return hashVal, err
	}
	if nCopied != int64(length) {
		return hashVal, fmt.Errorf("read: %d, expected: %d bytes",
			nCopied, length)
	}
	copy(hashVal[:], hasher.Sum(nil))
	return hashVal, nil
}

func scanRegularInode(inode *filesystem.RegularInode, fileSystem *FileSystem,
	myPathName string) error {
	f, err := os.Open(path.Join(fileSystem.rootDirectoryName, myPathName))
	if err != nil {
		return err
	}
	defer f.Close()
	reader := io.Reader(f)
	if fileSystem.fsScanContext != nil {
		reader = fileSystem.fsScanContext.NewReader(f)
	}
	inode.Hash, err = fileSystem.hasher.Hash(reader, inode.Size)
	if err != nil {
		return fmt.Errorf("scanRegularInode(%s): %s", myPathName, err)
	}
	return nil
}

func scanSymlinkInode(inode *filesystem.SymlinkInode, fileSystem *FileSystem,
	myPathName string) error {
	target, err := os.Readlink(path.Join(fileSystem.rootDirectoryName,
		myPathName))
	if err != nil {
		return err
	}
	inode.Symlink = target
	return nil
}
<commit_msg>Do not fail scanning if file grows between Lstat() and hashing read.<commit_after>package scanner

import (
	"crypto/sha512"
	"errors"
	"fmt"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/filter"
	"github.com/Symantec/Dominator/lib/fsrateio"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/wsyscall"
	"io"
	"os"
	"path"
	"runtime"
	"sort"
	"syscall"
)

var myCountGC int

func myGC() {
	if myCountGC > 1000 {
		runtime.GC()
		myCountGC = 0
	}
	myCountGC++
}

type defaultHasher bool

func makeRegularInode(stat *wsyscall.Stat_t) *filesystem.RegularInode {
	var inode filesystem.RegularInode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	inode.MtimeSeconds = stat.Mtim.Sec
	inode.MtimeNanoSeconds = int32(stat.Mtim.Nsec)
	inode.Size = uint64(stat.Size)
	return &inode
}

func makeSymlinkInode(stat *wsyscall.Stat_t) *filesystem.SymlinkInode {
	var inode filesystem.SymlinkInode
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	return &inode
}

func makeSpecialInode(stat *wsyscall.Stat_t) *filesystem.SpecialInode {
	var inode filesystem.SpecialInode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	inode.MtimeSeconds = stat.Mtim.Sec
	inode.MtimeNanoSeconds = int32(stat.Mtim.Nsec)
	inode.Rdev = stat.Rdev
	return &inode
}

func scanFileSystem(rootDirectoryName string,
	fsScanContext *fsrateio.ReaderContext, scanFilter *filter.Filter,
	checkScanDisableRequest func() bool, hasher Hasher, oldFS *FileSystem) (
	*FileSystem, error) {
	var fileSystem FileSystem
	fileSystem.rootDirectoryName = rootDirectoryName
	fileSystem.fsScanContext = fsScanContext
	fileSystem.scanFilter = scanFilter
	fileSystem.checkScanDisableRequest = checkScanDisableRequest
	if hasher == nil {
		fileSystem.hasher = new(defaultHasher)
	} else {
		fileSystem.hasher = hasher
	}
	var stat wsyscall.Stat_t
	if err := wsyscall.Lstat(rootDirectoryName, &stat); err != nil {
		return nil, err
	}
	fileSystem.InodeTable = make(filesystem.InodeTable)
	fileSystem.dev = stat.Dev
	fileSystem.inodeNumber = stat.Ino
	fileSystem.Mode = filesystem.FileMode(stat.Mode)
	fileSystem.Uid = stat.Uid
	fileSystem.Gid = stat.Gid
	fileSystem.DirectoryCount++
	var tmpInode filesystem.RegularInode
	if sha512.New().Size() != len(tmpInode.Hash) {
		return nil, errors.New("incompatible hash size")
	}
	var oldDirectory *filesystem.DirectoryInode
	if oldFS != nil && oldFS.InodeTable != nil {
		oldDirectory = &oldFS.DirectoryInode
	}
	err, _ := scanDirectory(&fileSystem.FileSystem.DirectoryInode, oldDirectory,
		&fileSystem, oldFS, "/")
	oldFS = nil
	oldDirectory = nil
	if err != nil {
		return nil, err
	}
	fileSystem.ComputeTotalDataBytes()
	if err = fileSystem.RebuildInodePointers(); err != nil {
		panic(err)
	}
	return &fileSystem, nil
}

func scanDirectory(directory, oldDirectory *filesystem.DirectoryInode,
	fileSystem, oldFS *FileSystem, myPathName string) (error, bool) {
	file, err := os.Open(path.Join(fileSystem.rootDirectoryName, myPathName))
	if err != nil {
		return err, false
	}
	names, err := file.Readdirnames(-1)
	file.Close()
	if err != nil {
		return err, false
	}
	sort.Strings(names)
	entryList := make([]*filesystem.DirectoryEntry, 0, len(names))
	var copiedDirents int
	for _, name := range names {
		if directory == &fileSystem.DirectoryInode && name == ".subd" {
			continue
		}
		filename := path.Join(myPathName, name)
		if fileSystem.scanFilter != nil &&
			fileSystem.scanFilter.Match(filename) {
			continue
		}
		var stat wsyscall.Stat_t
		err := wsyscall.Lstat(path.Join(fileSystem.rootDirectoryName, filename),
			&stat)
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err, false
		}
		if stat.Dev != fileSystem.dev {
			continue
		}
		if fileSystem.checkScanDisableRequest != nil &&
			fileSystem.checkScanDisableRequest() {
			return errors.New("DisableScan"), false
		}
		myGC()
		dirent := new(filesystem.DirectoryEntry)
		dirent.Name = name
		dirent.InodeNumber = stat.Ino
		var oldDirent *filesystem.DirectoryEntry
		if oldDirectory != nil {
			index := len(entryList)
			if len(oldDirectory.EntryList) > index &&
				oldDirectory.EntryList[index].Name == name {
				oldDirent = oldDirectory.EntryList[index]
			}
		}
		if stat.Mode&syscall.S_IFMT == syscall.S_IFDIR {
			err = addDirectory(dirent, oldDirent, fileSystem, oldFS, myPathName,
				&stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFREG {
			err = addRegularFile(dirent, fileSystem, oldFS, myPathName, &stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
			err = addSymlink(dirent, fileSystem, oldFS, myPathName, &stat)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFSOCK {
			continue
		} else {
			err = addSpecialFile(dirent, fileSystem, oldFS, &stat)
		}
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err, false
		}
		if oldDirent != nil && *dirent == *oldDirent {
			dirent = oldDirent
			copiedDirents++
		}
		entryList = append(entryList, dirent)
	}
	if oldDirectory != nil && len(entryList) == copiedDirents &&
		len(entryList) == len(oldDirectory.EntryList) {
		directory.EntryList = oldDirectory.EntryList
		return nil, true
	} else {
		directory.EntryList = entryList
		return nil, false
	}
}

func addDirectory(dirent, oldDirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	myPathName := path.Join(directoryPathName, dirent.Name)
	if stat.Ino == fileSystem.inodeNumber {
		return errors.New("recursive directory: " + myPathName)
	}
	if _, ok := fileSystem.InodeTable[stat.Ino]; ok {
		return errors.New("hardlinked directory: " + myPathName)
	}
	inode := new(filesystem.DirectoryInode)
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	inode.Mode = filesystem.FileMode(stat.Mode)
	inode.Uid = stat.Uid
	inode.Gid = stat.Gid
	var oldInode *filesystem.DirectoryInode
	if oldDirent != nil {
		if oi, ok := oldDirent.Inode().(*filesystem.DirectoryInode); ok {
			oldInode = oi
		}
	}
	err, copied := scanDirectory(inode, oldInode, fileSystem, oldFS, myPathName)
	if err != nil {
		return err
	}
	if copied && filesystem.CompareDirectoriesMetadata(inode, oldInode, nil) {
		dirent.SetInode(oldInode)
		fileSystem.InodeTable[stat.Ino] = oldInode
	}
	fileSystem.DirectoryCount++
	return nil
}

func addRegularFile(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeRegularInode(stat)
	if inode.Size > 0 {
		err := scanRegularInode(inode, fileSystem,
			path.Join(directoryPathName, dirent.Name))
		if err != nil {
			return err
		}
	}
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.RegularInode); ok {
				if filesystem.CompareRegularInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func addSymlink(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem,
	directoryPathName string, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.SymlinkInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeSymlinkInode(stat)
	err := scanSymlinkInode(inode, fileSystem,
		path.Join(directoryPathName, dirent.Name))
	if err != nil {
		return err
	}
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.SymlinkInode); ok {
				if filesystem.CompareSymlinkInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func addSpecialFile(dirent *filesystem.DirectoryEntry,
	fileSystem, oldFS *FileSystem, stat *wsyscall.Stat_t) error {
	if inode, ok := fileSystem.InodeTable[stat.Ino]; ok {
		if inode, ok := inode.(*filesystem.SpecialInode); ok {
			dirent.SetInode(inode)
			return nil
		}
		return errors.New("inode changed type: " + dirent.Name)
	}
	inode := makeSpecialInode(stat)
	if oldFS != nil && oldFS.InodeTable != nil {
		if oldInode, found := oldFS.InodeTable[stat.Ino]; found {
			if oldInode, ok := oldInode.(*filesystem.SpecialInode); ok {
				if filesystem.CompareSpecialInodes(inode, oldInode, nil) {
					inode = oldInode
				}
			}
		}
	}
	dirent.SetInode(inode)
	fileSystem.InodeTable[stat.Ino] = inode
	return nil
}

func (*defaultHasher) Hash(reader io.Reader, length uint64) (hash.Hash, error) {
	hasher := sha512.New()
	var hashVal hash.Hash
	nCopied, err := io.CopyN(hasher, reader, int64(length))
	if err != nil {
		return hashVal, err
	}
	if nCopied != int64(length) {
		return hashVal, fmt.Errorf("read: %d, expected: %d bytes",
			nCopied, length)
	}
	copy(hashVal[:], hasher.Sum(nil))
	return hashVal, nil
}

func scanRegularInode(inode *filesystem.RegularInode, fileSystem *FileSystem,
	myPathName string) error {
	f, err := os.Open(path.Join(fileSystem.rootDirectoryName, myPathName))
	if err != nil {
		return err
	}
	defer f.Close()
	reader := io.Reader(f)
	if fileSystem.fsScanContext != nil {
		reader = fileSystem.fsScanContext.NewReader(f)
	}
	inode.Hash, err = fileSystem.hasher.Hash(reader, inode.Size)
	if err != nil {
		return fmt.Errorf("scanRegularInode(%s): %s", myPathName, err)
	}
	return nil
}

func scanSymlinkInode(inode *filesystem.SymlinkInode, fileSystem *FileSystem,
	myPathName string) error {
	target, err := os.Readlink(path.Join(fileSystem.rootDirectoryName,
		myPathName))
	if err != nil {
		return err
	}
	inode.Symlink = target
	return nil
}
<|endoftext|>


<commit_before>package taverna

import (
	"github.com/MG-RAST/AWE/lib/core"
	"time"
)

type WorkflowRun struct {
	State            string        `bson:"state" json:"state"`
	Invocations      []*Invocation `bson:"invocations" json:"invocations"`
	CreatedDate      time.Time     `bson:"createDate" json:"createDate"`
	StartedDate      time.Time     `bson:"startedDate" json:"updateDate"`
	CompletedDate    time.Time     `bson:"completedDate" json:"completedDate"`
	ProcessorReports []*ProcReport `bson:"processorReports" json:"processorReports"`
	Subject          string        `bson:"subject" json:"subject"`
}

type Invocation struct {
	Inputs  map[string]string `bson:"inputs" json:"inputs"`
	Outputs map[string]string `bson:"outputs" json:"outputs"`
	Name    string            `bson:"name" json:"name"`
	Id      string            `bson:"id" json:"id"`
}

type ProcReport struct {
	State         string        `bson:"state" json:"state"`
	Invocations   []*Invocation `bson:"invocations" json:"invocations"`
	CreatedDate   time.Time     `bson:"createDate" json:"createDate"`
	StartedDate   time.Time     `bson:"startedDate" json:"updateDate"`
	CompletedDate time.Time     `bson:"completedDate" json:"completedDate"`
}

func ExportWorkflowRun(job *core.Job) (wfrun *WorkflowRun, err error) {
	wfrun = new(WorkflowRun)
	wfrun.State = job.State
	wfrun.CreatedDate = job.Info.SubmitTime
	wfrun.StartedDate = job.Info.SubmitTime
	wfrun.CompletedDate = job.UpdateTime
	wfrun.Subject = job.Id
	for _, task := range job.Tasks {
		report := new(ProcReport)
		report.State = task.State
		invocation := new(Invocation)
		invocation.Id = task.Id
		invocation.Name = task.Cmd.Name
		invocation.Inputs = make(map[string]string)
		for name, io := range task.Inputs {
			invocation.Inputs[name] = io.Url
		}
		for name, io := range task.Predata {
			invocation.Inputs[name] = io.Url
		}
		for name, io := range task.Outputs {
			invocation.Outputs[name] = io.Url
		}
		report.Invocations = append(report.Invocations, invocation)
		wfrun.ProcessorReports = append(wfrun.ProcessorReports, report)
	}
	return
}
<commit_msg>fix for map initiazation<commit_after>package taverna

import (
	"github.com/MG-RAST/AWE/lib/core"
	"time"
)

type WorkflowRun struct {
	State            string        `bson:"state" json:"state"`
	Invocations      []*Invocation `bson:"invocations" json:"invocations"`
	CreatedDate      time.Time     `bson:"createDate" json:"createDate"`
	StartedDate      time.Time     `bson:"startedDate" json:"updateDate"`
	CompletedDate    time.Time     `bson:"completedDate" json:"completedDate"`
	ProcessorReports []*ProcReport `bson:"processorReports" json:"processorReports"`
	Subject          string        `bson:"subject" json:"subject"`
}

type Invocation struct {
	Inputs  map[string]string `bson:"inputs" json:"inputs"`
	Outputs map[string]string `bson:"outputs" json:"outputs"`
	Name    string            `bson:"name" json:"name"`
	Id      string            `bson:"id" json:"id"`
}

type ProcReport struct {
	State         string        `bson:"state" json:"state"`
	Invocations   []*Invocation `bson:"invocations" json:"invocations"`
	CreatedDate   time.Time     `bson:"createDate" json:"createDate"`
	StartedDate   time.Time     `bson:"startedDate" json:"updateDate"`
	CompletedDate time.Time     `bson:"completedDate" json:"completedDate"`
}

func ExportWorkflowRun(job *core.Job) (wfrun *WorkflowRun, err error) {
	wfrun = new(WorkflowRun)
	wfrun.State = job.State
	wfrun.CreatedDate = job.Info.SubmitTime
	wfrun.StartedDate = job.Info.SubmitTime
	wfrun.CompletedDate = job.UpdateTime
	wfrun.Subject = job.Id
	for _, task := range job.Tasks {
		report := new(ProcReport)
		report.State = task.State
		invocation := new(Invocation)
		invocation.Id = task.Id
		invocation.Name = task.Cmd.Name
		invocation.Inputs = make(map[string]string)
		invocation.Outputs = make(map[string]string)
		for name, io := range task.Inputs {
			invocation.Inputs[name] = io.Url
		}
		for name, io := range task.Predata {
			invocation.Inputs[name] = io.Url
		}
		for name, io := range task.Outputs {
			invocation.Outputs[name] = io.Url
		}
		report.Invocations = append(report.Invocations, invocation)
		wfrun.ProcessorReports = append(wfrun.ProcessorReports, report)
	}
	return
}
<|endoftext|>


<commit_before>package dnsimple

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

var (
	dnsimpleLiveTest bool
	dnsimpleToken    string
	dnsimpleBaseURL  string
	dnsimpleClient   *Client
)

func init() {
	dnsimpleToken = os.Getenv("DNSIMPLE_TOKEN")
	dnsimpleBaseURL = os.Getenv("DOMAINR_BASE_URL")

	// Prevent peoeple from wiping out their entire production account by mistake
	if dnsimpleBaseURL == "" {
		dnsimpleBaseURL = "https://api.sandbox.dnsimple.com"
	}

	if len(dnsimpleToken) > 0 {
		dnsimpleLiveTest = true
		dnsimpleClient = NewClient(NewOauthTokenCredentials(dnsimpleToken))
		dnsimpleClient.BaseURL = dnsimpleBaseURL
		dnsimpleClient.UserAgent = fmt.Sprintf("%v +livetest", dnsimpleClient.UserAgent)
	}
}

func TestLive_Whoami(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoamiResponse, err := dnsimpleClient.Identity.Whoami()
	if err != nil {
		t.Fatalf("Live Auth.Whoami() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", whoamiResponse.RateLimitRemaining(), whoamiResponse.RateLimit(), whoamiResponse.RateLimitReset())
	whoami := whoamiResponse.Data
	fmt.Printf("Account: %+v\n", whoami.Account)
	fmt.Printf("User: %+v\n", whoami.User)
}

func TestLive_Domains(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Whoami() returned error: %v", err)
	}

	accountID := whoami.Account.ID

	domainsResponse, err := dnsimpleClient.Domains.ListDomains(fmt.Sprintf("%v", accountID), nil)
	if err != nil {
		t.Fatalf("Live Domains.List() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", domainsResponse.RateLimitRemaining(), domainsResponse.RateLimit(), domainsResponse.RateLimitReset())
	fmt.Printf("Domains: %+v\n", domainsResponse.Data)
}

func TestLive_Registration(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Whoami() returned error: %v", err)
	}

	accountID := whoami.Account.ID

	// TODO: fetch the registrant randomly
	registerRequest := &DomainRegisterRequest{RegistrantID: 2}
	registrationResponse, err := dnsimpleClient.Registrar.RegisterDomain(fmt.Sprintf("%v", accountID), fmt.Sprintf("example-%v.com", time.Now().Unix()), registerRequest)
	if err != nil {
		t.Fatalf("Live Registrar.Register() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", registrationResponse.RateLimitRemaining(), registrationResponse.RateLimit(), registrationResponse.RateLimitReset())
	fmt.Printf("Domain: %+v\n", registrationResponse.Data)
}

func TestLive_Webhooks(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	var err error
	var webhook *Webhook
	var webhookResponse *WebhookResponse
	var webhooksResponse *WebhooksResponse

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Auth.Whoami()/Domains.List() returned error: %v", err)
	}
	accountID := whoami.Account.ID

	webhooksResponse, err = dnsimpleClient.Webhooks.ListWebhooks(fmt.Sprintf("%v", accountID), nil)
	if err != nil {
		t.Fatalf("Live Webhooks.List() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	fmt.Printf("Webhooks: %+v\n", webhooksResponse.Data)

	webhookAttributes := Webhook{URL: "https://livetest.test"}
	webhookResponse, err = dnsimpleClient.Webhooks.CreateWebhook(fmt.Sprintf("%v", accountID), webhookAttributes)
	if err != nil {
		t.Fatalf("Live Webhooks.Create() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	fmt.Printf("Webhook: %+v\n", webhookResponse.Data)
	webhook = webhookResponse.Data

	webhookResponse, err = dnsimpleClient.Webhooks.DeleteWebhook(fmt.Sprintf("%v", accountID), webhook.ID)
	if err != nil {
		t.Fatalf("Live Webhooks.Delete(%v) returned error: %v", webhook.ID, err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	webhook = webhookResponse.Data
}
<commit_msg>dnsimple: Add a live test for an error response<commit_after>package dnsimple

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

var (
	dnsimpleLiveTest bool
	dnsimpleToken    string
	dnsimpleBaseURL  string
	dnsimpleClient   *Client
)

func init() {
	dnsimpleToken = os.Getenv("DNSIMPLE_TOKEN")
	dnsimpleBaseURL = os.Getenv("DOMAINR_BASE_URL")

	// Prevent peoeple from wiping out their entire production account by mistake
	if dnsimpleBaseURL == "" {
		dnsimpleBaseURL = "https://api.sandbox.dnsimple.com"
	}

	if len(dnsimpleToken) > 0 {
		dnsimpleLiveTest = true
		dnsimpleClient = NewClient(NewOauthTokenCredentials(dnsimpleToken))
		dnsimpleClient.BaseURL = dnsimpleBaseURL
		dnsimpleClient.UserAgent = fmt.Sprintf("%v +livetest", dnsimpleClient.UserAgent)
	}
}

func TestLive_Whoami(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoamiResponse, err := dnsimpleClient.Identity.Whoami()
	if err != nil {
		t.Fatalf("Live Auth.Whoami() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", whoamiResponse.RateLimitRemaining(), whoamiResponse.RateLimit(), whoamiResponse.RateLimitReset())
	whoami := whoamiResponse.Data
	fmt.Printf("Account: %+v\n", whoami.Account)
	fmt.Printf("User: %+v\n", whoami.User)
}

func TestLive_Domains(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Whoami() returned error: %v", err)
	}

	accountID := whoami.Account.ID

	domainsResponse, err := dnsimpleClient.Domains.ListDomains(fmt.Sprintf("%v", accountID), nil)
	if err != nil {
		t.Fatalf("Live Domains.List() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", domainsResponse.RateLimitRemaining(), domainsResponse.RateLimit(), domainsResponse.RateLimitReset())
	fmt.Printf("Domains: %+v\n", domainsResponse.Data)
}

func TestLive_Registration(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Whoami() returned error: %v", err)
	}

	accountID := whoami.Account.ID

	// TODO: fetch the registrant randomly
	registerRequest := &DomainRegisterRequest{RegistrantID: 2}
	registrationResponse, err := dnsimpleClient.Registrar.RegisterDomain(fmt.Sprintf("%v", accountID), fmt.Sprintf("example-%v.com", time.Now().Unix()), registerRequest)
	if err != nil {
		t.Fatalf("Live Registrar.Register() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", registrationResponse.RateLimitRemaining(), registrationResponse.RateLimit(), registrationResponse.RateLimitReset())
	fmt.Printf("Domain: %+v\n", registrationResponse.Data)
}

func TestLive_Webhooks(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	var err error
	var webhook *Webhook
	var webhookResponse *WebhookResponse
	var webhooksResponse *WebhooksResponse

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Auth.Whoami()/Domains.List() returned error: %v", err)
	}
	accountID := whoami.Account.ID

	webhooksResponse, err = dnsimpleClient.Webhooks.ListWebhooks(fmt.Sprintf("%v", accountID), nil)
	if err != nil {
		t.Fatalf("Live Webhooks.List() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	fmt.Printf("Webhooks: %+v\n", webhooksResponse.Data)

	webhookAttributes := Webhook{URL: "https://livetest.test"}
	webhookResponse, err = dnsimpleClient.Webhooks.CreateWebhook(fmt.Sprintf("%v", accountID), webhookAttributes)
	if err != nil {
		t.Fatalf("Live Webhooks.Create() returned error: %v", err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	fmt.Printf("Webhook: %+v\n", webhookResponse.Data)
	webhook = webhookResponse.Data

	webhookResponse, err = dnsimpleClient.Webhooks.DeleteWebhook(fmt.Sprintf("%v", accountID), webhook.ID)
	if err != nil {
		t.Fatalf("Live Webhooks.Delete(%v) returned error: %v", webhook.ID, err)
	}

	fmt.Printf("RateLimit: %v/%v until %v\n", webhooksResponse.RateLimitRemaining(), webhooksResponse.RateLimit(), webhooksResponse.RateLimitReset())
	webhook = webhookResponse.Data
}

func TestLive_Error(t *testing.T) {
	if !dnsimpleLiveTest {
		t.Skip("skipping live test")
	}

	whoami, err := Whoami(dnsimpleClient)
	if err != nil {
		t.Fatalf("Live Error()/Whoami() returned error: %v", err)
	}

	_, err = dnsimpleClient.Registrar.RegisterDomain(fmt.Sprintf("%v", whoami.Account.ID), fmt.Sprintf("example-%v.com", time.Now().Unix()), &DomainRegisterRequest{})
	if err == nil {
		t.Fatalf("Live Error()/RegisterDomain() expected to return error")
	}

	e := err.(*ErrorResponse)
	fmt.Println(e.Message)
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"fmt"
	"io"

	"my/ev/packet"
	"my/ev/sim"
)

const (
	EFHM_DEFINITION = 0
	EFHM_TRADE      = 1
	EFHM_QUOTE      = 2
	EFHM_ORDER      = 3
	EFHM_REFRESHED  = 100
	EFHM_STOPPED    = 101
)
const (
	EFH_ORDER_BID = 1
	EFH_ORDER_ASK = -1
)

type efhm_header struct {
	Type           uint8
	TickCondition  uint8
	QueuePosition  uint16
	UnderlyingId   uint32
	SecurityId     uint32
	SequenceNumber uint32
	TimeStamp      uint64
}

type efhm_order struct {
	efhm_header
	TradeStatus     uint8
	OrderType       uint8
	OrderSide       int8
	_pad            byte
	Price           uint32
	Size            uint32
	AoNSize         uint32
	CustomerSize    uint32
	CustomerAoNSize uint32
	BDSize          uint32
	BDAoNSize       uint32
}

type efhm_quote struct {
	efhm_header
	TradeStatus        uint8
	_pad               [3]byte
	BidPrice           uint32
	BidSize            uint32
	BidOrderSize       uint32
	BidAoNSize         uint32
	BidCustomerSize    uint32
	BidCustomerAoNSize uint32
	BidBDSize          uint32
	BidBDAoNSize       uint32
	AskPrice           uint32
	AskSize            uint32
	AskOrderSize       uint32
	AskAoNSize         uint32
	AskCustomerSize    uint32
	AskCustomerAoNSize uint32
	AskBDSize          uint32
	AskBDAoNSize       uint32
}

type efhm_trade struct {
	efhm_header
	Price          uint32
	Size           uint32
	TradeCondition uint8
}

func (m efhm_header) String() string {
	switch m.Type {
	case EFHM_QUOTE, EFHM_ORDER, EFHM_TRADE:
		return fmt.Sprintf("HDR{T:%d, TC:%d, QP:%d, UId:%08x, SId:%08x, SN:%d, TS:%08x}",
			m.Type,
			m.TickCondition,
			m.QueuePosition,
			m.UnderlyingId,
			m.SecurityId,
			m.SequenceNumber,
			m.TimeStamp,
		)
	default:
		return fmt.Sprintf("HDR{T:%d}", m.Type)
	}
}
func (m efhm_order) String() string {
	return fmt.Sprintf("%s ORD{TS:%d, OT:%d, OS:%+d, P:%10d, S:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}",
		m.efhm_header,
		m.TradeStatus,
		m.OrderType,
		m.OrderSide,
		m.Price,
		m.Size,
		m.AoNSize,
		m.CustomerSize,
		m.CustomerAoNSize,
		m.BDSize,
		m.BDAoNSize,
	)
}
func (m efhm_quote) String() string {
	return fmt.Sprintf("%s QUO{TS:%d, "+
		"Bid{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}, "+
		"Ask{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}"+
		"}",
		m.efhm_header,
		m.TradeStatus,
		m.BidPrice,
		m.BidSize,
		m.BidOrderSize,
		m.BidAoNSize,
		m.BidCustomerSize,
		m.BidCustomerAoNSize,
		m.BidBDSize,
		m.BidBDAoNSize,
		m.AskPrice,
		m.AskSize,
		m.AskOrderSize,
		m.AskAoNSize,
		m.AskCustomerSize,
		m.AskCustomerAoNSize,
		m.AskBDSize,
		m.AskBDAoNSize,
	)
}
func (m efhm_trade) String() string {
	return fmt.Sprintf("%s TRD{P:%10d, S:%d, TC:%d}",
		m.efhm_header,
		m.Price,
		m.Size,
		m.TradeCondition,
	)
}

type EfhLoggerPrinter interface {
	PrintOrder(efhm_order)
	PrintQuote(efhm_quote)
	PrintTrade(efhm_trade)
}

type testefhPrinter struct {
	w io.Writer
}

var _ EfhLoggerPrinter = &testefhPrinter{}

func NewTestefhPrinter(w io.Writer) EfhLoggerPrinter {
	return &testefhPrinter{w: w}
}
func (p *testefhPrinter) PrintOrder(o efhm_order) {
	fmt.Fprintln(p.w, o)
}
func (p *testefhPrinter) PrintQuote(o efhm_quote) {
	fmt.Fprintln(p.w, o)
}
func (p *testefhPrinter) PrintTrade(m efhm_trade) {
	fmt.Fprintln(p.w, m)
}

type EfhLogger struct {
	TobLogger
	printer EfhLoggerPrinter
	mode    EfhLoggerOutputMode
	stream  Stream
}

var _ sim.Observer = &EfhLogger{}

func NewEfhLogger(p EfhLoggerPrinter) *EfhLogger {
	l := &EfhLogger{
		printer:   p,
		TobLogger: *NewTobLogger(),
		stream:    *NewStream(),
	}
	return l
}

type EfhLoggerOutputMode byte

const (
	EfhLoggerOutputOrders EfhLoggerOutputMode = iota
	EfhLoggerOutputQuotes
)

func (l *EfhLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	l.mode = mode
}

func (l *EfhLogger) MessageArrived(idm *sim.SimMessage) {
	l.stream.MessageArrived(idm)
	l.TobLogger.MessageArrived(idm)
	if m, ok := l.stream.getExchangeMessage().(packet.TradeMessage); ok {
		oid, price, size := m.TradeInfo()
		l.lastOptionId = oid
		l.genUpdateTrades(price, size)
	}
}

func (l *EfhLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if l.mode == EfhLoggerOutputOrders {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNew) {
			l.genUpdateOrders(l.bid)
			l.genUpdateOrders(l.ask)
		}
	} else {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNewForce) {
			l.genUpdateQuotes()
		}
	}
}

func (l *EfhLogger) genUpdateHeader(messageType uint8) efhm_header {
	return efhm_header{
		Type:           messageType,
		SecurityId:     l.lastOptionId.ToUint32(),
		SequenceNumber: uint32(l.stream.getSeqNum()), // FIXME MoldUDP64 seqNum is 64 bit
		TimeStamp:      l.stream.getTimestamp(),
	}
}
func (l *EfhLogger) genUpdateOrders(tob tob) {
	if !tob.updated() {
		return
	}
	m := efhm_order{
		efhm_header: l.genUpdateHeader(EFHM_ORDER),
		Price:       uint32(tob.New.Price),
		Size:        uint32(tob.New.Size),
		OrderType:   1,
	}
	switch tob.Side {
	case packet.MarketSideBid:
		m.OrderSide = EFH_ORDER_BID
	case packet.MarketSideAsk:
		m.OrderSide = EFH_ORDER_ASK
	}
	l.printer.PrintOrder(m)
}
func (l *EfhLogger) genUpdateQuotes() {
	m := efhm_quote{
		efhm_header: l.genUpdateHeader(EFHM_QUOTE),
		BidPrice:    uint32(l.bid.New.Price),
		BidSize:     uint32(l.bid.New.Size),
		AskPrice:    uint32(l.ask.New.Price),
		AskSize:     uint32(l.ask.New.Size),
	}
	l.printer.PrintQuote(m)
}
func (l *EfhLogger) genUpdateTrades(price packet.Price, size int) {
	m := efhm_trade{
		efhm_header: l.genUpdateHeader(EFHM_TRADE),
		Price:       uint32(packet.PriceTo4Dec(price)),
		Size:        uint32(size),
	}
	l.printer.PrintTrade(m)
}
<commit_msg>rec:EfhLogger: expand efhm_header fields to 64 bit<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"fmt"
	"io"

	"my/ev/packet"
	"my/ev/sim"
)

const (
	EFHM_DEFINITION = 0
	EFHM_TRADE      = 1
	EFHM_QUOTE      = 2
	EFHM_ORDER      = 3
	EFHM_REFRESHED  = 100
	EFHM_STOPPED    = 101
)
const (
	EFH_ORDER_BID = 1
	EFH_ORDER_ASK = -1
)

type efhm_header struct {
	Type           uint8
	TickCondition  uint8
	QueuePosition  uint16
	UnderlyingId   uint32
	SecurityId     uint64
	SequenceNumber uint64
	TimeStamp      uint64
}

type efhm_order struct {
	efhm_header
	TradeStatus     uint8
	OrderType       uint8
	OrderSide       int8
	_pad            byte
	Price           uint32
	Size            uint32
	AoNSize         uint32
	CustomerSize    uint32
	CustomerAoNSize uint32
	BDSize          uint32
	BDAoNSize       uint32
}

type efhm_quote struct {
	efhm_header
	TradeStatus        uint8
	_pad               [3]byte
	BidPrice           uint32
	BidSize            uint32
	BidOrderSize       uint32
	BidAoNSize         uint32
	BidCustomerSize    uint32
	BidCustomerAoNSize uint32
	BidBDSize          uint32
	BidBDAoNSize       uint32
	AskPrice           uint32
	AskSize            uint32
	AskOrderSize       uint32
	AskAoNSize         uint32
	AskCustomerSize    uint32
	AskCustomerAoNSize uint32
	AskBDSize          uint32
	AskBDAoNSize       uint32
}

type efhm_trade struct {
	efhm_header
	Price          uint32
	Size           uint32
	TradeCondition uint8
}

func (m efhm_header) String() string {
	switch m.Type {
	case EFHM_QUOTE, EFHM_ORDER, EFHM_TRADE:
		return fmt.Sprintf("HDR{T:%d, TC:%d, QP:%d, UId:%08x, SId:%08x, SN:%d, TS:%08x}",
			m.Type,
			m.TickCondition,
			m.QueuePosition,
			m.UnderlyingId,
			m.SecurityId,
			m.SequenceNumber,
			m.TimeStamp,
		)
	default:
		return fmt.Sprintf("HDR{T:%d}", m.Type)
	}
}
func (m efhm_order) String() string {
	return fmt.Sprintf("%s ORD{TS:%d, OT:%d, OS:%+d, P:%10d, S:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}",
		m.efhm_header,
		m.TradeStatus,
		m.OrderType,
		m.OrderSide,
		m.Price,
		m.Size,
		m.AoNSize,
		m.CustomerSize,
		m.CustomerAoNSize,
		m.BDSize,
		m.BDAoNSize,
	)
}
func (m efhm_quote) String() string {
	return fmt.Sprintf("%s QUO{TS:%d, "+
		"Bid{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}, "+
		"Ask{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}"+
		"}",
		m.efhm_header,
		m.TradeStatus,
		m.BidPrice,
		m.BidSize,
		m.BidOrderSize,
		m.BidAoNSize,
		m.BidCustomerSize,
		m.BidCustomerAoNSize,
		m.BidBDSize,
		m.BidBDAoNSize,
		m.AskPrice,
		m.AskSize,
		m.AskOrderSize,
		m.AskAoNSize,
		m.AskCustomerSize,
		m.AskCustomerAoNSize,
		m.AskBDSize,
		m.AskBDAoNSize,
	)
}
func (m efhm_trade) String() string {
	return fmt.Sprintf("%s TRD{P:%10d, S:%d, TC:%d}",
		m.efhm_header,
		m.Price,
		m.Size,
		m.TradeCondition,
	)
}

type EfhLoggerPrinter interface {
	PrintOrder(efhm_order)
	PrintQuote(efhm_quote)
	PrintTrade(efhm_trade)
}

type testefhPrinter struct {
	w io.Writer
}

var _ EfhLoggerPrinter = &testefhPrinter{}

func NewTestefhPrinter(w io.Writer) EfhLoggerPrinter {
	return &testefhPrinter{w: w}
}
func (p *testefhPrinter) PrintOrder(o efhm_order) {
	fmt.Fprintln(p.w, o)
}
func (p *testefhPrinter) PrintQuote(o efhm_quote) {
	fmt.Fprintln(p.w, o)
}
func (p *testefhPrinter) PrintTrade(m efhm_trade) {
	fmt.Fprintln(p.w, m)
}

type EfhLogger struct {
	TobLogger
	printer EfhLoggerPrinter
	mode    EfhLoggerOutputMode
	stream  Stream
}

var _ sim.Observer = &EfhLogger{}

func NewEfhLogger(p EfhLoggerPrinter) *EfhLogger {
	l := &EfhLogger{
		printer:   p,
		TobLogger: *NewTobLogger(),
		stream:    *NewStream(),
	}
	return l
}

type EfhLoggerOutputMode byte

const (
	EfhLoggerOutputOrders EfhLoggerOutputMode = iota
	EfhLoggerOutputQuotes
)

func (l *EfhLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	l.mode = mode
}

func (l *EfhLogger) MessageArrived(idm *sim.SimMessage) {
	l.stream.MessageArrived(idm)
	l.TobLogger.MessageArrived(idm)
	if m, ok := l.stream.getExchangeMessage().(packet.TradeMessage); ok {
		oid, price, size := m.TradeInfo()
		l.lastOptionId = oid
		l.genUpdateTrades(price, size)
	}
}

func (l *EfhLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if l.mode == EfhLoggerOutputOrders {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNew) {
			l.genUpdateOrders(l.bid)
			l.genUpdateOrders(l.ask)
		}
	} else {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNewForce) {
			l.genUpdateQuotes()
		}
	}
}

func (l *EfhLogger) genUpdateHeader(messageType uint8) efhm_header {
	return efhm_header{
		Type:           messageType,
		SecurityId:     l.lastOptionId.ToUint64(),
		SequenceNumber: l.stream.getSeqNum(),
		TimeStamp:      l.stream.getTimestamp(),
	}
}
func (l *EfhLogger) genUpdateOrders(tob tob) {
	if !tob.updated() {
		return
	}
	m := efhm_order{
		efhm_header: l.genUpdateHeader(EFHM_ORDER),
		Price:       uint32(tob.New.Price),
		Size:        uint32(tob.New.Size),
		OrderType:   1,
	}
	switch tob.Side {
	case packet.MarketSideBid:
		m.OrderSide = EFH_ORDER_BID
	case packet.MarketSideAsk:
		m.OrderSide = EFH_ORDER_ASK
	}
	l.printer.PrintOrder(m)
}
func (l *EfhLogger) genUpdateQuotes() {
	m := efhm_quote{
		efhm_header: l.genUpdateHeader(EFHM_QUOTE),
		BidPrice:    uint32(l.bid.New.Price),
		BidSize:     uint32(l.bid.New.Size),
		AskPrice:    uint32(l.ask.New.Price),
		AskSize:     uint32(l.ask.New.Size),
	}
	l.printer.PrintQuote(m)
}
func (l *EfhLogger) genUpdateTrades(price packet.Price, size int) {
	m := efhm_trade{
		efhm_header: l.genUpdateHeader(EFHM_TRADE),
		Price:       uint32(packet.PriceTo4Dec(price)),
		Size:        uint32(size),
	}
	l.printer.PrintTrade(m)
}
<|endoftext|>


<commit_before>package particle

import (
	"math"
	"time"

	"github.com/200sc/go-dist/intrange"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/event"
	"github.com/oakmound/oak/physics"
	"github.com/oakmound/oak/render"
	"github.com/oakmound/oak/timing"
)

const (
	//IgnoreEnd refers to the life value given to particles that want to skip their source's end function.
	IgnoreEnd = -2000 / 2
)

// A Source is used to store and control a set of particles.
type Source struct {
	render.Layered
	Generator  Generator
	particles  [blockSize]Particle
	nextPID    int
	CID        event.CID
	pIDBlock   int
	stackLevel int
	paused     bool
	EndFunc    func()
}

// NewSource creates a new source
func NewSource(g Generator, stackLevel int) *Source {
	ps := new(Source)
	ps.Generator = g
	ps.stackLevel = stackLevel
	ps.Init()
	return ps
}

// Init allows a source to be considered as an entity, and initializes it
func (ps *Source) Init() event.CID {
	CID := event.NextID(ps)
	CID.Bind(rotateParticles, event.Enter)
	ps.CID = CID
	ps.pIDBlock = Allocate(ps.CID)
	if ps.Generator.GetBaseGenerator().Duration != Inf {
		go func(ps *Source, duration intrange.Range) {
			timing.DoAfter(time.Duration(duration.Poll())*time.Millisecond, func() {
				ps.Stop()
			})
		}(ps, ps.Generator.GetBaseGenerator().Duration)
	}
	return CID
}

func (ps *Source) cycleParticles() bool {
	pg := ps.Generator.GetBaseGenerator()
	cycled := false
	for i := 0; i < ps.nextPID; i++ {
		p := ps.particles[i]
		bp := p.GetBaseParticle()
		for bp.Life <= 0 {
			p.Undraw()
			cycled = true
			if pg.EndFunc != nil && bp.Life > IgnoreEnd {
				pg.EndFunc(p)
			}
			ps.nextPID--
			if i == ps.nextPID {
				return cycled
			}
			ps.particles[i], ps.particles[ps.nextPID] = ps.particles[ps.nextPID], ps.particles[i]

			p = ps.particles[i]
			p.setPID(i + ps.pIDBlock*blockSize)
			bp = p.GetBaseParticle()
		}
		// Ignore dead particles
		if bp.Life > 0 {
			cycled = true
			bp.Life--
			// Apply rotational acceleration
			if pg.Rotation != nil {
				bp.Vel = bp.Vel.Rotate(pg.Rotation.Poll())
			}

			if pg.SpeedDecay.X() != 0 {
				bp.Vel = bp.Vel.SetX(bp.Vel.X() * pg.SpeedDecay.X())
				if math.Abs(bp.Vel.X()) < 0.2 {
					bp.Vel = bp.Vel.SetX(0)
				}
			}
			if pg.SpeedDecay.Y() != 0 {
				bp.Vel = bp.Vel.SetY(bp.Vel.Y() * pg.SpeedDecay.Y())
				if math.Abs(bp.Vel.Y()) < 0.2 {
					bp.Vel = bp.Vel.SetY(0)
				}
			}

			bp.Vel.Add(pg.Gravity)
			bp.Add(bp.Vel)
			bp.SetLayer(ps.Layer(bp.GetPos()))
			p.Cycle(ps.Generator)
		}
	}
	return cycled
}

// Layer is shorthand for getting the base generator behind a source's layer
func (ps *Source) Layer(v physics.Vector) int {
	return ps.Generator.GetBaseGenerator().LayerFunc(v)
}

func (ps *Source) addParticles() {
	pg := ps.Generator.GetBaseGenerator()
	// Regularly create particles (up until max particles)
	newParticleCount := int(pg.NewPerFrame.Poll())

	if ps.nextPID+newParticleCount >= blockSize {
		newParticleCount = blockSize - ps.nextPID
	}

	if ps.nextPID+newParticleCount >= pg.ParticleLimit {
		newParticleCount = pg.ParticleLimit - ps.nextPID
	}

	var p Particle
	var bp *baseParticle
	for i := 0; i < newParticleCount; i++ {
		angle := pg.Angle.Poll()
		speed := pg.Speed.Poll()
		startLife := pg.LifeSpan.Poll()

		// If this particle has not been allocated yet
		if ps.particles[ps.nextPID] == nil {
			bp = &baseParticle{
				LayeredPoint: render.NewLayeredPoint(
					pg.X()+floatFromSpread(pg.Spread.X()),
					pg.Y()+floatFromSpread(pg.Spread.Y()),
					0,
				),
				Src: ps,
				Vel: physics.NewVector(
					speed*math.Cos(angle)*-1,
					speed*math.Sin(angle)*-1),
				Life:      startLife,
				totalLife: startLife,
				pID:       ps.nextPID + ps.pIDBlock*blockSize,
			}

			p = ps.Generator.GenerateParticle(bp)

			// If this is a 'recycled' particle waiting to be redrawn
		} else {
			bp = ps.particles[ps.nextPID].GetBaseParticle()
			bp.LayeredPoint = render.NewLayeredPoint(
				pg.X()+floatFromSpread(pg.Spread.X()),
				pg.Y()+floatFromSpread(pg.Spread.Y()),
				0)
			bp.Vel = physics.NewVector(
				speed*math.Cos(angle)*-1,
				speed*math.Sin(angle)*-1)
			bp.Life = startLife
			bp.totalLife = startLife
			p = ps.Generator.GenerateParticle(bp)

		}
		ps.particles[ps.nextPID] = p
		ps.nextPID++
		p.SetLayer(ps.Layer(bp.GetPos()))
		_, err := render.Draw(p, ps.stackLevel)
		dlog.ErrorCheck(err)
	}

}

// rotateParticles updates particles over time as long
// as a Source is active.
func rotateParticles(id int, nothing interface{}) int {
	ps := event.GetEntity(id).(*Source)
	if !ps.paused {
		ps.cycleParticles()
		ps.addParticles()
	}
	return 0
}

// clearParticles is used after a Source has been stopped
// to continue moving old particles for as long as they exist.
func clearParticles(id int, nothing interface{}) int {
	if ps, ok := event.GetEntity(id).(*Source); ok {
		if !ps.paused {
			if ps.cycleParticles() {
			} else {
				if ps.EndFunc != nil {
					ps.EndFunc()
				}
				event.DestroyEntity(id)
				Deallocate(ps.pIDBlock)
				return event.UnbindEvent
			}
		}

		return 0
	}
	return event.UnbindEvent
}

// Stop manually stops a Source, if its duration is infinite
// or if it should be stopped before expriring naturally.
func (ps *Source) Stop() {
	if ps == nil {
		return
	}
	ps.CID.UnbindAllAndRebind([]event.Bindable{clearParticles}, []string{event.Enter})
}

// Pause on a Source just stops the repetition
// of its rotation function, which moves, destroys,
// ages and generates particles. Existing particles will
// stay in place.
func (ps *Source) Pause() {
	ps.paused = true
}

// UnPause on a source a Source rebinds it's rotate function.
func (ps *Source) UnPause() {
	ps.paused = false
}

// ShiftX shift's a source's underlying generator
func (ps *Source) ShiftX(x float64) {
	ps.Generator.ShiftX(x)
}

// ShiftY shift's a source's underlying generator (todo: consider if this shoud be composed)
func (ps *Source) ShiftY(y float64) {
	ps.Generator.ShiftY(y)
}

// SetPos sets a source's underlying generator
func (ps *Source) SetPos(x, y float64) {
	ps.Generator.SetPos(x, y)
}
<commit_msg>Add zero check for limit<commit_after>package particle

import (
	"math"
	"time"

	"github.com/200sc/go-dist/intrange"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/event"
	"github.com/oakmound/oak/physics"
	"github.com/oakmound/oak/render"
	"github.com/oakmound/oak/timing"
)

const (
	//IgnoreEnd refers to the life value given to particles that want to skip their source's end function.
	IgnoreEnd = -2000 / 2
)

// A Source is used to store and control a set of particles.
type Source struct {
	render.Layered
	Generator  Generator
	particles  [blockSize]Particle
	nextPID    int
	CID        event.CID
	pIDBlock   int
	stackLevel int
	paused     bool
	EndFunc    func()
}

// NewSource creates a new source
func NewSource(g Generator, stackLevel int) *Source {
	ps := new(Source)
	ps.Generator = g
	ps.stackLevel = stackLevel
	ps.Init()
	return ps
}

// Init allows a source to be considered as an entity, and initializes it
func (ps *Source) Init() event.CID {
	CID := event.NextID(ps)
	CID.Bind(rotateParticles, event.Enter)
	ps.CID = CID
	ps.pIDBlock = Allocate(ps.CID)
	if ps.Generator.GetBaseGenerator().Duration != Inf {
		go func(ps *Source, duration intrange.Range) {
			timing.DoAfter(time.Duration(duration.Poll())*time.Millisecond, func() {
				ps.Stop()
			})
		}(ps, ps.Generator.GetBaseGenerator().Duration)
	}
	return CID
}

func (ps *Source) cycleParticles() bool {
	pg := ps.Generator.GetBaseGenerator()
	cycled := false
	for i := 0; i < ps.nextPID; i++ {
		p := ps.particles[i]
		bp := p.GetBaseParticle()
		for bp.Life <= 0 {
			p.Undraw()
			cycled = true
			if pg.EndFunc != nil && bp.Life > IgnoreEnd {
				pg.EndFunc(p)
			}
			ps.nextPID--
			if i == ps.nextPID {
				return cycled
			}
			ps.particles[i], ps.particles[ps.nextPID] = ps.particles[ps.nextPID], ps.particles[i]

			p = ps.particles[i]
			p.setPID(i + ps.pIDBlock*blockSize)
			bp = p.GetBaseParticle()
		}
		// Ignore dead particles
		if bp.Life > 0 {
			cycled = true
			bp.Life--
			// Apply rotational acceleration
			if pg.Rotation != nil {
				bp.Vel = bp.Vel.Rotate(pg.Rotation.Poll())
			}

			if pg.SpeedDecay.X() != 0 {
				bp.Vel = bp.Vel.SetX(bp.Vel.X() * pg.SpeedDecay.X())
				if math.Abs(bp.Vel.X()) < 0.2 {
					bp.Vel = bp.Vel.SetX(0)
				}
			}
			if pg.SpeedDecay.Y() != 0 {
				bp.Vel = bp.Vel.SetY(bp.Vel.Y() * pg.SpeedDecay.Y())
				if math.Abs(bp.Vel.Y()) < 0.2 {
					bp.Vel = bp.Vel.SetY(0)
				}
			}

			bp.Vel.Add(pg.Gravity)
			bp.Add(bp.Vel)
			bp.SetLayer(ps.Layer(bp.GetPos()))
			p.Cycle(ps.Generator)
		}
	}
	return cycled
}

// Layer is shorthand for getting the base generator behind a source's layer
func (ps *Source) Layer(v physics.Vector) int {
	return ps.Generator.GetBaseGenerator().LayerFunc(v)
}

func (ps *Source) addParticles() {
	pg := ps.Generator.GetBaseGenerator()
	// Regularly create particles (up until max particles)
	newParticleCount := int(pg.NewPerFrame.Poll())

	if ps.nextPID+newParticleCount >= blockSize {
		newParticleCount = blockSize - ps.nextPID
	}

	if pg.ParticleLimit != 0 {
		if ps.nextPID+newParticleCount >= pg.ParticleLimit {
			newParticleCount = pg.ParticleLimit - ps.nextPID
		}
	}

	var p Particle
	var bp *baseParticle
	for i := 0; i < newParticleCount; i++ {
		angle := pg.Angle.Poll()
		speed := pg.Speed.Poll()
		startLife := pg.LifeSpan.Poll()

		// If this particle has not been allocated yet
		if ps.particles[ps.nextPID] == nil {
			bp = &baseParticle{
				LayeredPoint: render.NewLayeredPoint(
					pg.X()+floatFromSpread(pg.Spread.X()),
					pg.Y()+floatFromSpread(pg.Spread.Y()),
					0,
				),
				Src: ps,
				Vel: physics.NewVector(
					speed*math.Cos(angle)*-1,
					speed*math.Sin(angle)*-1),
				Life:      startLife,
				totalLife: startLife,
				pID:       ps.nextPID + ps.pIDBlock*blockSize,
			}

			p = ps.Generator.GenerateParticle(bp)

			// If this is a 'recycled' particle waiting to be redrawn
		} else {
			bp = ps.particles[ps.nextPID].GetBaseParticle()
			bp.LayeredPoint = render.NewLayeredPoint(
				pg.X()+floatFromSpread(pg.Spread.X()),
				pg.Y()+floatFromSpread(pg.Spread.Y()),
				0)
			bp.Vel = physics.NewVector(
				speed*math.Cos(angle)*-1,
				speed*math.Sin(angle)*-1)
			bp.Life = startLife
			bp.totalLife = startLife
			p = ps.Generator.GenerateParticle(bp)

		}
		ps.particles[ps.nextPID] = p
		ps.nextPID++
		p.SetLayer(ps.Layer(bp.GetPos()))
		_, err := render.Draw(p, ps.stackLevel)
		dlog.ErrorCheck(err)
	}

}

// rotateParticles updates particles over time as long
// as a Source is active.
func rotateParticles(id int, nothing interface{}) int {
	ps := event.GetEntity(id).(*Source)
	if !ps.paused {
		ps.cycleParticles()
		ps.addParticles()
	}
	return 0
}

// clearParticles is used after a Source has been stopped
// to continue moving old particles for as long as they exist.
func clearParticles(id int, nothing interface{}) int {
	if ps, ok := event.GetEntity(id).(*Source); ok {
		if !ps.paused {
			if ps.cycleParticles() {
			} else {
				if ps.EndFunc != nil {
					ps.EndFunc()
				}
				event.DestroyEntity(id)
				Deallocate(ps.pIDBlock)
				return event.UnbindEvent
			}
		}

		return 0
	}
	return event.UnbindEvent
}

// Stop manually stops a Source, if its duration is infinite
// or if it should be stopped before expriring naturally.
func (ps *Source) Stop() {
	if ps == nil {
		return
	}
	ps.CID.UnbindAllAndRebind([]event.Bindable{clearParticles}, []string{event.Enter})
}

// Pause on a Source just stops the repetition
// of its rotation function, which moves, destroys,
// ages and generates particles. Existing particles will
// stay in place.
func (ps *Source) Pause() {
	ps.paused = true
}

// UnPause on a source a Source rebinds it's rotate function.
func (ps *Source) UnPause() {
	ps.paused = false
}

// ShiftX shift's a source's underlying generator
func (ps *Source) ShiftX(x float64) {
	ps.Generator.ShiftX(x)
}

// ShiftY shift's a source's underlying generator (todo: consider if this shoud be composed)
func (ps *Source) ShiftY(y float64) {
	ps.Generator.ShiftY(y)
}

// SetPos sets a source's underlying generator
func (ps *Source) SetPos(x, y float64) {
	ps.Generator.SetPos(x, y)
}
<|endoftext|>


<commit_before>package configuration

import (
	"cf"
	"fileutils"
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	"path/filepath"
	"testing"
)

func TestLoadingWithNoConfigFile(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		assert.Equal(t, config.Target, "")
		assert.Equal(t, config.ApiVersion, "")
		assert.Equal(t, config.AuthorizationEndpoint, "")
		assert.Equal(t, config.AccessToken, "")
	})
}

func TestSavingAndLoading(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		configToSave, err := repo.Get()
		assert.NoError(t, err)

		configToSave.ApiVersion = "3.1.0"
		configToSave.Target = "https://api.target.example.com"
		configToSave.AuthorizationEndpoint = "https://login.target.example.com"
		configToSave.AccessToken = "bearer my_access_token"

		repo.Save()

		singleton = nil
		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig, configToSave)
	})
}

func TestSetOrganization(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.OrganizationFields = cf.OrganizationFields{}

		org := cf.OrganizationFields{}
		org.Name = "my-org"
		org.Guid = "my-org-guid"
		err = repo.SetOrganization(org)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestSetSpace(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		repo.Get()
		space := cf.SpaceFields{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"

		err := repo.SetSpace(space)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearTokens(t *testing.T) {
	withFakeHome(func() {
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"

		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		config.OrganizationFields = org
		config.SpaceFields = space
		repo.Save()

		err = repo.ClearTokens()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearSession(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"
		repo.Save()

		err = repo.ClearSession()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, cf.OrganizationFields{})
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestNewConfigGivesYouCurrentVersionedConfig(t *testing.T) {
	withFakeHome(func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
	})
}

func TestReadingOutdatedConfigReturnsNewConfig(t *testing.T) {
	withConfigFixture(t, "outdated-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()

		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
		assert.Equal(t, config.Target, "")
	})
}

func TestReadingVersionNumberFromExistingConfig(t *testing.T) {
	withConfigFixture(t, "versioned-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 9001)
	})
}

func withFakeHome(callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	defer func() {
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		NewConfigurationDiskRepository().Delete()
	}()

	fileutils.TempDir("test-config", func(dir string, err error) {
		os.Setenv("HOME", dir)
		os.Setenv("HOMEPATH", dir)
		callback()
	})
}

func withConfigFixture(t *testing.T, name string, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	defer func() {
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		singleton = nil
	}()

	cwd, err := os.Getwd()
	assert.NoError(t, err)

	fixturePath := filepath.Join(cwd, fmt.Sprintf("../../fixtures/config/%s", name))
	os.Setenv("HOME", fixturePath)
	os.Setenv("HOMEPATH", fixturePath)
	callback()
}
<commit_msg>Append volume name and relative path for config test on windows<commit_after>package configuration

import (
	"cf"
	"fileutils"
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	"path/filepath"
	"testing"
	"strings"
)

func TestLoadingWithNoConfigFile(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		assert.Equal(t, config.Target, "")
		assert.Equal(t, config.ApiVersion, "")
		assert.Equal(t, config.AuthorizationEndpoint, "")
		assert.Equal(t, config.AccessToken, "")
	})
}

func TestSavingAndLoading(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		configToSave, err := repo.Get()
		assert.NoError(t, err)

		configToSave.ApiVersion = "3.1.0"
		configToSave.Target = "https://api.target.example.com"
		configToSave.AuthorizationEndpoint = "https://login.target.example.com"
		configToSave.AccessToken = "bearer my_access_token"

		repo.Save()

		singleton = nil
		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig, configToSave)
	})
}

func TestSetOrganization(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.OrganizationFields = cf.OrganizationFields{}

		org := cf.OrganizationFields{}
		org.Name = "my-org"
		org.Guid = "my-org-guid"
		err = repo.SetOrganization(org)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestSetSpace(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		repo.Get()
		space := cf.SpaceFields{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"

		err := repo.SetSpace(space)
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearTokens(t *testing.T) {
	withFakeHome(t, func() {
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"

		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		config.OrganizationFields = org
		config.SpaceFields = space
		repo.Save()

		err = repo.ClearTokens()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, org)
		assert.Equal(t, savedConfig.SpaceFields, space)
	})
}

func TestClearSession(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)

		config.Target = "http://api.example.com"
		config.RefreshToken = "some old refresh token"
		config.AccessToken = "some old access token"
		org := cf.OrganizationFields{}
		org.Name = "my-org"
		space := cf.SpaceFields{}
		space.Name = "my-space"
		repo.Save()

		err = repo.ClearSession()
		assert.NoError(t, err)

		repo.Save()

		savedConfig, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, savedConfig.Target, "http://api.example.com")
		assert.Empty(t, savedConfig.AccessToken)
		assert.Empty(t, savedConfig.RefreshToken)
		assert.Equal(t, savedConfig.OrganizationFields, cf.OrganizationFields{})
		assert.Equal(t, savedConfig.SpaceFields, cf.SpaceFields{})
	})
}

func TestNewConfigGivesYouCurrentVersionedConfig(t *testing.T) {
	withFakeHome(t, func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
	})
}

func TestReadingOutdatedConfigReturnsNewConfig(t *testing.T) {
	withConfigFixture(t, "outdated-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()

		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 1)
		assert.Equal(t, config.Target, "")
	})
}

func TestReadingVersionNumberFromExistingConfig(t *testing.T) {
	withConfigFixture(t, "versioned-config", func() {
		repo := NewConfigurationDiskRepository()
		config, err := repo.Get()
		assert.NoError(t, err)
		assert.Equal(t, config.ConfigVersion, 9001)
	})
}

func withFakeHome(t *testing.T, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	oldHomeDrive := os.Getenv("HOMEDRIVE")
	defer func() {
		os.Setenv("HOMEDRIVE", oldHomeDrive)
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		NewConfigurationDiskRepository().Delete()
	}()

	fileutils.TempDir("test-config", func(dir string, err error) {
		os.Setenv("HOME", dir)

		volumeName := filepath.VolumeName(dir)
		if volumeName != "" {
			relativePath := strings.Replace(dir, volumeName, "", 1)

			os.Setenv("HOMEPATH", relativePath)
			os.Setenv("HOMEDRIVE", volumeName)
		}

		callback()
	})
}

func withConfigFixture(t *testing.T, name string, callback func()) {
	oldHome := os.Getenv("HOME")
	oldHomePath := os.Getenv("HOMEPATH")
	oldHomeDrive := os.Getenv("HOMEDRIVE")
	defer func() {
		os.Setenv("HOMEDRIVE", oldHomeDrive)
		os.Setenv("HOMEPATH", oldHomePath)
		os.Setenv("HOME", oldHome)
	}()

	defer func() {
		singleton = nil
	}()

	cwd, err := os.Getwd()
	assert.NoError(t, err)

	fixturePath := filepath.Join(cwd, fmt.Sprintf("../../fixtures/config/%s", name))
	os.Setenv("HOME", fixturePath)

	volumeName := filepath.VolumeName(fixturePath)
	if volumeName != "" {
		relativePath := strings.Replace(fixturePath, volumeName, "", 1)

		os.Setenv("HOMEPATH", relativePath)
		os.Setenv("HOMEDRIVE", volumeName)
	}

	callback()
}
<|endoftext|>


<commit_before>package revok

import (
	"encoding/json"

	"code.cloudfoundry.org/lager"
	"github.com/google/go-github/github"
)

//go:generate counterfeiter . GitHubClient

type GitHubClient interface {
	ListRepositories(lager.Logger) ([]GitHubRepository, error)
}

type client struct {
	ghClient *github.Client
}

func NewGitHubClient(ghClient *github.Client) GitHubClient {
	return &client{
		ghClient: ghClient,
	}
}

func (c *client) ListRepositories(logger lager.Logger) ([]GitHubRepository, error) {
	logger = logger.Session("list-originalRepositories")

	opts := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 30},
	}

	var originalRepos []*github.Repository

	for {
		rs, resp, err := c.ghClient.Repositories.List("", opts)
		if err != nil {
			logger.Error("failed", err, lager.Data{
				"fetching-page": opts.ListOptions.Page,
			})
			return nil, err
		}

		originalRepos = append(originalRepos, rs...)

		if resp.NextPage == 0 {
			break
		}

		opts.ListOptions.Page = resp.NextPage
	}

	var repos []GitHubRepository

	for _, r := range originalRepos {
		rawJSONBytes, err := json.Marshal(r)
		if err != nil {
			logger.Error("failed-to-marshal-json", err)
			return nil, err
		}

		repos = append(repos, GitHubRepository{
			Name:          *r.Name,
			Owner:         *r.Owner.Login,
			SSHURL:        *r.SSHURL,
			Private:       *r.Private,
			DefaultBranch: *r.DefaultBranch,
			RawJSON:       rawJSONBytes,
		})
	}

	return repos, nil
}

type GitHubRepository struct {
	Name          string
	Owner         string
	SSHURL        string
	Private       bool
	DefaultBranch string
	RawJSON       []byte
}
<commit_msg>Remove unnecessary *github.Repository array<commit_after>package revok

import (
	"encoding/json"

	"code.cloudfoundry.org/lager"
	"github.com/google/go-github/github"
)

//go:generate counterfeiter . GitHubClient

type GitHubClient interface {
	ListRepositories(lager.Logger) ([]GitHubRepository, error)
}

type client struct {
	ghClient *github.Client
}

func NewGitHubClient(ghClient *github.Client) GitHubClient {
	return &client{
		ghClient: ghClient,
	}
}

func (c *client) ListRepositories(logger lager.Logger) ([]GitHubRepository, error) {
	logger = logger.Session("list-originalRepositories")

	opts := &github.RepositoryListOptions{
		ListOptions: github.ListOptions{PerPage: 30},
	}

	var repos []GitHubRepository

	for {
		rs, resp, err := c.ghClient.Repositories.List("", opts)
		if err != nil {
			logger.Error("failed", err, lager.Data{
				"fetching-page": opts.ListOptions.Page,
			})
			return nil, err
		}

		for _, repo := range rs {
			rawJSONBytes, err := json.Marshal(repo)
			if err != nil {
				logger.Error("failed-to-marshal-json", err)
				return nil, err
			}

			repos = append(repos, GitHubRepository{
				Name:          *repo.Name,
				Owner:         *repo.Owner.Login,
				SSHURL:        *repo.SSHURL,
				Private:       *repo.Private,
				DefaultBranch: *repo.DefaultBranch,
				RawJSON:       rawJSONBytes,
			})
		}

		if resp.NextPage == 0 {
			break
		}

		opts.ListOptions.Page = resp.NextPage
	}

	return repos, nil
}

type GitHubRepository struct {
	Name          string
	Owner         string
	SSHURL        string
	Private       bool
	DefaultBranch string
	RawJSON       []byte
}
<|endoftext|>