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

package main

import (
	"github.com/ligato/vpp-agent/plugins/vpp/binapi/interfaces"
	"log"
	"net"
	"time"

	"git.fd.io/govpp.git/api"
	"github.com/ligato/vpp-agent/plugins/govppmux"

	"github.com/ligato/cn-infra/agent"
)

func main() {
	// Create an instance of our plugin.
	p := new(HelloWorld)
	p.GoVPPMux = &govppmux.DefaultPlugin

	// Create new agent with our plugin instance.
	a := agent.NewAgent(agent.AllPlugins(p))

	// Run starts the agent with plugins, wait until shutdown
	// and then stops the agent and its plugins.
	if err := a.Start(); err != nil {
		log.Fatalln(err)
	}

	p.syncVppCall()
	p.asyncVppCall()
	p.multiRequestCall()

	if err := a.Stop(); err != nil {
		log.Fatalln(err)
	}
}

// HelloWorld represents our plugin.
type HelloWorld struct {
	vppChan api.Channel

	GoVPPMux govppmux.API
}

// String is used to identify the plugin by giving it name.
func (p *HelloWorld) String() string {
	return "HelloWorld"
}

// Init is executed on agent initialization.
func (p *HelloWorld) Init() (err error) {
	log.Println("Hello World!")

	if p.vppChan, err = p.GoVPPMux.NewAPIChannel(); err != nil {
		panic(err)
	}

	return nil
}

func (p *HelloWorld) syncVppCall() {
	// prepare request
	request := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:01"),
	}
	// prepare reply
	reply := &interfaces.CreateLoopbackReply{}
	// send request and obtain reply
	err := p.vppChan.SendRequest(request).ReceiveReply(reply)
	if err != nil {
		panic(err)
	}
	// check return value
	if reply.Retval != 0 {
		log.Panicf("Sync call loopback create returned %d", reply.Retval)
	}

	log.Printf("Sync call created loopback with index %d", reply.SwIfIndex)
}

func (p *HelloWorld) asyncVppCall() {
	// prepare requests
	request1 := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:02"),
	}
	request2 := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:03"),
	}

	// obtain contexts
	reqCtx1 := p.vppChan.SendRequest(request1)
	reqCtx2 := p.vppChan.SendRequest(request2)

	// wait a bit
	time.Sleep(2 * time.Second)

	// prepare replies
	reply1 := &interfaces.CreateLoopbackReply{}
	reply2 := &interfaces.CreateLoopbackReply{}

	// receive replies
	if err := reqCtx1.ReceiveReply(reply1); err != nil {
		panic(err)
	}
	if err := reqCtx2.ReceiveReply(reply2); err != nil {
		panic(err)
	}

	log.Printf("Async call created loopbacks with indexes %d and %d",
		reply1.SwIfIndex, reply2.SwIfIndex)
}

func (p *HelloWorld) multiRequestCall() {
	// prepare request
	request := &interfaces.SwInterfaceDump{}
	multiReqCtx := p.vppChan.SendMultiRequest(request)

	// read replies in the loop
	for {
		reply := &interfaces.SwInterfaceDetails{}
		last, err := multiReqCtx.ReceiveReply(reply)
		if err != nil {
			panic(err)
		}
		if last {
			break
		}
		log.Printf("received VPP interface with index %d", reply.SwIfIndex)
	}
}

// Close is executed on agent shutdown.
func (p *HelloWorld) Close() error {
	p.vppChan.Close()
	log.Println("Goodbye World!")
	return nil
}

func macParser(mac string) []byte {
	hw, err := net.ParseMAC(mac)
	if err != nil {
		panic(err)
	}
	return hw
}
<commit_msg>update import<commit_after>//  Copyright (c) 2019 Cisco and/or its affiliates.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at:
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package main

import (
	"github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1901/interfaces"
	"log"
	"net"
	"time"

	"git.fd.io/govpp.git/api"
	"github.com/ligato/vpp-agent/plugins/govppmux"

	"github.com/ligato/cn-infra/agent"
)

func main() {
	// Create an instance of our plugin.
	p := new(HelloWorld)
	p.GoVPPMux = &govppmux.DefaultPlugin

	// Create new agent with our plugin instance.
	a := agent.NewAgent(agent.AllPlugins(p))

	// Run starts the agent with plugins, wait until shutdown
	// and then stops the agent and its plugins.
	if err := a.Start(); err != nil {
		log.Fatalln(err)
	}

	p.syncVppCall()
	p.asyncVppCall()
	p.multiRequestCall()

	if err := a.Stop(); err != nil {
		log.Fatalln(err)
	}
}

// HelloWorld represents our plugin.
type HelloWorld struct {
	vppChan api.Channel

	GoVPPMux govppmux.API
}

// String is used to identify the plugin by giving it name.
func (p *HelloWorld) String() string {
	return "HelloWorld"
}

// Init is executed on agent initialization.
func (p *HelloWorld) Init() (err error) {
	log.Println("Hello World!")

	if p.vppChan, err = p.GoVPPMux.NewAPIChannel(); err != nil {
		panic(err)
	}

	return nil
}

func (p *HelloWorld) syncVppCall() {
	// prepare request
	request := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:01"),
	}
	// prepare reply
	reply := &interfaces.CreateLoopbackReply{}
	// send request and obtain reply
	err := p.vppChan.SendRequest(request).ReceiveReply(reply)
	if err != nil {
		panic(err)
	}
	// check return value
	if reply.Retval != 0 {
		log.Panicf("Sync call loopback create returned %d", reply.Retval)
	}

	log.Printf("Sync call created loopback with index %d", reply.SwIfIndex)
}

func (p *HelloWorld) asyncVppCall() {
	// prepare requests
	request1 := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:02"),
	}
	request2 := &interfaces.CreateLoopback{
		MacAddress: macParser("00:00:00:00:00:03"),
	}

	// obtain contexts
	reqCtx1 := p.vppChan.SendRequest(request1)
	reqCtx2 := p.vppChan.SendRequest(request2)

	// wait a bit
	time.Sleep(2 * time.Second)

	// prepare replies
	reply1 := &interfaces.CreateLoopbackReply{}
	reply2 := &interfaces.CreateLoopbackReply{}

	// receive replies
	if err := reqCtx1.ReceiveReply(reply1); err != nil {
		panic(err)
	}
	if err := reqCtx2.ReceiveReply(reply2); err != nil {
		panic(err)
	}

	log.Printf("Async call created loopbacks with indexes %d and %d",
		reply1.SwIfIndex, reply2.SwIfIndex)
}

func (p *HelloWorld) multiRequestCall() {
	// prepare request
	request := &interfaces.SwInterfaceDump{}
	multiReqCtx := p.vppChan.SendMultiRequest(request)

	// read replies in the loop
	for {
		reply := &interfaces.SwInterfaceDetails{}
		last, err := multiReqCtx.ReceiveReply(reply)
		if err != nil {
			panic(err)
		}
		if last {
			break
		}
		log.Printf("received VPP interface with index %d", reply.SwIfIndex)
	}
}

// Close is executed on agent shutdown.
func (p *HelloWorld) Close() error {
	p.vppChan.Close()
	log.Println("Goodbye World!")
	return nil
}

func macParser(mac string) []byte {
	hw, err := net.ParseMAC(mac)
	if err != nil {
		panic(err)
	}
	return hw
}
<|endoftext|>


<commit_before>package backend

import (
	"database/sql/driver"
	"encoding/json"

	"facette/mapper"
	"facette/template"

	"github.com/facette/sliceutil"
)

// Collection represents a library collection item instance.
type Collection struct {
	Item
	Entries    CollectionEntryList `json:"entries,omitempty"`
	Link       *Collection         `orm:"type:varchar(36);foreign_key:ID" json:"-"`
	LinkID     string              `orm:"-" json:"link,omitempty"`
	Attributes mapper.Map          `json:"attributes,omitempty"`
	Alias      string              `orm:"type:varchar(128);unique" json:"alias,omitempty"`
	Options    mapper.Map          `json:"options,omitempty"`
	Parent     *Collection         `orm:"type:varchar(36);foreign_key:ID" json:"-"`
	ParentID   string              `orm:"-" json:"parent,omitempty"`
	Template   bool                `orm:"not_null;default:false" json:"template"`
}

// Validate checks whether or not the collection item instance is valid.
func (c Collection) Validate(backend *Backend) error {
	if err := c.Item.Validate(backend); err != nil {
		return err
	}

	// Check for parent identifier
	if c.ParentID == "" {
		return nil
	} else if c.ID == c.ParentID {
		return ErrInvalidParent
	}

	// Get collections associations
	tx := backend.db.Begin()
	defer tx.Commit()

	q := tx.Select("id", "parent").Where("parent IS NOT NULL").From(Collection{})

	rows, err := q.Rows()
	if err != nil {
		return err
	}
	defer rows.Close()

	collections := map[string]string{}
	for rows.Next() {
		var collection Collection
		if err := q.Scan(rows, &collection).Error(); err != nil {
			return err
		}
		collections[collection.ID] = collection.ParentID
	}

	// Loop through collections for conflicting parenting
	parent := c.ParentID
	for {
		var ok bool

		parent, ok = collections[parent]
		if !ok {
			break
		} else if parent == c.ID {
			return ErrInvalidParent
		}
	}

	return nil
}

// CollectionEntryList represents a list of library collection entries.
type CollectionEntryList []CollectionEntry

// Value marshals the collection entries for compatibility with SQL drivers.
func (l CollectionEntryList) Value() (driver.Value, error) {
	data, err := json.Marshal(l)
	return data, err
}

// Scan unmarshals the collection entries retrieved from SQL drivers.
func (l *CollectionEntryList) Scan(v interface{}) error {
	return json.Unmarshal(v.([]byte), l)
}

// CollectionEntry represents a library collection entry instance.
type CollectionEntry struct {
	ID         string     `json:"id"`
	Attributes mapper.Map `json:"attributes,omitempty"`
	Options    mapper.Map `json:"options,omitempty"`
}

// Expand expands the collection template with attributes passed as parameter.
func (c *Collection) Expand(attrs mapper.Map, backend *Backend) error {
	var err error

	if title, ok := c.Options["title"].(string); ok {
		if c.Options["title"], err = template.Expand(title, attrs); err != nil {
			return err
		}
	}

	c.Attributes.Merge(attrs, true)
	c.Template = false

	// Fecth graph entries titles
	titles := map[string]string{}

	ids := []interface{}{}
	for _, entry := range c.Entries {
		if !sliceutil.Has(ids, entry.ID) {
			ids = append(ids, entry.ID)
		}
	}

	if len(ids) > 0 {
		tx := backend.db.Begin()
		defer tx.Commit()

		graphs := []Graph{}
		tx.Select("id", "options").Where("id IN (?)", ids).Find(&graphs)

		for _, graph := range graphs {
			if title, ok := graph.Options["title"].(string); ok {
				titles[graph.ID] = title
			}
		}
	}

	// Update collection entries with resolved data
	for i := range c.Entries {
		if title, ok := titles[c.Entries[i].ID]; ok {
			c.Entries[i].Attributes.Merge(c.Attributes, true)

			// Set title in options
			if c.Entries[i].Options == nil {
				c.Entries[i].Options = mapper.Map{}
			}

			if c.Entries[i].Options["title"], err = template.Expand(title, c.Entries[i].Attributes); err != nil {
				return err
			}
		}
	}

	return nil
}
<commit_msg>Add collection cache support in backend<commit_after>package backend

import (
	"database/sql/driver"
	"encoding/json"
	"time"

	"facette/mapper"
	"facette/template"

	"github.com/facette/sliceutil"
)

const collectionCacheTime = 30

// collectionsCache stores parent relations between collections in order to prevent requesting data from database
// upon each validation (see collectionCacheTime above)
var collectionsCache struct {
	updated time.Time
	data    map[string]string
}

// Collection represents a library collection item instance.
type Collection struct {
	Item
	Entries    CollectionEntryList `json:"entries,omitempty"`
	Link       *Collection         `orm:"type:varchar(36);foreign_key:ID" json:"-"`
	LinkID     string              `orm:"-" json:"link,omitempty"`
	Attributes mapper.Map          `json:"attributes,omitempty"`
	Alias      string              `orm:"type:varchar(128);unique" json:"alias,omitempty"`
	Options    mapper.Map          `json:"options,omitempty"`
	Parent     *Collection         `orm:"type:varchar(36);foreign_key:ID" json:"-"`
	ParentID   string              `orm:"-" json:"parent,omitempty"`
	Template   bool                `orm:"not_null;default:false" json:"template"`
}

// Validate checks whether or not the collection item instance is valid.
func (c Collection) Validate(backend *Backend) error {
	if err := c.Item.Validate(backend); err != nil {
		return err
	}

	// Check for parent identifier
	if c.ParentID == "" {
		return nil
	} else if c.ID == c.ParentID {
		return ErrInvalidParent
	}

	// Get collections associations
	if collectionsCache.updated.Before(time.Now().Add(-1 * collectionCacheTime * time.Second)) {
		tx := backend.db.Begin()
		defer tx.Commit()

		q := tx.Select("id", "parent").Where("parent IS NOT NULL").From(Collection{})

		rows, err := q.Rows()
		if err != nil {
			return err
		}
		defer rows.Close()

		collectionsCache.data = map[string]string{}
		for rows.Next() {
			var collection Collection
			if err := q.Scan(rows, &collection).Error(); err != nil {
				return err
			}
			collectionsCache.data[collection.ID] = collection.ParentID
		}

		collectionsCache.updated = time.Now()
	}

	// Loop through collections for conflicting parenting
	parent := c.ParentID
	for {
		var ok bool

		parent, ok = collectionsCache.data[parent]
		if !ok {
			break
		} else if parent == c.ID {
			return ErrInvalidParent
		}
	}

	// Update cache entry for current collection
	collectionsCache.data[c.ID] = c.ParentID

	return nil
}

// CollectionEntryList represents a list of library collection entries.
type CollectionEntryList []CollectionEntry

// Value marshals the collection entries for compatibility with SQL drivers.
func (l CollectionEntryList) Value() (driver.Value, error) {
	data, err := json.Marshal(l)
	return data, err
}

// Scan unmarshals the collection entries retrieved from SQL drivers.
func (l *CollectionEntryList) Scan(v interface{}) error {
	return json.Unmarshal(v.([]byte), l)
}

// CollectionEntry represents a library collection entry instance.
type CollectionEntry struct {
	ID         string     `json:"id"`
	Attributes mapper.Map `json:"attributes,omitempty"`
	Options    mapper.Map `json:"options,omitempty"`
}

// Expand expands the collection template with attributes passed as parameter.
func (c *Collection) Expand(attrs mapper.Map, backend *Backend) error {
	var err error

	if title, ok := c.Options["title"].(string); ok {
		if c.Options["title"], err = template.Expand(title, attrs); err != nil {
			return err
		}
	}

	c.Attributes.Merge(attrs, true)
	c.Template = false

	// Fecth graph entries titles
	titles := map[string]string{}

	ids := []interface{}{}
	for _, entry := range c.Entries {
		if !sliceutil.Has(ids, entry.ID) {
			ids = append(ids, entry.ID)
		}
	}

	if len(ids) > 0 {
		tx := backend.db.Begin()
		defer tx.Commit()

		graphs := []Graph{}
		tx.Select("id", "options").Where("id IN (?)", ids).Find(&graphs)

		for _, graph := range graphs {
			if title, ok := graph.Options["title"].(string); ok {
				titles[graph.ID] = title
			}
		}
	}

	// Update collection entries with resolved data
	for i := range c.Entries {
		if title, ok := titles[c.Entries[i].ID]; ok {
			c.Entries[i].Attributes.Merge(c.Attributes, true)

			// Set title in options
			if c.Entries[i].Options == nil {
				c.Entries[i].Options = mapper.Map{}
			}

			if c.Entries[i].Options["title"], err = template.Expand(title, c.Entries[i].Attributes); err != nil {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package game

import (
	"context"
	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/verath/archipelago/lib/common"
	"github.com/verath/archipelago/lib/game/model"
	"sync"
	"time"
)

const defaultTickInterval time.Duration = (time.Second / 2)

// The gameLoop is what updates the game model instance that it is
// associated with. The updates are performed in ticks. Each tick
// applies all actions that has been added since the last tick
// sequentially on the model. For each such actions, zero or more
// events are created. Those events are dispatched as the last stage
// of the tick.
//
// Notice that any reads or writes (outside of actions) on the model
// once the gameLoop is started is not safe.
type gameLoop struct {
	logEntry *logrus.Entry
	// Duration between each tick
	tickInterval time.Duration
	// The game instance on which actions are to be applied
	game *model.Game

	gameOverMu sync.Mutex
	// Flag for if the game has completed
	gameOver bool

	eventHandlerMu sync.Mutex
	// A handler to handle events produced when applying actions
	// to the game instance.
	eventHandler eventHandler
	// A WaitGroup for events being handled by the registered event
	// handler.
	handleEventWG sync.WaitGroup

	actionsMu sync.Mutex
	// actions is slice of actions to be applied on the next tick
	actions []model.Action
	// actionsAppliedCh is a channel that is closed once the actions
	// have all been applied (i.e. after the next tick), or once the
	// gameLoop is finished.
	actionsAppliedCh chan struct{}
}

// A handler for game events produced from applying actions.
type eventHandler interface {
	// handleEvent handles an event produced. This method will be called on a
	// separate go routine and must block until the even has been handled, or
	// the context is cancelled.
	handleEvent(ctx context.Context, event model.Event)
}

func newGameLoop(log *logrus.Logger, game *model.Game) (*gameLoop, error) {
	logEntry := common.ModuleLogEntryWithID(log, "gameLoop")

	return &gameLoop{
		logEntry:         logEntry,
		tickInterval:     defaultTickInterval,
		game:             game,
		actions:          make([]model.Action, 0),
		actionsAppliedCh: make(chan struct{}),
	}, nil
}

// SetEventHandler sets the handler for game events.
func (gl *gameLoop) SetEventHandler(eventHandler eventHandler) {
	gl.eventHandlerMu.Lock()
	gl.eventHandler = eventHandler
	gl.eventHandlerMu.Unlock()
}

// ApplyAction adds an action to be processed in the next tick. The method
// blocks until the action has been applied, until it is determined that
// the action will never be applied (i.e. the game loop quit), or the
// context is cancelled.
func (gl *gameLoop) ApplyAction(ctx context.Context, action model.Action) error {
	gl.actionsMu.Lock()
	gl.actions = append(gl.actions, action)
	appliedCh := gl.actionsAppliedCh
	gl.actionsMu.Unlock()
	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-appliedCh:
		return nil
	}
}

// Run runs the game loop. Run blocks until the context is cancelled, an
// error occurs, or the game is finished.
func (gl *gameLoop) Run(ctx context.Context) error {
	gl.logEntry.Debug("Starting")
	defer gl.logEntry.Debug("Stopped")
	err := gl.tickLoop(ctx)
	// Close the actionsAppliedCh, as no more actions will be applied
	gl.actionsMu.Lock()
	close(gl.actionsAppliedCh)
	gl.actionsMu.Unlock()
	// Wait for calls to eventHandler to finish
	gl.handleEventWG.Wait()
	return errors.Wrap(err, "error while running tickLoop")
}

// Sets the game over flag, returning an error if it is already set
func (gl *gameLoop) setGameOver() error {
	gl.gameOverMu.Lock()
	defer gl.gameOverMu.Unlock()
	if gl.gameOver {
		return errors.New("Game is already over")
	}
	gl.gameOver = true
	return nil
}

// Checks if the game over flag has been set
func (gl *gameLoop) isGameOver() bool {
	gl.gameOverMu.Lock()
	defer gl.gameOverMu.Unlock()
	return gl.gameOver
}

// tickLoop performs a "tick" each tickInterval. The tick is what updates the game, by
// applying actions that has been added since the last tick. This method blocks until
// the game is over, or an error occurs.
func (gl *gameLoop) tickLoop(ctx context.Context) error {
	tickInterval := gl.tickInterval
	ticker := time.NewTicker(tickInterval)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			if err := gl.tick(ctx, tickInterval); err != nil {
				return errors.Wrap(err, "Error when performing tick")
			}
		}
		// Check for game over after each tick, and stop the loop if game is over
		if gl.isGameOver() {
			return nil
		}
	}
}

// Perform a tick on the game; Applies all queued actions on the game
// sequentially, making it safe for the applied actions to modify the
// game-state. An additional TickAction is always performed as the
// last actions during a tick.
func (gl *gameLoop) tick(ctx context.Context, delta time.Duration) error {
	// Obtain a slice of the actions added since the last tick.
	acts, actsAppliedCh := gl.swapActions()
	defer close(actsAppliedCh)
	// Add a tick actions as the last action to our local actions slice.
	acts = append(acts, &model.ActionTick{Delta: delta})
	for _, act := range acts {
		if err := gl.applyAction(ctx, act); err != nil {
			return err
		}
		// Check for game over after each action applied, and
		// stop processing actions if the game is over
		if gl.isGameOver() {
			return nil
		}
	}
	return nil
}

// swapActions swaps the current slice of actions with a new empty slice,
// and the current actionsAppliedCh with a new channel. It returns the
// old actions slice and actionsAppliedCh.
func (gl *gameLoop) swapActions() ([]model.Action, chan<- struct{}) {
	gl.actionsMu.Lock()
	defer gl.actionsMu.Unlock()
	acts := gl.actions
	actsAppliedCh := gl.actionsAppliedCh
	// We slowly shrink the initial capacity of the actions here, so
	// that one tick with an abnormal number of actions doesn't result
	// in every new actions slice being allocated that same large size.
	newLen := len(acts) / 2
	gl.actions = make([]model.Action, 0, newLen)
	gl.actionsAppliedCh = make(chan struct{})
	return acts, actsAppliedCh
}

// Applies a single action to the game, and handles each event this action
// produced sequentially.
func (gl *gameLoop) applyAction(ctx context.Context, act model.Action) error {
	evts, err := act.Apply(gl.game)
	if err != nil {
		err = gl.handleActionError(ctx, err)
		return errors.Wrap(err, "Unable to handle action error")
	}
	if err := gl.handleEvents(ctx, evts); err != nil {
		return errors.Wrap(err, "Error handling events")
	}
	return nil
}

// Handles an error returned from applying an action. Non-fatal errors
// are logged and ignored. Fatal action errors results in a game over event
// being sent. All but non-fatal action errors are returned to the caller.
func (gl *gameLoop) handleActionError(ctx context.Context, err error) error {
	switch err := err.(type) {
	case model.ActionError:
		if !err.IsFatal() {
			gl.logEntry.WithError(err).Warn("Ignoring non-fatal ActionError")
			return nil
		}
		gl.logEntry.WithError(err).Debug("handle fatal ActionError")
		// Send a game over event with the opponent as winner
		var winner *model.Player
		if err.Player() != nil {
			winner = gl.game.Opponent(err.Player().ID())
		}
		gl.handleEvent(ctx, model.NewEventGameOver(winner))
	default:
		gl.logEntry.WithError(err).Debug("handle generic error")
	}
	return err
}

// handleEvent handles a single event by forwarding it to the registered
// eventHandler on a new go-routine.
func (gl *gameLoop) handleEvent(ctx context.Context, evt model.Event) {
	gl.eventHandlerMu.Lock()
	handler := gl.eventHandler
	gl.eventHandlerMu.Unlock()
	if handler == nil {
		gl.logEntry.Warn("handleEvent called, but no eventHandler was registered")
		return
	}
	gl.handleEventWG.Add(1)
	go func() {
		defer gl.handleEventWG.Done()
		handler.handleEvent(ctx, evt)
	}()
}

// handleEvents handles each event produced by delegating to the event handler.
// If an event representing the game being over is encountered, then all further
// events are discarded and the gameLoop is set to game over state.
func (gl *gameLoop) handleEvents(ctx context.Context, evts []model.Event) error {
	for _, evt := range evts {
		gl.handleEvent(ctx, evt)
		// Stop processing events if we sent a game over event
		if model.IsGameOverEvent(evt) {
			return gl.setGameOver()
		}
	}
	return nil
}
<commit_msg>Wait for handlers before closing acctionsAppliedCh<commit_after>package game

import (
	"context"
	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/verath/archipelago/lib/common"
	"github.com/verath/archipelago/lib/game/model"
	"sync"
	"time"
)

const defaultTickInterval time.Duration = (time.Second / 2)

// The gameLoop is what updates the game model instance that it is
// associated with. The updates are performed in ticks. Each tick
// applies all actions that has been added since the last tick
// sequentially on the model. For each such actions, zero or more
// events are created. Those events are dispatched as the last stage
// of the tick.
//
// Notice that any reads or writes (outside of actions) on the model
// once the gameLoop is started is not safe.
type gameLoop struct {
	logEntry *logrus.Entry
	// Duration between each tick
	tickInterval time.Duration
	// The game instance on which actions are to be applied
	game *model.Game

	gameOverMu sync.Mutex
	// Flag for if the game has completed
	gameOver bool

	eventHandlerMu sync.Mutex
	// A handler to handle events produced when applying actions
	// to the game instance.
	eventHandler eventHandler
	// A WaitGroup for events being handled by the registered event
	// handler.
	handleEventWG sync.WaitGroup

	actionsMu sync.Mutex
	// actions is slice of actions to be applied on the next tick
	actions []model.Action
	// actionsAppliedCh is a channel that is closed once the actions
	// have all been applied (i.e. after the next tick), or once the
	// gameLoop is finished.
	actionsAppliedCh chan struct{}
}

// A handler for game events produced from applying actions.
type eventHandler interface {
	// handleEvent handles an event produced. This method will be called on a
	// separate go routine and must block until the even has been handled, or
	// the context is cancelled.
	handleEvent(ctx context.Context, event model.Event)
}

func newGameLoop(log *logrus.Logger, game *model.Game) (*gameLoop, error) {
	logEntry := common.ModuleLogEntryWithID(log, "gameLoop")

	return &gameLoop{
		logEntry:         logEntry,
		tickInterval:     defaultTickInterval,
		game:             game,
		actions:          make([]model.Action, 0),
		actionsAppliedCh: make(chan struct{}),
	}, nil
}

// SetEventHandler sets the handler for game events.
func (gl *gameLoop) SetEventHandler(eventHandler eventHandler) {
	gl.eventHandlerMu.Lock()
	gl.eventHandler = eventHandler
	gl.eventHandlerMu.Unlock()
}

// ApplyAction adds an action to be processed in the next tick. The method
// blocks until the action has been applied, until it is determined that
// the action will never be applied (i.e. the game loop quit), or the
// context is cancelled.
func (gl *gameLoop) ApplyAction(ctx context.Context, action model.Action) error {
	gl.actionsMu.Lock()
	gl.actions = append(gl.actions, action)
	appliedCh := gl.actionsAppliedCh
	gl.actionsMu.Unlock()
	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-appliedCh:
		return nil
	}
}

// Run runs the game loop. Run blocks until the context is cancelled, an
// error occurs, or the game is finished.
func (gl *gameLoop) Run(ctx context.Context) error {
	gl.logEntry.Debug("Starting")
	defer gl.logEntry.Debug("Stopped")
	err := gl.tickLoop(ctx)
	// Wait for calls to eventHandler to finish
	gl.handleEventWG.Wait()
	// Close the actionsAppliedCh, as no more actions will be applied
	gl.actionsMu.Lock()
	close(gl.actionsAppliedCh)
	gl.actionsMu.Unlock()
	return errors.Wrap(err, "error while running tickLoop")
}

// Sets the game over flag, returning an error if it is already set
func (gl *gameLoop) setGameOver() error {
	gl.gameOverMu.Lock()
	defer gl.gameOverMu.Unlock()
	if gl.gameOver {
		return errors.New("Game is already over")
	}
	gl.gameOver = true
	return nil
}

// Checks if the game over flag has been set
func (gl *gameLoop) isGameOver() bool {
	gl.gameOverMu.Lock()
	defer gl.gameOverMu.Unlock()
	return gl.gameOver
}

// tickLoop performs a "tick" each tickInterval. The tick is what updates the game, by
// applying actions that has been added since the last tick. This method blocks until
// the game is over, or an error occurs.
func (gl *gameLoop) tickLoop(ctx context.Context) error {
	tickInterval := gl.tickInterval
	ticker := time.NewTicker(tickInterval)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			if err := gl.tick(ctx, tickInterval); err != nil {
				return errors.Wrap(err, "Error when performing tick")
			}
		}
		// Check for game over after each tick, and stop the loop if game is over
		if gl.isGameOver() {
			return nil
		}
	}
}

// Perform a tick on the game; Applies all queued actions on the game
// sequentially, making it safe for the applied actions to modify the
// game-state. An additional TickAction is always performed as the
// last actions during a tick.
func (gl *gameLoop) tick(ctx context.Context, delta time.Duration) error {
	// Obtain a slice of the actions added since the last tick.
	acts, actsAppliedCh := gl.swapActions()
	defer close(actsAppliedCh)
	// Add a tick actions as the last action to our local actions slice.
	acts = append(acts, &model.ActionTick{Delta: delta})
	for _, act := range acts {
		if err := gl.applyAction(ctx, act); err != nil {
			return err
		}
		// Check for game over after each action applied, and
		// stop processing actions if the game is over
		if gl.isGameOver() {
			return nil
		}
	}
	return nil
}

// swapActions swaps the current slice of actions with a new empty slice,
// and the current actionsAppliedCh with a new channel. It returns the
// old actions slice and actionsAppliedCh.
func (gl *gameLoop) swapActions() ([]model.Action, chan<- struct{}) {
	gl.actionsMu.Lock()
	defer gl.actionsMu.Unlock()
	acts := gl.actions
	actsAppliedCh := gl.actionsAppliedCh
	// We slowly shrink the initial capacity of the actions here, so
	// that one tick with an abnormal number of actions doesn't result
	// in every new actions slice being allocated that same large size.
	newLen := len(acts) / 2
	gl.actions = make([]model.Action, 0, newLen)
	gl.actionsAppliedCh = make(chan struct{})
	return acts, actsAppliedCh
}

// Applies a single action to the game, and handles each event this action
// produced sequentially.
func (gl *gameLoop) applyAction(ctx context.Context, act model.Action) error {
	evts, err := act.Apply(gl.game)
	if err != nil {
		err = gl.handleActionError(ctx, err)
		return errors.Wrap(err, "Unable to handle action error")
	}
	if err := gl.handleEvents(ctx, evts); err != nil {
		return errors.Wrap(err, "Error handling events")
	}
	return nil
}

// Handles an error returned from applying an action. Non-fatal errors
// are logged and ignored. Fatal action errors results in a game over event
// being sent. All but non-fatal action errors are returned to the caller.
func (gl *gameLoop) handleActionError(ctx context.Context, err error) error {
	switch err := err.(type) {
	case model.ActionError:
		if !err.IsFatal() {
			gl.logEntry.WithError(err).Warn("Ignoring non-fatal ActionError")
			return nil
		}
		gl.logEntry.WithError(err).Debug("handle fatal ActionError")
		// Send a game over event with the opponent as winner
		var winner *model.Player
		if err.Player() != nil {
			winner = gl.game.Opponent(err.Player().ID())
		}
		gl.handleEvent(ctx, model.NewEventGameOver(winner))
	default:
		gl.logEntry.WithError(err).Debug("handle generic error")
	}
	return err
}

// handleEvent handles a single event by forwarding it to the registered
// eventHandler on a new go-routine.
func (gl *gameLoop) handleEvent(ctx context.Context, evt model.Event) {
	gl.eventHandlerMu.Lock()
	handler := gl.eventHandler
	gl.eventHandlerMu.Unlock()
	if handler == nil {
		gl.logEntry.Warn("handleEvent called, but no eventHandler was registered")
		return
	}
	gl.handleEventWG.Add(1)
	go func() {
		defer gl.handleEventWG.Done()
		handler.handleEvent(ctx, evt)
	}()
}

// handleEvents handles each event produced by delegating to the event handler.
// If an event representing the game being over is encountered, then all further
// events are discarded and the gameLoop is set to game over state.
func (gl *gameLoop) handleEvents(ctx context.Context, evts []model.Event) error {
	for _, evt := range evts {
		gl.handleEvent(ctx, evt)
		// Stop processing events if we sent a game over event
		if model.IsGameOverEvent(evt) {
			return gl.setGameOver()
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package goose

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/lib/pq"
	_ "github.com/ziutek/mymysql/godrv"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"text/template"
	"time"
)

var (
	ErrTableDoesNotExist = errors.New("table does not exist")
	ErrNoPreviousVersion = errors.New("no previous version found")
)

type MigrationRecord struct {
	VersionId int64
	TStamp    time.Time
	IsApplied bool // was this a result of up() or down()
}

type Migration struct {
	Version  int64
	Next     int64  // next version, or -1 if none
	Previous int64  // previous version, -1 if none
	Source   string // path to .go or .sql script
}

type migrationSorter []*Migration

// helpers so we can use pkg sort
func (ms migrationSorter) Len() int           { return len(ms) }
func (ms migrationSorter) Swap(i, j int)      { ms[i], ms[j] = ms[j], ms[i] }
func (ms migrationSorter) Less(i, j int) bool { return ms[i].Version < ms[j].Version }

func newMigration(v int64, src string) *Migration {
	return &Migration{v, -1, -1, src}
}

func RunMigrations(conf *DBConf, migrationsDir string, target int64) (err error) {

	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return err
	}
	defer db.Close()

	current, err := EnsureDBVersion(conf, db)
	if err != nil {
		return err
	}

	migrations, err := CollectMigrations(migrationsDir, current, target)
	if err != nil {
		return err
	}

	if len(migrations) == 0 {
		fmt.Printf("goose: no migrations to run. current version: %d\n", current)
		return nil
	}

	ms := migrationSorter(migrations)
	direction := current < target
	ms.Sort(direction)

	fmt.Printf("goose: migrating db environment '%v', current version: %d, target: %d\n",
		conf.Env, current, target)

	for _, m := range ms {

		switch filepath.Ext(m.Source) {
		case ".go":
			err = runGoMigration(conf, m.Source, m.Version, direction)
		case ".sql":
			err = runSQLMigration(conf, db, m.Source, m.Version, direction)
		}

		if err != nil {
			return errors.New(fmt.Sprintf("FAIL %v, quitting migration", err))
		}

		fmt.Println("OK   ", filepath.Base(m.Source))
	}

	return nil
}

// collect all the valid looking migration scripts in the
// migrations folder, and key them by version
func CollectMigrations(dirpath string, current, target int64) (m []*Migration, err error) {

	// extract the numeric component of each migration,
	// filter out any uninteresting files,
	// and ensure we only have one file per migration version.
	filepath.Walk(dirpath, func(name string, info os.FileInfo, err error) error {

		if v, e := NumericComponent(name); e == nil {

			for _, g := range m {
				if v == g.Version {
					log.Fatalf("more than one file specifies the migration for version %d (%s and %s)",
						v, g.Source, filepath.Join(dirpath, name))
				}
			}

			if versionFilter(v, current, target) {
				m = append(m, newMigration(v, name))
			}
		}

		return nil
	})

	return m, nil
}

func versionFilter(v, current, target int64) bool {

	if target > current {
		return v > current && v <= target
	}

	if target < current {
		return v <= current && v > target
	}

	return false
}

func (ms migrationSorter) Sort(direction bool) {
	sort.Sort(ms)

	// reverse order if needed
	if direction == false {
		for i, j := 0, len(ms)-1; i < j; i, j = i+1, j-1 {
			ms[i], ms[j] = ms[j], ms[i]
		}
	}

	// now that we're sorted in the appropriate direction,
	// populate next and previous for each migration
	for i, m := range ms {
		prev := int64(-1)
		if i > 0 {
			prev = ms[i-1].Version
			ms[i-1].Next = m.Version
		}
		ms[i].Previous = prev
	}
}

// look for migration scripts with names in the form:
//  XXX_descriptivename.ext
// where XXX specifies the version number
// and ext specifies the type of migration
func NumericComponent(name string) (int64, error) {

	base := filepath.Base(name)

	if ext := filepath.Ext(base); ext != ".go" && ext != ".sql" {
		return 0, errors.New("not a recognized migration file type")
	}

	idx := strings.Index(base, "_")
	if idx < 0 {
		return 0, errors.New("no separator found")
	}

	n, e := strconv.ParseInt(base[:idx], 10, 64)
	if e == nil && n <= 0 {
		return 0, errors.New("migration IDs must be greater than zero")
	}

	return n, e
}

// retrieve the current version for this DB.
// Create and initialize the DB version table if it doesn't exist.
func EnsureDBVersion(conf *DBConf, db *sql.DB) (int64, error) {

	rows, err := conf.Driver.Dialect.dbVersionQuery(db)
	if err != nil {
		if err == ErrTableDoesNotExist {
			return 0, createVersionTable(conf, db)
		}
		return 0, err
	}
	defer rows.Close()

	// The most recent record for each migration specifies
	// whether it has been applied or rolled back.
	// The first version we find that has been applied is the current version.

	toSkip := make([]int64, 0)

	for rows.Next() {
		var row MigrationRecord
		if err = rows.Scan(&row.VersionId, &row.IsApplied); err != nil {
			log.Fatal("error scanning rows:", err)
		}

		// have we already marked this version to be skipped?
		skip := false
		for _, v := range toSkip {
			if v == row.VersionId {
				skip = true
				break
			}
		}

		// if version has been applied and not marked to be skipped, we're done
		if row.IsApplied && !skip {
			return row.VersionId, nil
		}

		// version is either not applied, or we've already seen a more
		// recent version of it that was not applied.
		if !skip {
			toSkip = append(toSkip, row.VersionId)
		}
	}

	panic("failure in EnsureDBVersion()")
}

// Create the goose_db_version table
// and insert the initial 0 value into it
func createVersionTable(conf *DBConf, db *sql.DB) error {
	txn, err := db.Begin()
	if err != nil {
		return err
	}

	d := conf.Driver.Dialect

	if _, err := txn.Exec(d.createVersionTableSql()); err != nil {
		txn.Rollback()
		return err
	}

	version := 0
	applied := true
	if _, err := txn.Exec(d.insertVersionSql(), version, applied); err != nil {
		txn.Rollback()
		return err
	}

	return txn.Commit()
}

// wrapper for EnsureDBVersion for callers that don't already have
// their own DB instance
func GetDBVersion(conf *DBConf) (version int64, err error) {

	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return -1, err
	}
	defer db.Close()

	version, err = EnsureDBVersion(conf, db)
	if err != nil {
		return -1, err
	}

	return version, nil
}

func GetPreviousDBVersion(dirpath string, version int64) (previous int64, err error) {

	previous = -1
	sawGivenVersion := false

	filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error {

		if !info.IsDir() {
			if v, e := NumericComponent(name); e == nil {
				if v > previous && v < version {
					previous = v
				}
				if v == version {
					sawGivenVersion = true
				}
			}
		}

		return nil
	})

	if previous == -1 {
		if sawGivenVersion {
			// the given version is (likely) valid but we didn't find
			// anything before it.
			// 'previous' must reflect that no migrations have been applied.
			previous = 0
		} else {
			err = ErrNoPreviousVersion
		}
	}

	return
}

// helper to identify the most recent possible version
// within a folder of migration scripts
func GetMostRecentDBVersion(dirpath string) (version int64, err error) {

	version = -1

	filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error {

		if !info.IsDir() {
			if v, e := NumericComponent(name); e == nil {
				if v > version {
					version = v
				}
			}
		}

		return nil
	})

	if version == -1 {
		err = errors.New("no valid version found")
	}

	return
}

func CreateMigration(name, migrationType, dir string, t time.Time) (path string, err error) {

	if migrationType != "go" && migrationType != "sql" {
		return "", errors.New("migration type must be 'go' or 'sql'")
	}

	timestamp := t.Format("20060102150405")
	filename := fmt.Sprintf("%v_%v.%v", timestamp, name, migrationType)

	fpath := filepath.Join(dir, filename)

	var tmpl *template.Template
	if migrationType == "sql" {
		tmpl = sqlMigrationTemplate
	} else {
		tmpl = goMigrationTemplate
	}

	path, err = writeTemplateToFile(fpath, tmpl, timestamp)

	return
}

var goMigrationTemplate = template.Must(template.New("goose.go-migration").Parse(`
package main

import (
	"database/sql"
)

// Up is executed when this migration is applied
func Up_{{ . }}(txn *sql.Tx) {

}

// Down is executed when this migration is rolled back
func Down_{{ . }}(txn *sql.Tx) {

}
`))

var sqlMigrationTemplate = template.Must(template.New("goose.sql-migration").Parse(`
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied

-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

`))
<commit_msg>added extra checks to  GetMostRecentDBVersion to avoid errors unexpected error during migration<commit_after>package goose

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/lib/pq"
	_ "github.com/ziutek/mymysql/godrv"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"text/template"
	"time"
)

var (
	ErrNotDirectory      = errors.New("path is not a directory")
	ErrTableDoesNotExist = errors.New("table does not exist")
	ErrNoPreviousVersion = errors.New("no previous version found")
)

type MigrationRecord struct {
	VersionId int64
	TStamp    time.Time
	IsApplied bool // was this a result of up() or down()
}

type Migration struct {
	Version  int64
	Next     int64  // next version, or -1 if none
	Previous int64  // previous version, -1 if none
	Source   string // path to .go or .sql script
}

type migrationSorter []*Migration

// helpers so we can use pkg sort
func (ms migrationSorter) Len() int           { return len(ms) }
func (ms migrationSorter) Swap(i, j int)      { ms[i], ms[j] = ms[j], ms[i] }
func (ms migrationSorter) Less(i, j int) bool { return ms[i].Version < ms[j].Version }

func newMigration(v int64, src string) *Migration {
	return &Migration{v, -1, -1, src}
}

func RunMigrations(conf *DBConf, migrationsDir string, target int64) (err error) {

	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return err
	}
	defer db.Close()

	current, err := EnsureDBVersion(conf, db)
	if err != nil {
		return err
	}

	migrations, err := CollectMigrations(migrationsDir, current, target)
	if err != nil {
		return err
	}

	if len(migrations) == 0 {
		fmt.Printf("goose: no migrations to run. current version: %d\n", current)
		return nil
	}

	ms := migrationSorter(migrations)
	direction := current < target
	ms.Sort(direction)

	fmt.Printf("goose: migrating db environment '%v', current version: %d, target: %d\n",
		conf.Env, current, target)

	for _, m := range ms {

		switch filepath.Ext(m.Source) {
		case ".go":
			err = runGoMigration(conf, m.Source, m.Version, direction)
		case ".sql":
			err = runSQLMigration(conf, db, m.Source, m.Version, direction)
		}

		if err != nil {
			return errors.New(fmt.Sprintf("FAIL %v, quitting migration", err))
		}

		fmt.Println("OK   ", filepath.Base(m.Source))
	}

	return nil
}

// collect all the valid looking migration scripts in the
// migrations folder, and key them by version
func CollectMigrations(dirpath string, current, target int64) (m []*Migration, err error) {

	// extract the numeric component of each migration,
	// filter out any uninteresting files,
	// and ensure we only have one file per migration version.
	filepath.Walk(dirpath, func(name string, info os.FileInfo, err error) error {

		if v, e := NumericComponent(name); e == nil {

			for _, g := range m {
				if v == g.Version {
					log.Fatalf("more than one file specifies the migration for version %d (%s and %s)",
						v, g.Source, filepath.Join(dirpath, name))
				}
			}

			if versionFilter(v, current, target) {
				m = append(m, newMigration(v, name))
			}
		}

		return nil
	})

	return m, nil
}

func versionFilter(v, current, target int64) bool {

	if target > current {
		return v > current && v <= target
	}

	if target < current {
		return v <= current && v > target
	}

	return false
}

func (ms migrationSorter) Sort(direction bool) {
	sort.Sort(ms)

	// reverse order if needed
	if direction == false {
		for i, j := 0, len(ms)-1; i < j; i, j = i+1, j-1 {
			ms[i], ms[j] = ms[j], ms[i]
		}
	}

	// now that we're sorted in the appropriate direction,
	// populate next and previous for each migration
	for i, m := range ms {
		prev := int64(-1)
		if i > 0 {
			prev = ms[i-1].Version
			ms[i-1].Next = m.Version
		}
		ms[i].Previous = prev
	}
}

// look for migration scripts with names in the form:
//  XXX_descriptivename.ext
// where XXX specifies the version number
// and ext specifies the type of migration
func NumericComponent(name string) (int64, error) {

	base := filepath.Base(name)

	if ext := filepath.Ext(base); ext != ".go" && ext != ".sql" {
		return 0, errors.New("not a recognized migration file type")
	}

	idx := strings.Index(base, "_")
	if idx < 0 {
		return 0, errors.New("no separator found")
	}

	n, e := strconv.ParseInt(base[:idx], 10, 64)
	if e == nil && n <= 0 {
		return 0, errors.New("migration IDs must be greater than zero")
	}

	return n, e
}

// retrieve the current version for this DB.
// Create and initialize the DB version table if it doesn't exist.
func EnsureDBVersion(conf *DBConf, db *sql.DB) (int64, error) {

	rows, err := conf.Driver.Dialect.dbVersionQuery(db)
	if err != nil {
		if err == ErrTableDoesNotExist {
			return 0, createVersionTable(conf, db)
		}
		return 0, err
	}
	defer rows.Close()

	// The most recent record for each migration specifies
	// whether it has been applied or rolled back.
	// The first version we find that has been applied is the current version.

	toSkip := make([]int64, 0)

	for rows.Next() {
		var row MigrationRecord
		if err = rows.Scan(&row.VersionId, &row.IsApplied); err != nil {
			log.Fatal("error scanning rows:", err)
		}

		// have we already marked this version to be skipped?
		skip := false
		for _, v := range toSkip {
			if v == row.VersionId {
				skip = true
				break
			}
		}

		// if version has been applied and not marked to be skipped, we're done
		if row.IsApplied && !skip {
			return row.VersionId, nil
		}

		// version is either not applied, or we've already seen a more
		// recent version of it that was not applied.
		if !skip {
			toSkip = append(toSkip, row.VersionId)
		}
	}

	panic("failure in EnsureDBVersion()")
}

// Create the goose_db_version table
// and insert the initial 0 value into it
func createVersionTable(conf *DBConf, db *sql.DB) error {
	txn, err := db.Begin()
	if err != nil {
		return err
	}

	d := conf.Driver.Dialect

	if _, err := txn.Exec(d.createVersionTableSql()); err != nil {
		txn.Rollback()
		return err
	}

	version := 0
	applied := true
	if _, err := txn.Exec(d.insertVersionSql(), version, applied); err != nil {
		txn.Rollback()
		return err
	}

	return txn.Commit()
}

// wrapper for EnsureDBVersion for callers that don't already have
// their own DB instance
func GetDBVersion(conf *DBConf) (version int64, err error) {

	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return -1, err
	}
	defer db.Close()

	version, err = EnsureDBVersion(conf, db)
	if err != nil {
		return -1, err
	}

	return version, nil
}

func GetPreviousDBVersion(dirpath string, version int64) (previous int64, err error) {

	previous = -1
	sawGivenVersion := false

	filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error {

		if !info.IsDir() {
			if v, e := NumericComponent(name); e == nil {
				if v > previous && v < version {
					previous = v
				}
				if v == version {
					sawGivenVersion = true
				}
			}
		}

		return nil
	})

	if previous == -1 {
		if sawGivenVersion {
			// the given version is (likely) valid but we didn't find
			// anything before it.
			// 'previous' must reflect that no migrations have been applied.
			previous = 0
		} else {
			err = ErrNoPreviousVersion
		}
	}

	return
}

// helper to identify the most recent possible version
// within a folder of migration scripts
func GetMostRecentDBVersion(dirpath string) (version int64, err error) {

	version = -1

	// check if migrationsDir exists and is a directory
	fi, err := os.Stat(dirpath)
	if err != nil {
		return version, err
	}
	if !fi.Mode().IsDir() {
		return version, ErrNotDirectory
	}

	filepath.Walk(dirpath, func(name string, info os.FileInfo, walkerr error) error {

		if !info.IsDir() {
			if v, e := NumericComponent(name); e == nil {
				if v > version {
					version = v
				}
			}
		}

		return nil
	})

	if version == -1 {
		err = errors.New("no valid version found")
	}

	return
}

func CreateMigration(name, migrationType, dir string, t time.Time) (path string, err error) {

	if migrationType != "go" && migrationType != "sql" {
		return "", errors.New("migration type must be 'go' or 'sql'")
	}

	timestamp := t.Format("20060102150405")
	filename := fmt.Sprintf("%v_%v.%v", timestamp, name, migrationType)

	fpath := filepath.Join(dir, filename)

	var tmpl *template.Template
	if migrationType == "sql" {
		tmpl = sqlMigrationTemplate
	} else {
		tmpl = goMigrationTemplate
	}

	path, err = writeTemplateToFile(fpath, tmpl, timestamp)

	return
}

var goMigrationTemplate = template.Must(template.New("goose.go-migration").Parse(`
package main

import (
	"database/sql"
)

// Up is executed when this migration is applied
func Up_{{ . }}(txn *sql.Tx) {

}

// Down is executed when this migration is rolled back
func Down_{{ . }}(txn *sql.Tx) {

}
`))

var sqlMigrationTemplate = template.Must(template.New("goose.sql-migration").Parse(`
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied

-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back

`))
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"time"

	"github.com/globalsign/certlint/asn1"
	"github.com/globalsign/certlint/certdata"
	"github.com/globalsign/certlint/checks"
	"github.com/globalsign/certlint/errors"

	_ "github.com/globalsign/certlint/checks/certificate/all"
	_ "github.com/globalsign/certlint/checks/extensions/all"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/client"
)

func main() {
	var logServer = flag.String("server", "https://ct.googleapis.com/aviator", "CT log server")
	var start = flag.Int64("start", 0, "CT log start index")
	flag.Parse()

	logClient := client.New(*logServer, nil, nil)
	sth, err := logClient.GetSTH()
	if err != nil {
		fmt.Printf("Failed to get tree head: %s\n", err.Error())
		return
	}

	var startIndex = *start
	for {
		entries, err := logClient.GetEntries(startIndex, startIndex+1000)
		if err != nil {
			fmt.Printf("Failed to get entries: %s\n", err.Error())
			break
		}

		for _, entry := range entries {
			startIndex++
			ctEntry(entry)
		}

		if !(startIndex < int64(sth.TreeSize)) {
			break
		}
	}
}

func ctEntry(entry ct.LogEntry) {
	switch entry.Leaf.TimestampedEntry.EntryType {
	case ct.X509LogEntryType:
		leaf, err := entry.Leaf.X509Certificate()
		if err != nil {
			fmt.Printf("Failed to get leaf certificate in entry %d: %s\n", entry.Index, err.Error())
			return
		}
		check(leaf.Raw)
		return

	case ct.PrecertLogEntryType:
		check(entry.Chain[0])
		return

	default:
		fmt.Printf("Failed to parse unknown entry type: %s", entry.Leaf.TimestampedEntry.EntryType)
		return
	}
}

func check(der []byte) {
	var e = errors.New(nil)

	// Check the ASN1 structure for common formatting errros
	e.Append(asn1.CheckStruct(der))

	// Load and parse certificate
	d, err := certdata.Load(der)
	if err == nil {
		// Don't check expired certificates
		if d.Cert.NotAfter.Before(time.Now()) {
			return
		}

		// Perform all and only the imported checks
		e.Append(checks.Certificate.Check(d))
	}

	// List all errors
	if len(e.List()) > 0 {
		fmt.Printf("'%s' issued by '%s'\n", d.Cert.Subject.CommonName, d.Cert.Issuer.CommonName)
		for _, err := range e.List() {
			fmt.Printf("\t- %s (%s)\n", err.Error(), d.Type)
		}
		fmt.Println()
	}
}
<commit_msg>Using jsonclient.Options as argument to new client<commit_after>package main

import (
	"flag"
	"fmt"
	"time"

	"github.com/globalsign/certlint/asn1"
	"github.com/globalsign/certlint/certdata"
	"github.com/globalsign/certlint/checks"
	"github.com/globalsign/certlint/errors"

	_ "github.com/globalsign/certlint/checks/certificate/all"
	_ "github.com/globalsign/certlint/checks/extensions/all"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/client"
	"github.com/google/certificate-transparency/go/jsonclient"
)

func main() {
	var logServer = flag.String("server", "https://ct.googleapis.com/aviator", "CT log server")
	var start = flag.Int64("start", 0, "CT log start index")
	flag.Parse()

	logClient := client.New(*logServer, nil, jsonclient.Options{})
	sth, err := logClient.GetSTH()
	if err != nil {
		fmt.Printf("Failed to get tree head: %s\n", err.Error())
		return
	}

	var startIndex = *start
	for {
		entries, err := logClient.GetEntries(startIndex, startIndex+1000)
		if err != nil {
			fmt.Printf("Failed to get entries: %s\n", err.Error())
			break
		}

		for _, entry := range entries {
			startIndex++
			ctEntry(entry)
		}

		if !(startIndex < int64(sth.TreeSize)) {
			break
		}
	}
}

func ctEntry(entry ct.LogEntry) {
	switch entry.Leaf.TimestampedEntry.EntryType {
	case ct.X509LogEntryType:
		leaf, err := entry.Leaf.X509Certificate()
		if err != nil {
			fmt.Printf("Failed to get leaf certificate in entry %d: %s\n", entry.Index, err.Error())
			return
		}
		check(leaf.Raw)
		return

	case ct.PrecertLogEntryType:
		check(entry.Chain[0])
		return

	default:
		fmt.Printf("Failed to parse unknown entry type: %s", entry.Leaf.TimestampedEntry.EntryType)
		return
	}
}

func check(der []byte) {
	var e = errors.New(nil)

	// Check the ASN1 structure for common formatting errros
	e.Append(asn1.CheckStruct(der))

	// Load and parse certificate
	d, err := certdata.Load(der)
	if err == nil {
		// Don't check expired certificates
		if d.Cert.NotAfter.Before(time.Now()) {
			return
		}

		// Perform all and only the imported checks
		e.Append(checks.Certificate.Check(d))
	}

	// List all errors
	if len(e.List()) > 0 {
		fmt.Printf("'%s' issued by '%s'\n", d.Cert.Subject.CommonName, d.Cert.Issuer.CommonName)
		for _, err := range e.List() {
			fmt.Printf("\t- %s (%s)\n", err.Error(), d.Type)
		}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package store4_test

import (
	"fmt"
	"log"
	"math/rand"
	"runtime"
	"testing"

	"github.com/jimsmart/store4"
)

// What are we testing here?
//
// For starters: we should be benching time to add n quads when store already has x quads in it.

var storeFind *store4.QuadStore

// func init() {
// 	storeFind = newStoreForFind()
// }

const (
	namespace = "urn:store4:benchmark/padded-iri#"
)

func newStoreWithRandomQuads(count uint64) *store4.QuadStore {
	s := store4.NewQuadStore()
	for s.Size() < count {
		q := randomQuad("")
		s.Add(q[0], q[1], q[2], q[3])
	}
	return s
}

func randomQuad(graph string) [4]string {
	var q [4]string
	// TODO(js) Random quads do not represent the distribution of real-world data!!! :/
	q[0] = randomIRI()
	q[1] = randomIRI()
	q[2] = randomIRI()
	q[3] = graph
	return q
}

func randomIRI() string {
	return namespace + fmt.Sprintf("%16x", rand.Int63())
}

func randomQuadn(n int, graph string) [4]string {
	var q [4]string
	// TODO(js) Random quads do not represent the distribution of real-world data!!! :/
	q[0] = randomIRIn(n)
	q[1] = randomIRIn(n)
	q[2] = randomIRIn(n)
	q[3] = graph
	return q
}

func randomIRIn(n int) string {
	return namespace + fmt.Sprintf("%16x", rand.Int63n(int64(n)))
}

func benchmarkAddRemoveRandomsTo(count uint64, b *testing.B) {
	s := newStoreWithRandomQuads(count)
	q := randomQuad("")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		s.Add(q[0], q[1], q[2], q[3])
		s.Remove(q[0], q[1], q[2], q[3])
	}
}

func BenchmarkAddRemoveRandomsToEmpty(b *testing.B)       { benchmarkAddRemoveRandomsTo(0, b) }
func BenchmarkAddRemoveRandomsTo10kRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(10000, b) }
func BenchmarkAddRemoveRandomsTo100kRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(100000, b) }
func BenchmarkAddRemoveRandomsTo500kRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(500000, b) }
func BenchmarkAddRemoveRandomsTo1mRandoms(b *testing.B)   { benchmarkAddRemoveRandomsTo(1000000, b) }

// // func BenchmarkAddRemoveRandomsTo10mRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(10000000, b) }
// // func BenchmarkAddRemoveRandomsTo50mRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(50000000, b) }
// // func BenchmarkAddRemoveRandomsTo100mRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(100000000, b) }

func logMemStatsDifference(before, after *runtime.MemStats) {
	out := "Diff "
	out = out + fmtMemStatMiB("Alloc", after.Alloc-before.Alloc)
	out = out + fmtMemStatMiB("TotalAlloc", after.TotalAlloc-before.TotalAlloc)
	out = out + fmtMemStatMiB("Sys", after.Sys-before.Sys)
	log.Println(out)
}

func fmtMemStatMiB(name string, n uint64) string {
	return fmt.Sprintf("- %s: %.2fMiB ", name, float64(n)/1024/1024)
}

func readMemStats() *runtime.MemStats {
	m := &runtime.MemStats{}
	runtime.ReadMemStats(m)
	return m
}

func createStoreForFind(dim int) *store4.QuadStore {
	if storeFind != nil {
		return storeFind
	}

	before := readMemStats()

	storeFind = newStoreWithDim(dim)
	log.Println("QuadStore.Size", storeFind.Size())

	after := readMemStats()
	logMemStatsDifference(before, after)

	return storeFind
}

func newStoreWithDim(dim int) *store4.QuadStore {
	// dimSquared := dim * dim
	// dimCubed := dimSquared * dim
	// dimQuads := dimCubed * dim
	s := store4.NewQuadStore()
	for i := 0; i < dim; i++ {
		for j := 0; j < dim; j++ {
			for k := 0; k < dim; k++ {
				s.Add(iri(i), iri(j), iri(k), "")
			}
		}
	}
	return s
}

func iri(i int) string {
	return namespace + fmt.Sprintf("%16x", i)
}

func BenchmarkSomeWith_NoWildcards(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], q[1], q[2], q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], q[1], "*", q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardPO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], "*", "*", q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardSPO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith("*", "*", "*", "", fn) {
			panic("bad SomeWith")
		}
	}
}
<commit_msg>Cleanup<commit_after>package store4_test

import (
	"fmt"
	"log"
	"math/rand"
	"runtime"
	"testing"

	"github.com/jimsmart/store4"
)

// $ go test -run=XXX -bench=.

// What are we timing here? I don't think much of this has any meaning.

var storeFind *store4.QuadStore
var lastDim int

// func init() {
// 	storeFind = newStoreForFind()
// }

const (
	namespace = "urn:store4:benchmark/padded-iri#"
)

func newStoreWithRandomQuads(count uint64) *store4.QuadStore {
	s := store4.NewQuadStore()
	for s.Size() < count {
		q := randomQuad("")
		s.Add(q[0], q[1], q[2], q[3])
	}
	return s
}

func randomQuad(graph string) [4]string {
	var q [4]string
	// TODO(js) Random quads do not represent the distribution of real-world data!!! :/
	q[0] = randomIRI()
	q[1] = randomIRI()
	q[2] = randomIRI()
	q[3] = graph
	return q
}

func randomIRI() string {
	return namespace + fmt.Sprintf("%16x", rand.Int63())
}

func randomQuadn(n int, graph string) [4]string {
	var q [4]string
	// TODO(js) Random quads do not represent the distribution of real-world data!!! :/
	q[0] = randomIRIn(n)
	q[1] = randomIRIn(n)
	q[2] = randomIRIn(n)
	q[3] = graph
	return q
}

func randomIRIn(n int) string {
	return namespace + fmt.Sprintf("%16x", rand.Int63n(int64(n)))
}

func benchmarkAddRemoveRandomsTo(count uint64, b *testing.B) {
	s := newStoreWithRandomQuads(count)
	q := randomQuad("")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		s.Add(q[0], q[1], q[2], q[3])
		s.Remove(q[0], q[1], q[2], q[3])
	}
}

func BenchmarkAddRemoveRandomsToEmpty(b *testing.B)       { benchmarkAddRemoveRandomsTo(0, b) }
func BenchmarkAddRemoveRandomsTo10kRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(10000, b) }
func BenchmarkAddRemoveRandomsTo100kRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(100000, b) }
func BenchmarkAddRemoveRandomsTo500kRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(500000, b) }
func BenchmarkAddRemoveRandomsTo1mRandoms(b *testing.B)   { benchmarkAddRemoveRandomsTo(1000000, b) }

// // func BenchmarkAddRemoveRandomsTo10mRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(10000000, b) }
// // func BenchmarkAddRemoveRandomsTo50mRandoms(b *testing.B)  { benchmarkAddRemoveRandomsTo(50000000, b) }
// // func BenchmarkAddRemoveRandomsTo100mRandoms(b *testing.B) { benchmarkAddRemoveRandomsTo(100000000, b) }

func logMemStatsDifference(before, after *runtime.MemStats) {
	out := "Diff "
	out = out + fmtMemStatMiB("Alloc", after.Alloc-before.Alloc)
	out = out + fmtMemStatMiB("TotalAlloc", after.TotalAlloc-before.TotalAlloc)
	out = out + fmtMemStatMiB("Sys", after.Sys-before.Sys)
	log.Println(out)
}

func fmtMemStatMiB(name string, n uint64) string {
	return fmt.Sprintf("- %s: %.2fMiB ", name, float64(n)/1024/1024)
}

func readMemStats() *runtime.MemStats {
	m := &runtime.MemStats{}
	runtime.ReadMemStats(m)
	return m
}

func createStoreForFind(dim int) *store4.QuadStore {
	if storeFind != nil && lastDim == dim {
		return storeFind
	}

	before := readMemStats()

	storeFind = newStoreWithDim(dim)
	log.Println("QuadStore.Size", storeFind.Size())
	lastDim = dim

	after := readMemStats()
	logMemStatsDifference(before, after)

	return storeFind
}

func newStoreWithDim(dim int) *store4.QuadStore {
	// dimSquared := dim * dim
	// dimCubed := dimSquared * dim
	// dimQuads := dimCubed * dim
	s := store4.NewQuadStore()
	for i := 0; i < dim; i++ {
		for j := 0; j < dim; j++ {
			for k := 0; k < dim; k++ {
				s.Add(iri(i), iri(j), iri(k), "")
			}
		}
	}
	return s
}

func iri(i int) string {
	return namespace + fmt.Sprintf("%16x", i)
}

func BenchmarkSomeWith_NoWildcards(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], q[1], q[2], q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], q[1], "*", q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardPO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	q := randomQuadn(dim, "")
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith(q[0], "*", "*", q[3], fn) {
			panic("bad SomeWith")
		}
	}
}

func BenchmarkSomeWith_WildcardSPO(b *testing.B) {

	fn := func(s, p, o, g string) bool {
		return true
	}

	dim := 256
	s := createStoreForFind(dim)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		if !s.SomeWith("*", "*", "*", "", fn) {
			panic("bad SomeWith")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"time"

	"github.com/globalsign/certlint/asn1"
	"github.com/globalsign/certlint/certdata"
	"github.com/globalsign/certlint/checks"
	"github.com/globalsign/certlint/errors"

	_ "github.com/globalsign/certlint/checks/certificate/all"
	_ "github.com/globalsign/certlint/checks/extensions/all"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/client"
)

func main() {
	var logServer = flag.String("server", "https://ct.googleapis.com/aviator", "CT log server")
	var start = flag.Int64("start", 0, "CT log start index")
	flag.Parse()

	logClient := client.New(*logServer, nil)
	sth, err := logClient.GetSTH()
	if err != nil {
		fmt.Printf("Failed to get tree head: %s\n", err.Error())
		return
	}

	var startIndex = *start
	for {
		entries, err := logClient.GetEntries(startIndex, startIndex+1000)
		if err != nil {
			fmt.Printf("Failed to get entries: %s\n", err.Error())
			break
		}

		for _, entry := range entries {
			startIndex++
			ctEntry(entry)
		}

		if !(startIndex < int64(sth.TreeSize)) {
			break
		}
	}
}

func ctEntry(entry ct.LogEntry) {
	switch entry.Leaf.TimestampedEntry.EntryType {
	case ct.X509LogEntryType:
		leaf, err := entry.Leaf.X509Certificate()
		if err != nil {
			fmt.Printf("Failed to get leaf certificate in entry %d: %s\n", entry.Index, err.Error())
			return
		}
		check(leaf.Raw)
		return

	case ct.PrecertLogEntryType:
		check(entry.Chain[0])
		return

	default:
		fmt.Printf("Failed to parse unknown entry type: %s", entry.Leaf.TimestampedEntry.EntryType)
		return
	}
}

func check(der []byte) {
	var e = errors.New(nil)

	// Check the ASN1 structure for common formatting errros
	e.Append(asn1.CheckStruct(der))

	// Load and parse certificate
	d, err := certdata.Load(der)
	if err == nil {
		// Don't check expired certificates
		if d.Cert.NotAfter.Before(time.Now()) {
			return
		}

		// Perform all and only the imported checks
		e.Append(checks.Certificate.Check(d))
	}

	// List all errors
	if len(e.List()) > 0 {
		fmt.Printf("'%s' issued by '%s'\n", d.Cert.Subject.CommonName, d.Cert.Issuer.CommonName)
		for _, err := range e.List() {
			fmt.Printf("\t- %s (%s)\n", err.Error(), d.Type)
		}
		fmt.Println()
	}
}
<commit_msg>Updated ct.New with argument required by upstream<commit_after>package main

import (
	"flag"
	"fmt"
	"time"

	"github.com/globalsign/certlint/asn1"
	"github.com/globalsign/certlint/certdata"
	"github.com/globalsign/certlint/checks"
	"github.com/globalsign/certlint/errors"

	_ "github.com/globalsign/certlint/checks/certificate/all"
	_ "github.com/globalsign/certlint/checks/extensions/all"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/client"
)

func main() {
	var logServer = flag.String("server", "https://ct.googleapis.com/aviator", "CT log server")
	var start = flag.Int64("start", 0, "CT log start index")
	flag.Parse()

	logClient := client.New(*logServer, nil, nil)
	sth, err := logClient.GetSTH()
	if err != nil {
		fmt.Printf("Failed to get tree head: %s\n", err.Error())
		return
	}

	var startIndex = *start
	for {
		entries, err := logClient.GetEntries(startIndex, startIndex+1000)
		if err != nil {
			fmt.Printf("Failed to get entries: %s\n", err.Error())
			break
		}

		for _, entry := range entries {
			startIndex++
			ctEntry(entry)
		}

		if !(startIndex < int64(sth.TreeSize)) {
			break
		}
	}
}

func ctEntry(entry ct.LogEntry) {
	switch entry.Leaf.TimestampedEntry.EntryType {
	case ct.X509LogEntryType:
		leaf, err := entry.Leaf.X509Certificate()
		if err != nil {
			fmt.Printf("Failed to get leaf certificate in entry %d: %s\n", entry.Index, err.Error())
			return
		}
		check(leaf.Raw)
		return

	case ct.PrecertLogEntryType:
		check(entry.Chain[0])
		return

	default:
		fmt.Printf("Failed to parse unknown entry type: %s", entry.Leaf.TimestampedEntry.EntryType)
		return
	}
}

func check(der []byte) {
	var e = errors.New(nil)

	// Check the ASN1 structure for common formatting errros
	e.Append(asn1.CheckStruct(der))

	// Load and parse certificate
	d, err := certdata.Load(der)
	if err == nil {
		// Don't check expired certificates
		if d.Cert.NotAfter.Before(time.Now()) {
			return
		}

		// Perform all and only the imported checks
		e.Append(checks.Certificate.Check(d))
	}

	// List all errors
	if len(e.List()) > 0 {
		fmt.Printf("'%s' issued by '%s'\n", d.Cert.Subject.CommonName, d.Cert.Issuer.CommonName)
		for _, err := range e.List() {
			fmt.Printf("\t- %s (%s)\n", err.Error(), d.Type)
		}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package convalidur

import (
	"errors"
	"reflect"
	"regexp"
	"strconv"
	"time"
)

var (
	ErrRequired   = errors.New("is required")
	ErrNotMatched = errors.New("not matched")
	ErrNotEqual   = errors.New("is not a equal to value passed")
	ErrOutRange   = errors.New("is out of range")
	ErrIn         = errors.New("is not in the values passed")
	ErrLen        = errors.New("is more length than value passed")
	ErrDate       = errors.New("is not a valid datetime")

	ErrUnsupported  = errors.New("unsopported type")
	ErrBadParameter = errors.New("bad parameter")
)

const (
	PATTERN_EMAIL = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
	PATTERN_URL   = `^((ftp|http|https):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|((www\.)?)?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?)|localhost)(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`
)

type Validator struct {
	Errors *map[string][]string
}

func New(errors *map[string][]string) *Validator {
	return &Validator{errors}
}

type Str struct {
	value  string
	field  string
	errors *map[string][]string
}

func (v *Validator) Str(value, field string) *Str {
	return &Str{value, field, v.Errors}
}

func (str *Str) Required() *Str {
	if str.value == "" {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrRequired.Error())
	}
	return str
}

func (str *Str) Equal(eq string) *Str {
	if str.value != "" && str.value != eq {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrNotEqual.Error())
	}
	return str
}

func (str *Str) Len(int int) *Str {
	if str.value != "" && len(str.value) != int {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrLen.Error())
	}
	return str
}

func (str *Str) Range(min, max int) *Str {
	len := len(str.value)
	if str.value != "" && len < min || len > max {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrOutRange.Error())
	}
	return str
}

func (str *Str) In(values ...string) *Str {
	if str.value == "" {
		return str
	}
	for _, value := range values {
		if str.value == value {
			return str
		}
	}
	(*str.errors)[str.field] = append((*str.errors)[str.field], ErrIn.Error())
	return str
}

func (str *Str) Date(layout string) *Str {
	if str.value == "" {
		return str
	}
	if _, err := time.Parse(layout, str.value); err != nil {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrDate.Error())
	}
	return str
}

func (str *Str) Email() *Str {
	if str.value == "" {
		return str
	}
	return str.RegExp(PATTERN_EMAIL)
}

func (str *Str) URL() *Str {
	if str.value == "" {
		return str
	}
	return str.RegExp(PATTERN_URL)
}

func (str *Str) RegExp(pattern string) *Str {
	if str.value == "" {
		return str
	}
	if matched, err := regexp.MatchString(pattern, str.value); err != nil {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrBadParameter.Error())
	} else if !matched {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrNotMatched.Error())
	}
	return str
}

type Int struct {
	value  int
	field  string
	errors *map[string][]string
}

func (v *Validator) Int(value int, field string) *Int {
	return &Int{value, field, v.Errors}
}

func (int *Int) Required() *Int {
	if int.value == 0 {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrRequired.Error())
	}
	return int
}

func (int *Int) Len(num int) *Int {
	if int.value != 0 && len(strconv.Itoa(int.value)) != num {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrLen.Error())
	}
	return int
}

func (int *Int) Equal(eq int) *Int {
	if int.value != 0 && int.value != eq {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrNotEqual.Error())
	}
	return int
}

func (int *Int) Range(min, max int) *Int {
	if int.value != 0 && (int.value < min || int.value > max) {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrOutRange.Error())
	}
	return int
}

type Slice struct {
	raw    interface{}
	field  string
	errors *map[string][]string

	value reflect.Value
}

func (v *Validator) Slice(value interface{}, field string) *Slice {
	return &Slice{raw: value, field: field, errors: v.Errors}
}

func (sl *Slice) Required() *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		if sl.value.Len() == 0 {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrRequired.Error())
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) Range(min, max int) *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		len := sl.value.Len()
		if len < min || len > max {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrOutRange.Error())
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) In(values interface{}) *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		value := sl.value
		len := value.Len()
		for i := 0; i < len; i++ {
			sl.value = value.Index(i)
			sl.in(values)
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) in(n interface{}) *Slice {
	found := false

	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		value := sl.value
		len := value.Len()
		for i := 0; i < len; i++ {
			sl.value = value.Index(i)
			sl.in(n)
		}
	case reflect.Map:
		value := sl.value
		keys := sl.value.MapKeys()
		for _, key := range keys {
			sl.value = value.MapIndex(key)
			sl.in(n)
		}
	case reflect.String:
		values := reflect.ValueOf(n)
		switch values.Kind() {
		case reflect.Slice, reflect.Array:
			for j := 0; j < values.Len(); j++ {
				value := values.Index(j)
				str := ""
				switch value.Kind() {
				case reflect.String:
					str = value.String()
				case reflect.Interface:
					if m, ok := value.Interface().(string); ok {
						str = m
					} else if value.Kind() == reflect.String {
						str = value.String()
					}
				default:
					(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
				}
				if sl.value.String() == str {
					found = true
				}
			}
		default:
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
		}
		if !found {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrIn.Error())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		values := reflect.ValueOf(n)
		switch values.Kind() {
		case reflect.Slice, reflect.Array:
			for j := 0; j < values.Len(); j++ {
				value := values.Index(j)
				num := 0
				switch value.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
					num = int(value.Int())
				case reflect.Interface:
					switch p := value.Interface().(type) {
					case int:
						num = int(p)
					case int8:
						num = int(p)
					case int16:
						num = int(p)
					case int32:
						num = int(p)
					case int64:
						num = int(p)
					default:
						switch value.Kind() {
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
							num = int(value.Int())
						default:
							(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
						}
					}
				default:
					(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
				}
				if int(sl.value.Int()) == num {
					found = true
				}
			}
		default:
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
		}
		if !found {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrIn.Error())
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		// TODO
	case reflect.Float32, reflect.Float64:
		// TODO
	case reflect.Bool:
		// TODO
	case reflect.Interface:
		// TODO
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}

	return sl
}

type Map struct {
	raw    interface{}
	field  string
	errors *map[string][]string

	value reflect.Value
}

func (v *Validator) Map(value interface{}, field string) *Map {
	return &Map{raw: value, field: field, errors: v.Errors}
}

func (ma *Map) Required() *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	switch ma.value.Kind() {
	case reflect.Map:
		if ma.value.Len() == 0 {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrRequired.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) Range(min, max int) *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	if ma.value.Len() == 0 {
		return ma
	}
	switch ma.value.Kind() {
	case reflect.Map:
		len := ma.value.Len()
		if len < min || len > max {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrOutRange.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) In(values interface{}) *Map {
	return ma
}

func (ma *Map) Date(layout string) *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	if ma.value.Len() == 0 {
		return ma
	}
	switch ma.value.Kind() {
	case reflect.Map:
		for _, key := range ma.value.MapKeys() {
			ma.value = ma.value.MapIndex(key)
			ma.date(layout)
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) date(layout string) *Map {
	switch ma.value.Kind() {
	case reflect.Slice, reflect.Array:
		len := ma.value.Len()
		for i := 0; i < len; i++ {
			ma.value = ma.value.Index(i)
			ma.date(layout)
		}
	case reflect.String:
		if _, err := time.Parse(layout, ma.value.String()); err != nil {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrDate.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}
<commit_msg>clean some code<commit_after>package convalidur

import (
	"errors"
	"reflect"
	"regexp"
	"strconv"
	"time"
)

var (
	ErrRequired   = errors.New("is required")
	ErrNotMatched = errors.New("not matched")
	ErrNotEqual   = errors.New("is not a equal to value passed")
	ErrOutRange   = errors.New("is out of range")
	ErrIn         = errors.New("is not in the values passed")
	ErrLen        = errors.New("is more length than value passed")
	ErrDate       = errors.New("is not a valid datetime")

	ErrUnsupported  = errors.New("unsopported type")
	ErrBadParameter = errors.New("bad parameter")
)

const (
	PATTERN_EMAIL = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
	PATTERN_URL   = `^((ftp|http|https):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|((www\.)?)?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?)|localhost)(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`
)

type Validator struct {
	Errors *map[string][]string
}

func New(errors *map[string][]string) *Validator {
	return &Validator{errors}
}

type Str struct {
	value  string
	field  string
	errors *map[string][]string
}

func (v *Validator) Str(value, field string) *Str {
	return &Str{value, field, v.Errors}
}

func (str *Str) Required() *Str {
	if str.value == "" {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrRequired.Error())
	}
	return str
}

func (str *Str) Equal(eq string) *Str {
	if str.value != "" && str.value != eq {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrNotEqual.Error())
	}
	return str
}

func (str *Str) Len(int int) *Str {
	if str.value != "" && len(str.value) != int {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrLen.Error())
	}
	return str
}

func (str *Str) Range(min, max int) *Str {
	len := len(str.value)
	if str.value != "" && len < min || len > max {
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrOutRange.Error())
	}
	return str
}

func (str *Str) In(values ...string) *Str {
	if str.value != "" {
		for _, value := range values {
			if str.value == value {
				return str
			}
		}
		(*str.errors)[str.field] = append((*str.errors)[str.field], ErrIn.Error())
	}
	return str
}

func (str *Str) Date(layout string) *Str {
	if str.value != "" {
		if _, err := time.Parse(layout, str.value); err != nil {
			(*str.errors)[str.field] = append((*str.errors)[str.field], ErrDate.Error())
		}
	}
	return str
}

func (str *Str) Email() *Str {
	if str.value == "" {
		return str
	}
	return str.RegExp(PATTERN_EMAIL)
}

func (str *Str) URL() *Str {
	if str.value != "" {
		return str.RegExp(PATTERN_URL)
	}
	return str
}

func (str *Str) RegExp(pattern string) *Str {
	if str.value != "" {
		if matched, err := regexp.MatchString(pattern, str.value); err != nil {
			(*str.errors)[str.field] = append((*str.errors)[str.field], ErrBadParameter.Error())
		} else if !matched {
			(*str.errors)[str.field] = append((*str.errors)[str.field], ErrNotMatched.Error())
		}
	}
	return str
}

type Int struct {
	value  int
	field  string
	errors *map[string][]string
}

func (v *Validator) Int(value int, field string) *Int {
	return &Int{value, field, v.Errors}
}

func (int *Int) Required() *Int {
	if int.value == 0 {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrRequired.Error())
	}
	return int
}

func (int *Int) Len(num int) *Int {
	if int.value != 0 && len(strconv.Itoa(int.value)) != num {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrLen.Error())
	}
	return int
}

func (int *Int) Equal(eq int) *Int {
	if int.value != 0 && int.value != eq {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrNotEqual.Error())
	}
	return int
}

func (int *Int) Range(min, max int) *Int {
	if int.value != 0 && (int.value < min || int.value > max) {
		(*int.errors)[int.field] = append((*int.errors)[int.field], ErrOutRange.Error())
	}
	return int
}

type Slice struct {
	raw    interface{}
	field  string
	errors *map[string][]string

	value reflect.Value
}

func (v *Validator) Slice(value interface{}, field string) *Slice {
	return &Slice{raw: value, field: field, errors: v.Errors}
}

func (sl *Slice) Required() *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		if sl.value.Len() == 0 {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrRequired.Error())
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) Range(min, max int) *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		len := sl.value.Len()
		if len < min || len > max {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrOutRange.Error())
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) In(values interface{}) *Slice {
	sl.value = reflect.ValueOf(sl.raw)
	if sl.value.Kind() == reflect.Ptr {
		sl.value = sl.value.Elem()
	}
	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		value := sl.value
		len := value.Len()
		for i := 0; i < len; i++ {
			sl.value = value.Index(i)
			sl.in(values)
		}
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}
	return sl
}

func (sl *Slice) in(n interface{}) *Slice {
	found := false

	switch sl.value.Kind() {
	case reflect.Slice, reflect.Array:
		value := sl.value
		len := value.Len()
		for i := 0; i < len; i++ {
			sl.value = value.Index(i)
			sl.in(n)
		}
	case reflect.Map:
		value := sl.value
		keys := sl.value.MapKeys()
		for _, key := range keys {
			sl.value = value.MapIndex(key)
			sl.in(n)
		}
	case reflect.String:
		values := reflect.ValueOf(n)
		switch values.Kind() {
		case reflect.Slice, reflect.Array:
			for j := 0; j < values.Len(); j++ {
				value := values.Index(j)
				str := ""
				switch value.Kind() {
				case reflect.String:
					str = value.String()
				case reflect.Interface:
					if m, ok := value.Interface().(string); ok {
						str = m
					} else if value.Kind() == reflect.String {
						str = value.String()
					}
				default:
					(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
				}
				if sl.value.String() == str {
					found = true
				}
			}
		default:
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
		}
		if !found {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrIn.Error())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		values := reflect.ValueOf(n)
		switch values.Kind() {
		case reflect.Slice, reflect.Array:
			for j := 0; j < values.Len(); j++ {
				value := values.Index(j)
				num := 0
				switch value.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
					num = int(value.Int())
				case reflect.Interface:
					switch p := value.Interface().(type) {
					case int:
						num = int(p)
					case int8:
						num = int(p)
					case int16:
						num = int(p)
					case int32:
						num = int(p)
					case int64:
						num = int(p)
					default:
						switch value.Kind() {
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
							num = int(value.Int())
						default:
							(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
						}
					}
				default:
					(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
				}
				if int(sl.value.Int()) == num {
					found = true
				}
			}
		default:
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrBadParameter.Error())
		}
		if !found {
			(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrIn.Error())
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		// TODO
	case reflect.Float32, reflect.Float64:
		// TODO
	case reflect.Bool:
		// TODO
	case reflect.Interface:
		// TODO
	default:
		(*sl.errors)[sl.field] = append((*sl.errors)[sl.field], ErrUnsupported.Error())
	}

	return sl
}

type Map struct {
	raw    interface{}
	field  string
	errors *map[string][]string

	value reflect.Value
}

func (v *Validator) Map(value interface{}, field string) *Map {
	return &Map{raw: value, field: field, errors: v.Errors}
}

func (ma *Map) Required() *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	switch ma.value.Kind() {
	case reflect.Map:
		if ma.value.Len() == 0 {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrRequired.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) Range(min, max int) *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	if ma.value.Len() == 0 {
		return ma
	}
	switch ma.value.Kind() {
	case reflect.Map:
		len := ma.value.Len()
		if len < min || len > max {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrOutRange.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) In(values interface{}) *Map {
	return ma
}

func (ma *Map) Date(layout string) *Map {
	ma.value = reflect.ValueOf(ma.raw)
	if ma.value.Kind() == reflect.Ptr {
		ma.value = ma.value.Elem()
	}
	if ma.value.Len() == 0 {
		return ma
	}
	switch ma.value.Kind() {
	case reflect.Map:
		for _, key := range ma.value.MapKeys() {
			ma.value = ma.value.MapIndex(key)
			ma.date(layout)
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}

func (ma *Map) date(layout string) *Map {
	switch ma.value.Kind() {
	case reflect.Slice, reflect.Array:
		len := ma.value.Len()
		for i := 0; i < len; i++ {
			ma.value = ma.value.Index(i)
			ma.date(layout)
		}
	case reflect.String:
		if _, err := time.Parse(layout, ma.value.String()); err != nil {
			(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrDate.Error())
		}
	default:
		(*ma.errors)[ma.field] = append((*ma.errors)[ma.field], ErrUnsupported.Error())
	}
	return ma
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"os"
)

func main() {

	var (
		ClientOV *ov.OVClient
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		600,
		"*")

	// Get all tasks present
	fmt.Println("\nGetting all tasks present: \n")
	task_list, err := ovc.GetTasks("", "", "", "")
	if err != nil {
		fmt.Println("Error getting the storage volumes ", err)
	}
	for i := 0; i < len(task_list.Members); i++ {
		fmt.Println(task_list.Members[i].Name)
	}
}
<commit_msg>tested all api versions  500-800<commit_after>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"os"
)

func main() {

	var (
		ClientOV *ov.OVClient
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		800,
		"*")

	// Get all tasks present
	fmt.Println("\nGetting all tasks present: \n")
	task_list, err := ovc.GetTasks("", "", "", "")
	if err != nil {
		fmt.Println("Error getting the storage volumes ", err)
	}
	for i := 0; i < len(task_list.Members); i++ {
		fmt.Println(task_list.Members[i].Name)
	}
}
<|endoftext|>