<commit_before>package puddle

import (
	"context"
	"errors"
	"sync"
	"time"
)

const (
	resourceStatusConstructing = 0
	resourceStatusIdle         = iota
	resourceStatusAcquired     = iota
	resourceStatusHijacked     = iota
)

// ErrClosedPool occurs on an attempt to acquire a connection from a closed pool
// or a pool that is closed while the acquire is waiting.
var ErrClosedPool = errors.New("closed pool")

// Constructor is a function called by the pool to construct a resource.
type Constructor func(ctx context.Context) (res interface{}, err error)

// Destructor is a function called by the pool to destroy a resource.
type Destructor func(res interface{})

// Resource is the resource handle returned by acquiring from the pool.
type Resource struct {
	value        interface{}
	pool         *Pool
	creationTime time.Time
	lastUsedNano int64
	status       byte
}

// Value returns the resource value.
func (res *Resource) Value() interface{} {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}
	return res.value
}

// Release returns the resource to the pool. res must not be subsequently used.
func (res *Resource) Release() {
	if res.status != resourceStatusAcquired {
		panic("tried to release resource that is not acquired")
	}
	res.pool.releaseAcquiredResource(res, nanotime())
}

// ReleaseUnused returns the resource to the pool without updating when it was last used used. i.e. LastUsedNanotime
// will not change. res must not be subsequently used.
func (res *Resource) ReleaseUnused() {
	if res.status != resourceStatusAcquired {
		panic("tried to release resource that is not acquired")
	}
	res.pool.releaseAcquiredResource(res, res.lastUsedNano)
}

// Destroy returns the resource to the pool for destruction. res must not be
// subsequently used.
func (res *Resource) Destroy() {
	if res.status != resourceStatusAcquired {
		panic("tried to destroy resource that is not acquired")
	}
	go res.pool.destroyAcquiredResource(res)
}

// Hijack assumes ownership of the resource from the pool. Caller is responsible
// for cleanup of resource value.
func (res *Resource) Hijack() {
	if res.status != resourceStatusAcquired {
		panic("tried to hijack resource that is not acquired")
	}
	res.pool.hijackAcquiredResource(res)
}

// CreationTime returns when the resource was created by the pool.
func (res *Resource) CreationTime() time.Time {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}
	return res.creationTime
}

// LastUsedNanotime returns when Release was last called on the resource measured in nanoseconds from an arbitrary time
// (a monotonic time). Returns creation time if Release has never been called. This is only useful to compare with
// other calls to LastUsedNanotime. In almost all cases, IdleDuration should be used instead.
func (res *Resource) LastUsedNanotime() int64 {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}

	return res.lastUsedNano
}

// IdleDuration returns the duration since Release was last called on the resource. This is equivalent to subtracting
// LastUsedNanotime to the current nanotime.
func (res *Resource) IdleDuration() time.Duration {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}

	return time.Duration(nanotime() - res.lastUsedNano)
}

// Pool is a concurrency-safe resource pool.
type Pool struct {
	cond       *sync.Cond
	destructWG *sync.WaitGroup

	allResources  []*Resource
	idleResources []*Resource

	constructor Constructor
	destructor  Destructor
	maxSize     int32

	acquireCount         int64
	acquireDuration      time.Duration
	emptyAcquireCount    int64
	canceledAcquireCount int64

	closed bool
}

// NewPool creates a new pool. Panics if maxSize is less than 1.
func NewPool(constructor Constructor, destructor Destructor, maxSize int32) *Pool {
	if maxSize < 1 {
		panic("maxSize is less than 1")
	}

	return &Pool{
		cond:        sync.NewCond(new(sync.Mutex)),
		destructWG:  &sync.WaitGroup{},
		maxSize:     maxSize,
		constructor: constructor,
		destructor:  destructor,
	}
}

// Close destroys all resources in the pool and rejects future Acquire calls.
// Blocks until all resources are returned to pool and destroyed.
func (p *Pool) Close() {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return
	}
	p.closed = true

	for _, res := range p.idleResources {
		p.allResources = removeResource(p.allResources, res)
		go p.destructResourceValue(res.value)
	}
	p.idleResources = nil
	p.cond.L.Unlock()

	// Wake up all go routines waiting for a resource to be returned so they can terminate.
	p.cond.Broadcast()

	p.destructWG.Wait()
}

// Stat is a snapshot of Pool statistics.
type Stat struct {
	constructingResources int32
	acquiredResources     int32
	idleResources         int32
	maxResources          int32
	acquireCount          int64
	acquireDuration       time.Duration
	emptyAcquireCount     int64
	canceledAcquireCount  int64
}

// TotalResource returns the total number of allocated resources in the pool.
// The value is the sum of ConstructingResources, AcquiredResources, and IdleResources.
func (s *Stat) TotalResources() int32 {
	return s.constructingResources + s.acquiredResources + s.idleResources
}

// ConstructingResources returns the number of resources with construction in progress in
// the pool.
func (s *Stat) ConstructingResources() int32 {
	return s.constructingResources
}

// AcquiredResources returns the number of currently acquired resources in the pool.
func (s *Stat) AcquiredResources() int32 {
	return s.acquiredResources
}

// IdleResources returns the number of currently idle resources in the pool.
func (s *Stat) IdleResources() int32 {
	return s.idleResources
}

// MaxResources returns the maximum size of the pool.
func (s *Stat) MaxResources() int32 {
	return s.maxResources
}

// AcquireCount returns the cumulative count of successful acquires from the pool.
func (s *Stat) AcquireCount() int64 {
	return s.acquireCount
}

// AcquireDuration returns the total duration of all successful acquires from
// the pool.
func (s *Stat) AcquireDuration() time.Duration {
	return s.acquireDuration
}

// EmptyAcquireCount returns the cumulative count of successful acquires from the pool
// that waited for a resource to be released or constructed because the pool was
// empty.
func (s *Stat) EmptyAcquireCount() int64 {
	return s.emptyAcquireCount
}

// CanceledAcquireCount returns the cumulative count of acquires from the pool
// that were canceled by a context.
func (s *Stat) CanceledAcquireCount() int64 {
	return s.canceledAcquireCount
}

// Stat returns the current pool statistics.
func (p *Pool) Stat() *Stat {
	p.cond.L.Lock()
	s := &Stat{
		maxResources:         p.maxSize,
		acquireCount:         p.acquireCount,
		emptyAcquireCount:    p.emptyAcquireCount,
		canceledAcquireCount: p.canceledAcquireCount,
		acquireDuration:      p.acquireDuration,
	}

	for _, res := range p.allResources {
		switch res.status {
		case resourceStatusConstructing:
			s.constructingResources += 1
		case resourceStatusIdle:
			s.idleResources += 1
		case resourceStatusAcquired:
			s.acquiredResources += 1
		}
	}

	p.cond.L.Unlock()
	return s
}

// Acquire gets a resource from the pool. If no resources are available and the pool
// is not at maximum capacity it will create a new resource. If the pool is at
// maximum capacity it will block until a resource is available. ctx can be used
// to cancel the Acquire.
func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
	startNano := nanotime()
	p.cond.L.Lock()
	if doneChan := ctx.Done(); doneChan != nil {
		select {
		case <-ctx.Done():
			p.canceledAcquireCount += 1
			p.cond.L.Unlock()
			return nil, ctx.Err()
		default:
		}
	}

	emptyAcquire := false

	for {
		if p.closed {
			p.cond.L.Unlock()
			return nil, ErrClosedPool
		}

		// If a resource is available now
		if len(p.idleResources) > 0 {
			res := p.idleResources[len(p.idleResources)-1]
			p.idleResources = p.idleResources[:len(p.idleResources)-1]
			res.status = resourceStatusAcquired
			if emptyAcquire {
				p.emptyAcquireCount += 1
			}
			p.acquireCount += 1
			p.acquireDuration += time.Duration(nanotime() - startNano)
			p.cond.L.Unlock()
			return res, nil
		}

		emptyAcquire = true

		// If there is room to create a resource do so
		if len(p.allResources) < int(p.maxSize) {
			res := &Resource{pool: p, creationTime: time.Now(), lastUsedNano: nanotime(), status: resourceStatusConstructing}
			p.allResources = append(p.allResources, res)
			p.destructWG.Add(1)
			p.cond.L.Unlock()

			value, err := p.constructResourceValue(ctx)
			p.cond.L.Lock()
			if err != nil {
				p.allResources = removeResource(p.allResources, res)
				p.destructWG.Done()

				select {
				case <-ctx.Done():
					if err == ctx.Err() {
						p.canceledAcquireCount += 1
					}
				default:
				}

				p.cond.L.Unlock()
				return nil, err
			}

			res.value = value
			res.status = resourceStatusAcquired
			p.emptyAcquireCount += 1
			p.acquireCount += 1
			p.acquireDuration += time.Duration(nanotime() - startNano)
			p.cond.L.Unlock()
			return res, nil
		}

		if ctx.Done() == nil {
			p.cond.Wait()
		} else {
			// Convert p.cond.Wait into a channel
			waitChan := make(chan struct{}, 1)
			go func() {
				p.cond.Wait()
				waitChan <- struct{}{}
			}()

			select {
			case <-ctx.Done():
				// Allow goroutine waiting for signal to exit. Re-signal since we couldn't
				// do anything with it. Another goroutine might be waiting.
				go func() {
					<-waitChan
					p.cond.Signal()
					p.cond.L.Unlock()
				}()

				p.cond.L.Lock()
				p.canceledAcquireCount += 1
				p.cond.L.Unlock()
				return nil, ctx.Err()
			case <-waitChan:
			}
		}
	}
}

// AcquireAllIdle atomically acquires all currently idle resources. Its intended
// use is for health check and keep-alive functionality. It does not update pool
// statistics.
func (p *Pool) AcquireAllIdle() []*Resource {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return nil
	}

	for _, res := range p.idleResources {
		res.status = resourceStatusAcquired
	}
	resources := make([]*Resource, len(p.idleResources))
	copy(resources, p.idleResources)
	p.idleResources = p.idleResources[0:0]

	p.cond.L.Unlock()
	return resources
}

// CreateResource constructs a new resource without acquiring it.
// It goes straight in the IdlePool. It does not check against maxSize.
// It can be useful to maintain warm resources under little load.
func (p *Pool) CreateResource(ctx context.Context) error {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return ErrClosedPool
	}
	p.cond.L.Unlock()

	value, err := p.constructResourceValue(ctx)
	if err != nil {
		return err
	}

	res := &Resource{
		pool:         p,
		creationTime: time.Now(),
		status:       resourceStatusIdle,
		value:        value,
		lastUsedNano: nanotime(),
	}
	p.destructWG.Add(1)

	p.cond.L.Lock()
	// If closed while constructing resource then destroy it and return an error
	if p.closed {
		go p.destructResourceValue(res.value)
		return ErrClosedPool
	}
	p.allResources = append(p.allResources, res)
	p.idleResources = append(p.idleResources, res)
	p.cond.L.Unlock()

	return nil
}

// releaseAcquiredResource returns res to the the pool.
func (p *Pool) releaseAcquiredResource(res *Resource, lastUsedNano int64) {
	p.cond.L.Lock()

	if !p.closed {
		res.lastUsedNano = lastUsedNano
		res.status = resourceStatusIdle
		p.idleResources = append(p.idleResources, res)
	} else {
		p.allResources = removeResource(p.allResources, res)
		go p.destructResourceValue(res.value)
	}

	p.cond.L.Unlock()
	p.cond.Signal()
}

// Remove removes res from the pool and closes it. If res is not part of the
// pool Remove will panic.
func (p *Pool) destroyAcquiredResource(res *Resource) {
	p.destructResourceValue(res.value)
	p.cond.L.Lock()
	p.allResources = removeResource(p.allResources, res)
	p.cond.L.Unlock()
	p.cond.Signal()
}

func (p *Pool) hijackAcquiredResource(res *Resource) {
	p.cond.L.Lock()

	p.allResources = removeResource(p.allResources, res)
	res.status = resourceStatusHijacked
	p.destructWG.Done() // not responsible for destructing hijacked resources

	p.cond.L.Unlock()
	p.cond.Signal()
}

func removeResource(slice []*Resource, res *Resource) []*Resource {
	for i := range slice {
		if slice[i] == res {
			slice[i] = slice[len(slice)-1]
			return slice[:len(slice)-1]
		}
	}

	panic("BUG: removeResource could not find res in slice")
}

func (p *Pool) constructResourceValue(ctx context.Context) (interface{}, error) {
	return p.constructor(ctx)
}

func (p *Pool) destructResourceValue(value interface{}) {
	p.destructor(value)
	p.destructWG.Done()
}
<commit_msg>Update the phrasing of TotalResources.<commit_after>package puddle

import (
	"context"
	"errors"
	"sync"
	"time"
)

const (
	resourceStatusConstructing = 0
	resourceStatusIdle         = iota
	resourceStatusAcquired     = iota
	resourceStatusHijacked     = iota
)

// ErrClosedPool occurs on an attempt to acquire a connection from a closed pool
// or a pool that is closed while the acquire is waiting.
var ErrClosedPool = errors.New("closed pool")

// Constructor is a function called by the pool to construct a resource.
type Constructor func(ctx context.Context) (res interface{}, err error)

// Destructor is a function called by the pool to destroy a resource.
type Destructor func(res interface{})

// Resource is the resource handle returned by acquiring from the pool.
type Resource struct {
	value        interface{}
	pool         *Pool
	creationTime time.Time
	lastUsedNano int64
	status       byte
}

// Value returns the resource value.
func (res *Resource) Value() interface{} {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}
	return res.value
}

// Release returns the resource to the pool. res must not be subsequently used.
func (res *Resource) Release() {
	if res.status != resourceStatusAcquired {
		panic("tried to release resource that is not acquired")
	}
	res.pool.releaseAcquiredResource(res, nanotime())
}

// ReleaseUnused returns the resource to the pool without updating when it was last used used. i.e. LastUsedNanotime
// will not change. res must not be subsequently used.
func (res *Resource) ReleaseUnused() {
	if res.status != resourceStatusAcquired {
		panic("tried to release resource that is not acquired")
	}
	res.pool.releaseAcquiredResource(res, res.lastUsedNano)
}

// Destroy returns the resource to the pool for destruction. res must not be
// subsequently used.
func (res *Resource) Destroy() {
	if res.status != resourceStatusAcquired {
		panic("tried to destroy resource that is not acquired")
	}
	go res.pool.destroyAcquiredResource(res)
}

// Hijack assumes ownership of the resource from the pool. Caller is responsible
// for cleanup of resource value.
func (res *Resource) Hijack() {
	if res.status != resourceStatusAcquired {
		panic("tried to hijack resource that is not acquired")
	}
	res.pool.hijackAcquiredResource(res)
}

// CreationTime returns when the resource was created by the pool.
func (res *Resource) CreationTime() time.Time {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}
	return res.creationTime
}

// LastUsedNanotime returns when Release was last called on the resource measured in nanoseconds from an arbitrary time
// (a monotonic time). Returns creation time if Release has never been called. This is only useful to compare with
// other calls to LastUsedNanotime. In almost all cases, IdleDuration should be used instead.
func (res *Resource) LastUsedNanotime() int64 {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}

	return res.lastUsedNano
}

// IdleDuration returns the duration since Release was last called on the resource. This is equivalent to subtracting
// LastUsedNanotime to the current nanotime.
func (res *Resource) IdleDuration() time.Duration {
	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
		panic("tried to access resource that is not acquired or hijacked")
	}

	return time.Duration(nanotime() - res.lastUsedNano)
}

// Pool is a concurrency-safe resource pool.
type Pool struct {
	cond       *sync.Cond
	destructWG *sync.WaitGroup

	allResources  []*Resource
	idleResources []*Resource

	constructor Constructor
	destructor  Destructor
	maxSize     int32

	acquireCount         int64
	acquireDuration      time.Duration
	emptyAcquireCount    int64
	canceledAcquireCount int64

	closed bool
}

// NewPool creates a new pool. Panics if maxSize is less than 1.
func NewPool(constructor Constructor, destructor Destructor, maxSize int32) *Pool {
	if maxSize < 1 {
		panic("maxSize is less than 1")
	}

	return &Pool{
		cond:        sync.NewCond(new(sync.Mutex)),
		destructWG:  &sync.WaitGroup{},
		maxSize:     maxSize,
		constructor: constructor,
		destructor:  destructor,
	}
}

// Close destroys all resources in the pool and rejects future Acquire calls.
// Blocks until all resources are returned to pool and destroyed.
func (p *Pool) Close() {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return
	}
	p.closed = true

	for _, res := range p.idleResources {
		p.allResources = removeResource(p.allResources, res)
		go p.destructResourceValue(res.value)
	}
	p.idleResources = nil
	p.cond.L.Unlock()

	// Wake up all go routines waiting for a resource to be returned so they can terminate.
	p.cond.Broadcast()

	p.destructWG.Wait()
}

// Stat is a snapshot of Pool statistics.
type Stat struct {
	constructingResources int32
	acquiredResources     int32
	idleResources         int32
	maxResources          int32
	acquireCount          int64
	acquireDuration       time.Duration
	emptyAcquireCount     int64
	canceledAcquireCount  int64
}

// TotalResource returns the total number of resources currently in the pool.
// The value is the sum of ConstructingResources, AcquiredResources, and
// IdleResources.
func (s *Stat) TotalResources() int32 {
	return s.constructingResources + s.acquiredResources + s.idleResources
}

// ConstructingResources returns the number of resources with construction in progress in
// the pool.
func (s *Stat) ConstructingResources() int32 {
	return s.constructingResources
}

// AcquiredResources returns the number of currently acquired resources in the pool.
func (s *Stat) AcquiredResources() int32 {
	return s.acquiredResources
}

// IdleResources returns the number of currently idle resources in the pool.
func (s *Stat) IdleResources() int32 {
	return s.idleResources
}

// MaxResources returns the maximum size of the pool.
func (s *Stat) MaxResources() int32 {
	return s.maxResources
}

// AcquireCount returns the cumulative count of successful acquires from the pool.
func (s *Stat) AcquireCount() int64 {
	return s.acquireCount
}

// AcquireDuration returns the total duration of all successful acquires from
// the pool.
func (s *Stat) AcquireDuration() time.Duration {
	return s.acquireDuration
}

// EmptyAcquireCount returns the cumulative count of successful acquires from the pool
// that waited for a resource to be released or constructed because the pool was
// empty.
func (s *Stat) EmptyAcquireCount() int64 {
	return s.emptyAcquireCount
}

// CanceledAcquireCount returns the cumulative count of acquires from the pool
// that were canceled by a context.
func (s *Stat) CanceledAcquireCount() int64 {
	return s.canceledAcquireCount
}

// Stat returns the current pool statistics.
func (p *Pool) Stat() *Stat {
	p.cond.L.Lock()
	s := &Stat{
		maxResources:         p.maxSize,
		acquireCount:         p.acquireCount,
		emptyAcquireCount:    p.emptyAcquireCount,
		canceledAcquireCount: p.canceledAcquireCount,
		acquireDuration:      p.acquireDuration,
	}

	for _, res := range p.allResources {
		switch res.status {
		case resourceStatusConstructing:
			s.constructingResources += 1
		case resourceStatusIdle:
			s.idleResources += 1
		case resourceStatusAcquired:
			s.acquiredResources += 1
		}
	}

	p.cond.L.Unlock()
	return s
}

// Acquire gets a resource from the pool. If no resources are available and the pool
// is not at maximum capacity it will create a new resource. If the pool is at
// maximum capacity it will block until a resource is available. ctx can be used
// to cancel the Acquire.
func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
	startNano := nanotime()
	p.cond.L.Lock()
	if doneChan := ctx.Done(); doneChan != nil {
		select {
		case <-ctx.Done():
			p.canceledAcquireCount += 1
			p.cond.L.Unlock()
			return nil, ctx.Err()
		default:
		}
	}

	emptyAcquire := false

	for {
		if p.closed {
			p.cond.L.Unlock()
			return nil, ErrClosedPool
		}

		// If a resource is available now
		if len(p.idleResources) > 0 {
			res := p.idleResources[len(p.idleResources)-1]
			p.idleResources = p.idleResources[:len(p.idleResources)-1]
			res.status = resourceStatusAcquired
			if emptyAcquire {
				p.emptyAcquireCount += 1
			}
			p.acquireCount += 1
			p.acquireDuration += time.Duration(nanotime() - startNano)
			p.cond.L.Unlock()
			return res, nil
		}

		emptyAcquire = true

		// If there is room to create a resource do so
		if len(p.allResources) < int(p.maxSize) {
			res := &Resource{pool: p, creationTime: time.Now(), lastUsedNano: nanotime(), status: resourceStatusConstructing}
			p.allResources = append(p.allResources, res)
			p.destructWG.Add(1)
			p.cond.L.Unlock()

			value, err := p.constructResourceValue(ctx)
			p.cond.L.Lock()
			if err != nil {
				p.allResources = removeResource(p.allResources, res)
				p.destructWG.Done()

				select {
				case <-ctx.Done():
					if err == ctx.Err() {
						p.canceledAcquireCount += 1
					}
				default:
				}

				p.cond.L.Unlock()
				return nil, err
			}

			res.value = value
			res.status = resourceStatusAcquired
			p.emptyAcquireCount += 1
			p.acquireCount += 1
			p.acquireDuration += time.Duration(nanotime() - startNano)
			p.cond.L.Unlock()
			return res, nil
		}

		if ctx.Done() == nil {
			p.cond.Wait()
		} else {
			// Convert p.cond.Wait into a channel
			waitChan := make(chan struct{}, 1)
			go func() {
				p.cond.Wait()
				waitChan <- struct{}{}
			}()

			select {
			case <-ctx.Done():
				// Allow goroutine waiting for signal to exit. Re-signal since we couldn't
				// do anything with it. Another goroutine might be waiting.
				go func() {
					<-waitChan
					p.cond.Signal()
					p.cond.L.Unlock()
				}()

				p.cond.L.Lock()
				p.canceledAcquireCount += 1
				p.cond.L.Unlock()
				return nil, ctx.Err()
			case <-waitChan:
			}
		}
	}
}

// AcquireAllIdle atomically acquires all currently idle resources. Its intended
// use is for health check and keep-alive functionality. It does not update pool
// statistics.
func (p *Pool) AcquireAllIdle() []*Resource {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return nil
	}

	for _, res := range p.idleResources {
		res.status = resourceStatusAcquired
	}
	resources := make([]*Resource, len(p.idleResources))
	copy(resources, p.idleResources)
	p.idleResources = p.idleResources[0:0]

	p.cond.L.Unlock()
	return resources
}

// CreateResource constructs a new resource without acquiring it.
// It goes straight in the IdlePool. It does not check against maxSize.
// It can be useful to maintain warm resources under little load.
func (p *Pool) CreateResource(ctx context.Context) error {
	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return ErrClosedPool
	}
	p.cond.L.Unlock()

	value, err := p.constructResourceValue(ctx)
	if err != nil {
		return err
	}

	res := &Resource{
		pool:         p,
		creationTime: time.Now(),
		status:       resourceStatusIdle,
		value:        value,
		lastUsedNano: nanotime(),
	}
	p.destructWG.Add(1)

	p.cond.L.Lock()
	// If closed while constructing resource then destroy it and return an error
	if p.closed {
		go p.destructResourceValue(res.value)
		return ErrClosedPool
	}
	p.allResources = append(p.allResources, res)
	p.idleResources = append(p.idleResources, res)
	p.cond.L.Unlock()

	return nil
}

// releaseAcquiredResource returns res to the the pool.
func (p *Pool) releaseAcquiredResource(res *Resource, lastUsedNano int64) {
	p.cond.L.Lock()

	if !p.closed {
		res.lastUsedNano = lastUsedNano
		res.status = resourceStatusIdle
		p.idleResources = append(p.idleResources, res)
	} else {
		p.allResources = removeResource(p.allResources, res)
		go p.destructResourceValue(res.value)
	}

	p.cond.L.Unlock()
	p.cond.Signal()
}

// Remove removes res from the pool and closes it. If res is not part of the
// pool Remove will panic.
func (p *Pool) destroyAcquiredResource(res *Resource) {
	p.destructResourceValue(res.value)
	p.cond.L.Lock()
	p.allResources = removeResource(p.allResources, res)
	p.cond.L.Unlock()
	p.cond.Signal()
}

func (p *Pool) hijackAcquiredResource(res *Resource) {
	p.cond.L.Lock()

	p.allResources = removeResource(p.allResources, res)
	res.status = resourceStatusHijacked
	p.destructWG.Done() // not responsible for destructing hijacked resources

	p.cond.L.Unlock()
	p.cond.Signal()
}

func removeResource(slice []*Resource, res *Resource) []*Resource {
	for i := range slice {
		if slice[i] == res {
			slice[i] = slice[len(slice)-1]
			return slice[:len(slice)-1]
		}
	}

	panic("BUG: removeResource could not find res in slice")
}

func (p *Pool) constructResourceValue(ctx context.Context) (interface{}, error) {
	return p.constructor(ctx)
}

func (p *Pool) destructResourceValue(value interface{}) {
	p.destructor(value)
	p.destructWG.Done()
}
<|endoftext|>


<commit_before>package stingray

import (
	"encoding/json"
	"net/http"
)

// A Pool is a Stingray pool.
type Pool struct {
	jsonResource   `json:"-"`
	PoolProperties `json:"properties"`
}

type PoolProperties struct {
	AutoScaling struct {
		AddNodeDelayTime *int      `json:"addnode_delaytime,omitempty"`
		CloudCredentials *string   `json:"cloud_credentials,omitempty"`
		Cluster          *string   `json:"cluster,omitempty"`
		DataCenter       *string   `json:"data_center,omitempty"`
		DataStore        *string   `json:"data_store,omitempty"`
		Enabled          *bool     `json:"enabled,omitempty"`
		External         *bool     `json:"external,omitempty"`
		Hysteresis       *int      `json:"hysteresis,omitempty"`
		ImageID          *string   `json:"imageid,omitempty"`
		IPsToUse         *string   `json:"ips_to_use,omitempty"`
		LastNodeIdleTime *int      `json:"last_node_idle_time,omitempty"`
		MaxNodes         *int      `json:"max_nodes,omitempty"`
		MinNodes         *int      `json:"min_nodes,omitempty"`
		Name             *string   `json:"name,omitempty"`
		Port             *int      `json:"port,omitempty"`
		Refractory       *int      `json:"refractory,omitempty"`
		ResponseTime     *int      `json:"response_time,omitempty"`
		ScaleDownLevel   *int      `json:"scale_down_level,omitempty"`
		ScaleUpLevel     *int      `json:"scale_up_level,omitempty"`
		SecurityGroupIDs *[]string `json:"securitygroupids,omitempty"`
		SizeID           *string   `json:"size_id,omitempty"`
		SubnetIDs        *[]string `json:"subnetids,omitempty"`
	} `json:"auto_scaling"`
	Basic struct {
		BandwidthClass                *string     `json:"bandwidth_class,omitempty"`
		FailurePool                   *string     `json:"failure_pool,omitempty"`
		MaxConnectionAttempts         *int        `json:"max_connection_attempts,omitempty"`
		MaxIdleConnectionsPerNode     *int        `json:"max_idle_connections_pernode,omitempty"`
		MaxTimedOutConnectionAttempts *int        `json:"max_timed_out_connection_attempts,omitempty"`
		Monitors                      *[]string   `json:"monitors,omitempty"`
		NodeCloseWithRST              *bool       `json:"node_close_with_rst,omitempty"`
		NodeConnectionAttempts        *int        `json:"node_connection_attempts,omitempty"`
		NodeDeleteBehavior            *string     `json:"node_delete_behavior,omitempty"`
		NodeDrainToDeleteTimeout      *int        `json:"node_drain_to_delete_timeout,omitempty"`
		NodesTable                    *NodesTable `json:"nodes_table,omitempty"`
		PassiveMonitoring             *bool       `json:"passive_monitoring,omitempty"`
		PersistenceClass              *string     `json:"persistence_class,omitempty"`
		Note                          *string     `json:"note,omitempty"`
		Transparent                   *bool       `json:"transparent,omitempty"`
	} `json:"basic"`
	Connection struct {
		MaxConnectTime        *int `json:"max_connect_time,omitempty"`
		MaxConnectionsPerNode *int `json:"max_connections_per_node,omitempty"`
		MaxQueueSize          *int `json:"max_queue_size,omitempty"`
		MaxReplyTime          *int `json:"max_reply_time,omitempty"`
		QueueTimeout          *int `json:"queue_timeout,omitempty"`
	} `json:"connection"`
	DNS struct {
		EDNSUDPSize *int `json:"edns_udpsize,omitempty"`
		MaxUDPSize  *int `json:"max_udpsize,omitempty"`
	} `json:"dns"`
	DNSAutoscale struct {
		Enabled   *bool     `json:"enabled,omitempty"`
		Hostnames *[]string `json:"hostnames,omitempty"`
		Port      *int      `json:"port,omitempty"`
	} `json:"dns_autoscale"`
	FTP struct {
		SupportRFC2428 *bool `json:"support_rfc_2428,omitempty"`
	} `json:"ftp"`
	HTTP struct {
		Keepalive              *bool `json:"keepalive,omitempty"`
		KeepaliveNonIdempotent *bool `json:"keepalive_non_idempotent,omitempty"`
	} `json:"http"`
	KerberosProtocolTransition struct {
		Principal *string `json:"principal,omitempty"`
		Target    *string `json:"target,omitempty"`
	} `json:"kerberos_protocol_transition"`
	LoadBalancing struct {
		Algorithm       *string `json:"algorithm,omitempty"`
		PriorityEnabled *bool   `json:"priority_enabled,omitempty"`
		PriorityNodes   *int    `json:"priority_nodes,omitempty"`
	} `json:"load_balancing"`
	Node struct {
		CloseOnDeath  *bool `json:"close_on_death,omitempty"`
		RetryFailTime *int  `json:"retry_fail_time,omitempty"`
	} `json:"node"`
	SMTP struct {
		SendStartTLS *bool `json:"send_starttls,omitempty"`
	} `json:"smtp"`
	SSL struct {
		ClientAuth          *bool     `json:"client_auth,omitempty"`
		CommonNameMatch     *[]string `json:"common_name_match,omitempty"`
		EllipticCurves      *[]string `json:"elliptic_curves,omitempty"`
		Enable              *bool     `json:"enable,omitempty"`
		Enhance             *bool     `json:"enhance,omitempty"`
		SendCloseAlerts     *bool     `json:"send_close_alerts,omitempty"`
		ServerName          *bool     `json:"server_name,omitempty"`
		SignatureAlgorithms *string   `json:"signature_algorithms,omitempty"`
		SSLCiphers          *string   `json:"ssl_ciphers,omitempty"`
		SSLSupportSSL2      *string   `json:"ssl_support_ssl2,omitempty"`
		SSLSupportSSL3      *string   `json:"ssl_support_ssl3,omitempty"`
		SSLSupportTLS1      *string   `json:"ssl_support_tls1,omitempty"`
		SSLSupportTLS11     *string   `json:"ssl_support_tls1_1,omitempty"`
		SSLSupportTLS12     *string   `json:"ssl_support_tls1_2,omitempty"`
		StrictVerify        *bool     `json:"strict_verify,omitempty"`
	} `json:"ssl"`
	TCP struct {
		Nagle *bool `json:"nagle,omitempty"`
	} `json:"tcp"`
	UDP struct {
		AcceptFrom     *string `json:"accept_from,omitempty"`
		AcceptFromMask *string `json:"accept_from_mask,omitempty"`
	} `json:"udp"`
}

type NodesTable []Node

type Node struct {
	Node     *string `json:"node,omitempty"`
	Priority *int    `json:"priority,omitempty"`
	State    *string `json:"state,omitempty"`
	Weight   *int    `json:"weight,omitempty"`
}

func (r *Pool) endpoint() string {
	return "pools"
}

func (r *Pool) String() string {
	s, _ := jsonMarshal(r)
	return string(s)
}

func (r *Pool) decode(data []byte) error {
	return json.Unmarshal(data, &r)
}

func NewPool(name string) *Pool {
	r := new(Pool)
	r.setName(name)
	return r
}

func (c *Client) GetPool(name string) (*Pool, *http.Response, error) {
	r := NewPool(name)

	resp, err := c.Get(r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

func (c *Client) ListPools() ([]string, *http.Response, error) {
	return c.List(&Pool{})
}
<commit_msg>Remove dns section from pool<commit_after>package stingray

import (
	"encoding/json"
	"net/http"
)

// A Pool is a Stingray pool.
type Pool struct {
	jsonResource   `json:"-"`
	PoolProperties `json:"properties"`
}

type PoolProperties struct {
	AutoScaling struct {
		AddNodeDelayTime *int      `json:"addnode_delaytime,omitempty"`
		CloudCredentials *string   `json:"cloud_credentials,omitempty"`
		Cluster          *string   `json:"cluster,omitempty"`
		DataCenter       *string   `json:"data_center,omitempty"`
		DataStore        *string   `json:"data_store,omitempty"`
		Enabled          *bool     `json:"enabled,omitempty"`
		External         *bool     `json:"external,omitempty"`
		Hysteresis       *int      `json:"hysteresis,omitempty"`
		ImageID          *string   `json:"imageid,omitempty"`
		IPsToUse         *string   `json:"ips_to_use,omitempty"`
		LastNodeIdleTime *int      `json:"last_node_idle_time,omitempty"`
		MaxNodes         *int      `json:"max_nodes,omitempty"`
		MinNodes         *int      `json:"min_nodes,omitempty"`
		Name             *string   `json:"name,omitempty"`
		Port             *int      `json:"port,omitempty"`
		Refractory       *int      `json:"refractory,omitempty"`
		ResponseTime     *int      `json:"response_time,omitempty"`
		ScaleDownLevel   *int      `json:"scale_down_level,omitempty"`
		ScaleUpLevel     *int      `json:"scale_up_level,omitempty"`
		SecurityGroupIDs *[]string `json:"securitygroupids,omitempty"`
		SizeID           *string   `json:"size_id,omitempty"`
		SubnetIDs        *[]string `json:"subnetids,omitempty"`
	} `json:"auto_scaling"`
	Basic struct {
		BandwidthClass                *string     `json:"bandwidth_class,omitempty"`
		FailurePool                   *string     `json:"failure_pool,omitempty"`
		MaxConnectionAttempts         *int        `json:"max_connection_attempts,omitempty"`
		MaxIdleConnectionsPerNode     *int        `json:"max_idle_connections_pernode,omitempty"`
		MaxTimedOutConnectionAttempts *int        `json:"max_timed_out_connection_attempts,omitempty"`
		Monitors                      *[]string   `json:"monitors,omitempty"`
		NodeCloseWithRST              *bool       `json:"node_close_with_rst,omitempty"`
		NodeConnectionAttempts        *int        `json:"node_connection_attempts,omitempty"`
		NodeDeleteBehavior            *string     `json:"node_delete_behavior,omitempty"`
		NodeDrainToDeleteTimeout      *int        `json:"node_drain_to_delete_timeout,omitempty"`
		NodesTable                    *NodesTable `json:"nodes_table,omitempty"`
		PassiveMonitoring             *bool       `json:"passive_monitoring,omitempty"`
		PersistenceClass              *string     `json:"persistence_class,omitempty"`
		Note                          *string     `json:"note,omitempty"`
		Transparent                   *bool       `json:"transparent,omitempty"`
	} `json:"basic"`
	Connection struct {
		MaxConnectTime        *int `json:"max_connect_time,omitempty"`
		MaxConnectionsPerNode *int `json:"max_connections_per_node,omitempty"`
		MaxQueueSize          *int `json:"max_queue_size,omitempty"`
		MaxReplyTime          *int `json:"max_reply_time,omitempty"`
		QueueTimeout          *int `json:"queue_timeout,omitempty"`
	} `json:"connection"`
	DNSAutoscale struct {
		Enabled   *bool     `json:"enabled,omitempty"`
		Hostnames *[]string `json:"hostnames,omitempty"`
		Port      *int      `json:"port,omitempty"`
	} `json:"dns_autoscale"`
	FTP struct {
		SupportRFC2428 *bool `json:"support_rfc_2428,omitempty"`
	} `json:"ftp"`
	HTTP struct {
		Keepalive              *bool `json:"keepalive,omitempty"`
		KeepaliveNonIdempotent *bool `json:"keepalive_non_idempotent,omitempty"`
	} `json:"http"`
	KerberosProtocolTransition struct {
		Principal *string `json:"principal,omitempty"`
		Target    *string `json:"target,omitempty"`
	} `json:"kerberos_protocol_transition"`
	LoadBalancing struct {
		Algorithm       *string `json:"algorithm,omitempty"`
		PriorityEnabled *bool   `json:"priority_enabled,omitempty"`
		PriorityNodes   *int    `json:"priority_nodes,omitempty"`
	} `json:"load_balancing"`
	Node struct {
		CloseOnDeath  *bool `json:"close_on_death,omitempty"`
		RetryFailTime *int  `json:"retry_fail_time,omitempty"`
	} `json:"node"`
	SMTP struct {
		SendStartTLS *bool `json:"send_starttls,omitempty"`
	} `json:"smtp"`
	SSL struct {
		ClientAuth          *bool     `json:"client_auth,omitempty"`
		CommonNameMatch     *[]string `json:"common_name_match,omitempty"`
		EllipticCurves      *[]string `json:"elliptic_curves,omitempty"`
		Enable              *bool     `json:"enable,omitempty"`
		Enhance             *bool     `json:"enhance,omitempty"`
		SendCloseAlerts     *bool     `json:"send_close_alerts,omitempty"`
		ServerName          *bool     `json:"server_name,omitempty"`
		SignatureAlgorithms *string   `json:"signature_algorithms,omitempty"`
		SSLCiphers          *string   `json:"ssl_ciphers,omitempty"`
		SSLSupportSSL2      *string   `json:"ssl_support_ssl2,omitempty"`
		SSLSupportSSL3      *string   `json:"ssl_support_ssl3,omitempty"`
		SSLSupportTLS1      *string   `json:"ssl_support_tls1,omitempty"`
		SSLSupportTLS11     *string   `json:"ssl_support_tls1_1,omitempty"`
		SSLSupportTLS12     *string   `json:"ssl_support_tls1_2,omitempty"`
		StrictVerify        *bool     `json:"strict_verify,omitempty"`
	} `json:"ssl"`
	TCP struct {
		Nagle *bool `json:"nagle,omitempty"`
	} `json:"tcp"`
	UDP struct {
		AcceptFrom     *string `json:"accept_from,omitempty"`
		AcceptFromMask *string `json:"accept_from_mask,omitempty"`
	} `json:"udp"`
}

type NodesTable []Node

type Node struct {
	Node     *string `json:"node,omitempty"`
	Priority *int    `json:"priority,omitempty"`
	State    *string `json:"state,omitempty"`
	Weight   *int    `json:"weight,omitempty"`
}

func (r *Pool) endpoint() string {
	return "pools"
}

func (r *Pool) String() string {
	s, _ := jsonMarshal(r)
	return string(s)
}

func (r *Pool) decode(data []byte) error {
	return json.Unmarshal(data, &r)
}

func NewPool(name string) *Pool {
	r := new(Pool)
	r.setName(name)
	return r
}

func (c *Client) GetPool(name string) (*Pool, *http.Response, error) {
	r := NewPool(name)

	resp, err := c.Get(r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

func (c *Client) ListPools() ([]string, *http.Response, error) {
	return c.List(&Pool{})
}
<|endoftext|>


<commit_before>// Copyright 2020, 2021 Google LLC
//
// 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
//
//     https://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.

// Binary wrap is a test helper program for //elisp:binary_test, which see.
package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"reflect"

	"github.com/google/go-cmp/cmp"
	"github.com/phst/runfiles"
)

func main() {
	log.Println("Args:", os.Args)
	log.Println("Environment:", os.Environ())
	var manifestFile string
	flag.StringVar(&manifestFile, "manifest", "", "")
	flag.Parse()
	if manifestFile == "" {
		log.Fatal("--manifest is empty")
	}
	runfilesLib, err := runfiles.Path("phst_rules_elisp/elisp/runfiles/runfiles.elc")
	if err != nil {
		log.Fatal(err)
	}
	// The load path setup depends on whether we use manifest-based or
	// directory-based runfiles.
	var loadPathArgs []string
	if dir, err := runfiles.Path("phst_rules_elisp"); err == nil {
		// Directory-based runfiles.
		loadPathArgs = []string{"--directory=" + dir}
	} else {
		// Manifest-based runfiles.
		loadPathArgs = []string{
			"--load=" + runfilesLib,
			"--funcall=elisp/runfiles/install-handler",
			"--directory=/bazel-runfile:phst_rules_elisp",
		}
	}
	inputFile, err := runfiles.Path("phst_rules_elisp/elisp/binary.cc")
	if err != nil {
		log.Fatal(err)
	}
	var outputFile string
	if os.PathSeparator == '/' {
		outputFile = "/tmp/output.dat"
	} else {
		outputFile = `C:\Temp\output.dat`
	}
	gotArgs := flag.Args()
	wantArgs := append(
		append([]string{"--quick", "--batch"}, loadPathArgs...),
		"--option",
		inputFile,
		" \t\n\r\f äα𝐴🐈'\\\"",
		"/:"+outputFile,
	)
	if diff := cmp.Diff(gotArgs, wantArgs); diff != "" {
		log.Fatalf("positional arguments: -got +want:\n%s", diff)
	}
	jsonData, err := ioutil.ReadFile(manifestFile)
	if err != nil {
		log.Fatalf("can’t read manifest: %s", err)
	}
	var gotManifest map[string]interface{}
	if err := json.Unmarshal(jsonData, &gotManifest); err != nil {
		log.Fatalf("can’t decode manifest: %s", err)
	}
	wantManifest := map[string]interface{}{
		"root":        "RUNFILES_ROOT",
		"tags":        []interface{}{"local", "mytag"},
		"loadPath":    []interface{}{"phst_rules_elisp"},
		"inputFiles":  []interface{}{"phst_rules_elisp/elisp/binary.cc", "phst_rules_elisp/elisp/binary.h"},
		"outputFiles": []interface{}{outputFile},
	}
	if diff := cmp.Diff(
		gotManifest, wantManifest,
		cmp.FilterPath(isInputFile, cmp.Transformer("", resolveRunfile)),
	); diff != "" {
		log.Fatalf("manifest: -got +want:\n%s", diff)
	}
}

func isInputFile(p cmp.Path) bool {
	if len(p) < 2 {
		return false
	}
	m, ok := p[1].(cmp.MapIndex)
	if !ok {
		return false
	}
	k := m.Key()
	return k.Kind() == reflect.String && k.String() == "inputFiles"
}

func resolveRunfile(s string) string {
	r, err := runfiles.Path(s)
	if err != nil {
		log.Fatalf("error resolving runfile for comparison: %s", err)
	}
	return r
}
<commit_msg>Only try to resolve runfiles that aren’t already resolved<commit_after>// Copyright 2020, 2021 Google LLC
//
// 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
//
//     https://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.

// Binary wrap is a test helper program for //elisp:binary_test, which see.
package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"reflect"

	"github.com/google/go-cmp/cmp"
	"github.com/phst/runfiles"
)

func main() {
	log.Println("Args:", os.Args)
	log.Println("Environment:", os.Environ())
	var manifestFile string
	flag.StringVar(&manifestFile, "manifest", "", "")
	flag.Parse()
	if manifestFile == "" {
		log.Fatal("--manifest is empty")
	}
	runfilesLib, err := runfiles.Path("phst_rules_elisp/elisp/runfiles/runfiles.elc")
	if err != nil {
		log.Fatal(err)
	}
	// The load path setup depends on whether we use manifest-based or
	// directory-based runfiles.
	var loadPathArgs []string
	if dir, err := runfiles.Path("phst_rules_elisp"); err == nil {
		// Directory-based runfiles.
		loadPathArgs = []string{"--directory=" + dir}
	} else {
		// Manifest-based runfiles.
		loadPathArgs = []string{
			"--load=" + runfilesLib,
			"--funcall=elisp/runfiles/install-handler",
			"--directory=/bazel-runfile:phst_rules_elisp",
		}
	}
	inputFile, err := runfiles.Path("phst_rules_elisp/elisp/binary.cc")
	if err != nil {
		log.Fatal(err)
	}
	var outputFile string
	if os.PathSeparator == '/' {
		outputFile = "/tmp/output.dat"
	} else {
		outputFile = `C:\Temp\output.dat`
	}
	gotArgs := flag.Args()
	wantArgs := append(
		append([]string{"--quick", "--batch"}, loadPathArgs...),
		"--option",
		inputFile,
		" \t\n\r\f äα𝐴🐈'\\\"",
		"/:"+outputFile,
	)
	if diff := cmp.Diff(gotArgs, wantArgs); diff != "" {
		log.Fatalf("positional arguments: -got +want:\n%s", diff)
	}
	jsonData, err := ioutil.ReadFile(manifestFile)
	if err != nil {
		log.Fatalf("can’t read manifest: %s", err)
	}
	var gotManifest map[string]interface{}
	if err := json.Unmarshal(jsonData, &gotManifest); err != nil {
		log.Fatalf("can’t decode manifest: %s", err)
	}
	wantManifest := map[string]interface{}{
		"root":        "RUNFILES_ROOT",
		"tags":        []interface{}{"local", "mytag"},
		"loadPath":    []interface{}{"phst_rules_elisp"},
		"inputFiles":  []interface{}{"phst_rules_elisp/elisp/binary.cc", "phst_rules_elisp/elisp/binary.h"},
		"outputFiles": []interface{}{outputFile},
	}
	if diff := cmp.Diff(
		gotManifest, wantManifest,
		cmp.FilterPath(isInputFile, cmp.Transformer("", resolveRunfile)),
	); diff != "" {
		log.Fatalf("manifest: -got +want:\n%s", diff)
	}
}

func isInputFile(p cmp.Path) bool {
	if len(p) < 2 {
		return false
	}
	m, ok := p[1].(cmp.MapIndex)
	if !ok {
		return false
	}
	k := m.Key()
	return k.Kind() == reflect.String && k.String() == "inputFiles"
}

func resolveRunfile(s string) string {
	if filepath.IsAbs(s) {
		return s
	}
	r, err := runfiles.Path(s)
	if err != nil {
		log.Fatalf("error resolving runfile for comparison: %s", err)
	}
	return r
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"time"

	"github.com/gorilla/mux"
)

var (
	port        = flag.String("p", ":12345", "HTTP listen address")
	fetcherPort = flag.String("f", ":8000", "DFK Fetcher port")
)

func init() {
	flag.Parse()
}

// Config provides basic configuration
type Config struct {
	Host         string
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// HTMLServer represents the web service that serves up HTML
type HTMLServer struct {
	server *http.Server
	wg     sync.WaitGroup
}

// Start launches the HTML Server
func Start(cfg Config) *HTMLServer {
	flag.Parse()
	// Setup Context
	_, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Setup Handlers
	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Conent-Type", "text/html")
		w.Write([]byte(`<!DOCTYPE html><html><body><h1>Hello World</h1></body></html>`))
	})
	r.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Conent-Type", "text/html")
		w.Write([]byte("\n\t\tUser-agent: *\n\t\tAllow: /allowed\n\t\tDisallow: /disallowed\n\t\t"))
	})
	r.HandleFunc("/allowed", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("allowed"))
	})
	r.HandleFunc("/disallowed", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(403)
		w.Write([]byte("disallowed"))
	})

	r.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte(`{"alive": true}`))
	})

	r.HandleFunc("/status/{status}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		st, err := strconv.Atoi(vars["status"])
		if err != nil {
			fmt.Println(err)
		}
		w.WriteHeader(st)
		w.Write([]byte(vars["status"]))
	})

	// Create the HTML Server
	htmlServer := HTMLServer{
		server: &http.Server{
			Addr:           cfg.Host,
			Handler:        r,
			ReadTimeout:    cfg.ReadTimeout,
			WriteTimeout:   cfg.WriteTimeout,
			MaxHeaderBytes: 1 << 20,
		},
	}

	// Add to the WaitGroup for the listener goroutine
	htmlServer.wg.Add(1)

	// Start the listener
	go func() {
		// fmt.Printf("\nProxy Server : Service started : Host=%v\n", htmlServer.server.Addr)
		// htmlServer.server.ListenAndServeTLS(
		// 	"/etc/letsencrypt/live/dataflowkit.org/fullchain.pem",
		// 	"/etc/letsencrypt/live/dataflowkit.org/privkey.pem",
		// )
		fmt.Printf("\nProxy Server : Service started : Host=%v\n", htmlServer.server.Addr)
		htmlServer.server.ListenAndServe()
		htmlServer.wg.Done()
	}()
	//redirect all requests from http to https
	// go http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	// 	http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
	// }))
	return &htmlServer
}

// Stop turns off the HTML Server
func (htmlServer *HTMLServer) Stop() error {
	// Create a context to attempt a graceful 5 second shutdown.
	const timeout = 5 * time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	fmt.Printf("\nTest Server : Service stopping\n")

	// Attempt the graceful shutdown by closing the listener
	// and completing all inflight requests
	if err := htmlServer.server.Shutdown(ctx); err != nil {
		// Looks like we timed out on the graceful shutdown. Force close.
		if err := htmlServer.server.Close(); err != nil {
			fmt.Printf("\nTest Server : Service stopping : Error=%v\n", err)
			return err
		}
	}
	// Wait for the listener to report that it is closed.
	htmlServer.wg.Wait()
	fmt.Printf("\nTest Server : Stopped\n")
	return nil
}

func main() {
	serverCfg := Config{
		Host:         *port, //"localhost:5000",
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}
	htmlServer := Start(serverCfg)
	defer htmlServer.Stop()

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt)
	<-sigChan

	fmt.Println("main : shutting down")
}
<commit_msg>add content-type to ping handler<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"time"

	"github.com/gorilla/mux"
)

var (
	port        = flag.String("p", ":12345", "HTTP listen address")
	fetcherPort = flag.String("f", ":8000", "DFK Fetcher port")
)

func init() {
	flag.Parse()
}

// Config provides basic configuration
type Config struct {
	Host         string
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// HTMLServer represents the web service that serves up HTML
type HTMLServer struct {
	server *http.Server
	wg     sync.WaitGroup
}

// Start launches the HTML Server
func Start(cfg Config) *HTMLServer {
	flag.Parse()
	// Setup Context
	_, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Setup Handlers
	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Conent-Type", "text/html")
		w.Write([]byte(`<!DOCTYPE html><html><body><h1>Hello World</h1></body></html>`))
	})
	r.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Conent-Type", "text/html")
		w.Write([]byte("\n\t\tUser-agent: *\n\t\tAllow: /allowed\n\t\tDisallow: /disallowed\n\t\t"))
	})
	r.HandleFunc("/allowed", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("allowed"))
	})
	r.HandleFunc("/disallowed", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(403)
		w.Write([]byte("disallowed"))
	})

	r.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"alive": true}`))
	})

	r.HandleFunc("/status/{status}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		st, err := strconv.Atoi(vars["status"])
		if err != nil {
			fmt.Println(err)
		}
		w.WriteHeader(st)
		w.Write([]byte(vars["status"]))
	})

	// Create the HTML Server
	htmlServer := HTMLServer{
		server: &http.Server{
			Addr:           cfg.Host,
			Handler:        r,
			ReadTimeout:    cfg.ReadTimeout,
			WriteTimeout:   cfg.WriteTimeout,
			MaxHeaderBytes: 1 << 20,
		},
	}

	// Add to the WaitGroup for the listener goroutine
	htmlServer.wg.Add(1)

	// Start the listener
	go func() {
		// fmt.Printf("\nProxy Server : Service started : Host=%v\n", htmlServer.server.Addr)
		// htmlServer.server.ListenAndServeTLS(
		// 	"/etc/letsencrypt/live/dataflowkit.org/fullchain.pem",
		// 	"/etc/letsencrypt/live/dataflowkit.org/privkey.pem",
		// )
		fmt.Printf("\nProxy Server : Service started : Host=%v\n", htmlServer.server.Addr)
		htmlServer.server.ListenAndServe()
		htmlServer.wg.Done()
	}()
	//redirect all requests from http to https
	// go http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	// 	http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
	// }))
	return &htmlServer
}

// Stop turns off the HTML Server
func (htmlServer *HTMLServer) Stop() error {
	// Create a context to attempt a graceful 5 second shutdown.
	const timeout = 5 * time.Second
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	fmt.Printf("\nTest Server : Service stopping\n")

	// Attempt the graceful shutdown by closing the listener
	// and completing all inflight requests
	if err := htmlServer.server.Shutdown(ctx); err != nil {
		// Looks like we timed out on the graceful shutdown. Force close.
		if err := htmlServer.server.Close(); err != nil {
			fmt.Printf("\nTest Server : Service stopping : Error=%v\n", err)
			return err
		}
	}
	// Wait for the listener to report that it is closed.
	htmlServer.wg.Wait()
	fmt.Printf("\nTest Server : Stopped\n")
	return nil
}

func main() {
	serverCfg := Config{
		Host:         *port, //"localhost:5000",
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}
	htmlServer := Start(serverCfg)
	defer htmlServer.Stop()

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt)
	<-sigChan

	fmt.Println("main : shutting down")
}
<|endoftext|>


<commit_before>// Package textpos provides types and functions for working with intervals of
// text in a textual document.
package textpos

import "fmt"

// Line is the line number of some text in a file.
type Line struct {
	value int
}

// LineFromOffset returns a Line object from an offset value.
func LineFromOffset(o int) Line { return LineFromOrdinal(o + 1) }

// LineFromOrdinal returns a Line object from a positive value.
func LineFromOrdinal(o int) Line { return Line{o} }

// Offset returns the line number where 0 indicates the first line.
func (n Line) Offset() int { return n.Ordinal() - 1 }

// Ordinal returns the line number where 1 indicates the first line.
func (n Line) Ordinal() int { return n.value }

// String returns the ordinal value encoded as a base 10 string.
func (n Line) String() string { return fmt.Sprintf("%d", n.Ordinal()) }

// IsValid reports if the line value is valid (ordinal >= 1).
func (n Line) IsValid() bool { return n.Ordinal() > 0 }

// Column is a number indicating a horrizontal offset within a line of text.
//
// Column may be used to designate byte or character offsets. Byte offsets are
// advantageous because they are simple well-defined but match cursor positions
// in most text editors. Characters are not a universally well-defined and
// require more complex lookup but generally correspond to cursor positions in
// text editors.
type Column struct {
	value int
}

// ColumnFromOffset returns a Column object from an offset value (where 0 indicates the first line).
func ColumnFromOffset(o int) Column { return ColumnFromOrdinal(o + 1) }

// ColumnFromOrdinal returns a Column object from an ordinal value (where 1 indicates the first line).
func ColumnFromOrdinal(o int) Column { return Column{o} }

// Offset returns the Column number where 0 indicates the first Column.
func (n Column) Offset() int { return n.Ordinal() - 1 }

// Ordinal returns the Column number where 1 indicates the first Column.
func (n Column) Ordinal() int { return n.value }

// String returns the ordinal value encoded as a base 10 string.
func (n Column) String() string { return fmt.Sprintf("%d", n.Ordinal()) }

// IsValid reports if the column value is valid (ordinal >= 1).
func (n Column) IsValid() bool { return n.Ordinal() > 0 }

// LineColumn is a two dimensional textual position (line, column).
type LineColumn struct {
	line Line
	col  Column
}

// MakeLineColumn returns a new LineColumn tuple.
func MakeLineColumn(line Line, col Column) LineColumn {
	return LineColumn{line, col}
}

// Line returns the line for the tuple.
func (p LineColumn) Line() Line { return p.line }

// Column returns the column for the tuple.
func (p LineColumn) Column() Column { return p.col }

// String returns a string representation of a LineColumn pair.
//
// If column and line are valid, returns "lineOrdinal:columnOrdinal."
func (p LineColumn) String() string {
	l, c := "-", "-"
	if p.Line().IsValid() {
		l = fmt.Sprintf("%d", p.Line().Ordinal())
	}
	if p.Line().IsValid() {
		c = fmt.Sprintf("%d", p.Column().Ordinal())
	}
	return fmt.Sprintf("%s:%s", l, c)
}
<commit_msg>Add warning in textpos package description that the API isn't stable.<commit_after>// Package textpos provides types and functions for working with line-based
// positions of text in a textual document.
//
// WARNING: This package's API is in flux. It is based on the "go/token" package.
package textpos

import "fmt"

// Line is the line number of some text in a file.
type Line struct {
	value int
}

// LineFromOffset returns a Line object from an offset value.
func LineFromOffset(o int) Line { return LineFromOrdinal(o + 1) }

// LineFromOrdinal returns a Line object from a positive value.
func LineFromOrdinal(o int) Line { return Line{o} }

// Offset returns the line number where 0 indicates the first line.
func (n Line) Offset() int { return n.Ordinal() - 1 }

// Ordinal returns the line number where 1 indicates the first line.
func (n Line) Ordinal() int { return n.value }

// String returns the ordinal value encoded as a base 10 string.
func (n Line) String() string { return fmt.Sprintf("%d", n.Ordinal()) }

// IsValid reports if the line value is valid (ordinal >= 1).
func (n Line) IsValid() bool { return n.Ordinal() > 0 }

// Column is a number indicating a horrizontal offset within a line of text.
//
// Column may be used to designate byte or character offsets. Byte offsets are
// advantageous because they are simple well-defined but match cursor positions
// in most text editors. Characters are not a universally well-defined and
// require more complex lookup but generally correspond to cursor positions in
// text editors.
type Column struct {
	value int
}

// ColumnFromOffset returns a Column object from an offset value (where 0 indicates the first line).
func ColumnFromOffset(o int) Column { return ColumnFromOrdinal(o + 1) }

// ColumnFromOrdinal returns a Column object from an ordinal value (where 1 indicates the first line).
func ColumnFromOrdinal(o int) Column { return Column{o} }

// Offset returns the Column number where 0 indicates the first Column.
func (n Column) Offset() int { return n.Ordinal() - 1 }

// Ordinal returns the Column number where 1 indicates the first Column.
func (n Column) Ordinal() int { return n.value }

// String returns the ordinal value encoded as a base 10 string.
func (n Column) String() string { return fmt.Sprintf("%d", n.Ordinal()) }

// IsValid reports if the column value is valid (ordinal >= 1).
func (n Column) IsValid() bool { return n.Ordinal() > 0 }

// LineColumn is a two dimensional textual position (line, column).
type LineColumn struct {
	line Line
	col  Column
}

// MakeLineColumn returns a new LineColumn tuple.
func MakeLineColumn(line Line, col Column) LineColumn {
	return LineColumn{line, col}
}

// Line returns the line for the tuple.
func (p LineColumn) Line() Line { return p.line }

// Column returns the column for the tuple.
func (p LineColumn) Column() Column { return p.col }

// String returns a string representation of a LineColumn pair.
//
// If column and line are valid, returns "lineOrdinal:columnOrdinal."
func (p LineColumn) String() string {
	l, c := "-", "-"
	if p.Line().IsValid() {
		l = fmt.Sprintf("%d", p.Line().Ordinal())
	}
	if p.Line().IsValid() {
		c = fmt.Sprintf("%d", p.Column().Ordinal())
	}
	return fmt.Sprintf("%s:%s", l, c)
}
<|endoftext|>


<commit_before>// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package uuid provides implementation of Universally Unique Identifier (UUID).
// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
// version 2 (as specified in DCE 1.1).
package uuid

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"hash"
	"net"
	"os"
	"sync"
	"time"
)

// UUID layout variants.
const (
	VariantNCS = iota
	VariantRFC4122
	VariantMicrosoft
	VariantFuture
)

// UUID DCE domains.
const (
	DomainPerson = iota
	DomainGroup
	DomainOrg
)

// Difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
const epochStart = 122192928000000000

// Used in string method conversion
const dash byte = '-'

// UUID v1/v2 storage.
var (
	storageMutex  sync.Mutex
	epochFunc     func() uint64 = unixTimeFunc
	clockSequence uint16
	lastTime      uint64
	hardwareAddr  [6]byte
	posixUID      = uint32(os.Getuid())
	posixGID      = uint32(os.Getgid())
)

// String parse helpers.
var (
	urnPrefix  = []byte("urn:uuid:")
	byteGroups = []int{8, 4, 4, 4, 12}
)

// Initialize storage
func init() {
	buf := make([]byte, 2)
	rand.Read(buf)
	clockSequence = binary.BigEndian.Uint16(buf)

	// Initialize hardwareAddr randomly in case
	// of real network interfaces absence
	rand.Read(hardwareAddr[:])

	// Set multicast bit as recommended in RFC 4122
	hardwareAddr[0] |= 0x01

	interfaces, err := net.Interfaces()
	if err == nil {
		for _, iface := range interfaces {
			if len(iface.HardwareAddr) >= 6 {
				copy(hardwareAddr[:], iface.HardwareAddr)
				break
			}
		}
	}
}

// Returns difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and current time.
// This is default epoch calculation function.
func unixTimeFunc() uint64 {
	return epochStart + uint64(time.Now().UnixNano()/100)
}

// UUID representation compliant with specification
// described in RFC 4122.
type UUID [16]byte

// The nil UUID is special form of UUID that is specified to have all
// 128 bits set to zero.
var Nil = UUID{}

// Predefined namespace UUIDs.
var (
	NamespaceDNS, _  = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	NamespaceURL, _  = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
	NamespaceOID, _  = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
	NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
)

// And returns result of binary AND of two UUIDs.
func And(u1 UUID, u2 UUID) UUID {
	u := UUID{}
	for i := 0; i < 16; i++ {
		u[i] = u1[i] & u2[i]
	}
	return u
}

// Or returns result of binary OR of two UUIDs.
func Or(u1 UUID, u2 UUID) UUID {
	u := UUID{}
	for i := 0; i < 16; i++ {
		u[i] = u1[i] | u2[i]
	}
	return u
}

// Equal returns true if u1 and u2 equals, otherwise returns false.
func Equal(u1 UUID, u2 UUID) bool {
	return bytes.Equal(u1[:], u2[:])
}

// Version returns algorithm version used to generate UUID.
func (u UUID) Version() uint {
	return uint(u[6] >> 4)
}

// Variant returns UUID layout variant.
func (u UUID) Variant() uint {
	switch {
	case (u[8] & 0x80) == 0x00:
		return VariantNCS
	case (u[8]&0xc0)|0x80 == 0x80:
		return VariantRFC4122
	case (u[8]&0xe0)|0xc0 == 0xc0:
		return VariantMicrosoft
	}
	return VariantFuture
}

// Bytes returns bytes slice representation of UUID.
func (u UUID) Bytes() []byte {
	return u[:]
}

// Returns canonical string representation of UUID:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (u UUID) String() string {
	buf := make([]byte, 36)

	hex.Encode(buf[0:8], u[0:4])
	buf[8] = dash
	hex.Encode(buf[9:13], u[4:6])
	buf[13] = dash
	hex.Encode(buf[14:18], u[6:8])
	buf[18] = dash
	hex.Encode(buf[19:23], u[8:10])
	buf[23] = dash
	hex.Encode(buf[24:], u[10:])

	return string(buf)
}

// SetVersion sets version bits.
func (u *UUID) SetVersion(v byte) {
	u[6] = (u[6] & 0x0f) | (v << 4)
}

// SetVariant sets variant bits as described in RFC 4122.
func (u *UUID) SetVariant() {
	u[8] = (u[8] & 0xbf) | 0x80
}

// MarshalText implements the encoding.TextMarshaler interface.
// The encoding is the same as returned by String.
func (u UUID) MarshalText() (text []byte, err error) {
	text = []byte(u.String())
	return
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Following formats are supported:
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
func (u *UUID) UnmarshalText(text []byte) (err error) {
	if len(text) < 32 {
		err = fmt.Errorf("uuid: invalid UUID string: %s", text)
		return
	}

	if bytes.Equal(text[:9], urnPrefix) {
		text = text[9:]
	} else if text[0] == '{' {
		text = text[1:]
	}

	b := u[:]

	for _, byteGroup := range byteGroups {
		if text[0] == '-' {
			text = text[1:]
		}

		_, err = hex.Decode(b[:byteGroup/2], text[:byteGroup])

		if err != nil {
			return
		}

		text = text[byteGroup:]
		b = b[byteGroup/2:]
	}

	return
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (u UUID) MarshalBinary() (data []byte, err error) {
	data = u.Bytes()
	return
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// It will return error if the slice isn't 16 bytes long.
func (u *UUID) UnmarshalBinary(data []byte) (err error) {
	if len(data) != 16 {
		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
		return
	}
	copy(u[:], data)

	return
}

// Scan implements the sql.Scanner interface.
// A 16-byte slice is handled by UnmarshalBinary, while
// a longer byte slice or a string is handled by UnmarshalText.
func (u *UUID) Scan(src interface{}) error {
	switch src := src.(type) {
	case []byte:
		if len(src) == 16 {
			return u.UnmarshalBinary(src)
		}
		return u.UnmarshalText(src)

	case string:
		return u.UnmarshalText([]byte(src))
	}

	return fmt.Errorf("uuid: cannot convert %T to UUID", src)
}

// FromBytes returns UUID converted from raw byte slice input.
// It will return error if the slice isn't 16 bytes long.
func FromBytes(input []byte) (u UUID, err error) {
	err = u.UnmarshalBinary(input)
	return
}

// FromString returns UUID parsed from string input.
// Input is expected in a form accepted by UnmarshalText.
func FromString(input string) (u UUID, err error) {
	err = u.UnmarshalText([]byte(input))
	return
}

// Returns UUID v1/v2 storage state.
// Returns epoch timestamp and clock sequence.
func getStorage() (uint64, uint16) {
	storageMutex.Lock()
	defer storageMutex.Unlock()

	timeNow := epochFunc()
	// Clock changed backwards since last UUID generation.
	// Should increase clock sequence.
	if timeNow <= lastTime {
		clockSequence++
	}
	lastTime = timeNow

	return timeNow, clockSequence
}

// NewV1 returns UUID based on current timestamp and MAC address.
func NewV1() UUID {
	u := UUID{}

	timeNow, clockSeq := getStorage()

	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
	binary.BigEndian.PutUint16(u[8:], clockSeq)

	copy(u[10:], hardwareAddr[:])

	u.SetVersion(1)
	u.SetVariant()

	return u
}

// NewV2 returns DCE Security UUID based on POSIX UID/GID.
func NewV2(domain byte) UUID {
	u := UUID{}

	switch domain {
	case DomainPerson:
		binary.BigEndian.PutUint32(u[0:], posixUID)
	case DomainGroup:
		binary.BigEndian.PutUint32(u[0:], posixGID)
	}

	timeNow, clockSeq := getStorage()

	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
	binary.BigEndian.PutUint16(u[8:], clockSeq)
	u[9] = domain

	copy(u[10:], hardwareAddr[:])

	u.SetVersion(2)
	u.SetVariant()

	return u
}

// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
func NewV3(ns UUID, name string) UUID {
	u := newFromHash(md5.New(), ns, name)
	u.SetVersion(3)
	u.SetVariant()

	return u
}

// NewV4 returns random generated UUID.
func NewV4() UUID {
	u := UUID{}
	rand.Read(u[:])
	u.SetVersion(4)
	u.SetVariant()

	return u
}

// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
func NewV5(ns UUID, name string) UUID {
	u := newFromHash(sha1.New(), ns, name)
	u.SetVersion(5)
	u.SetVariant()

	return u
}

// Returns UUID based on hashing of namespace UUID and name.
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
	u := UUID{}
	h.Write(ns[:])
	h.Write([]byte(name))
	copy(u[:], h.Sum(nil))

	return u
}
<commit_msg>Panic when there is an error getting entropy<commit_after>// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package uuid provides implementation of Universally Unique Identifier (UUID).
// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
// version 2 (as specified in DCE 1.1).
package uuid

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"hash"
	"net"
	"os"
	"sync"
	"time"
)

// UUID layout variants.
const (
	VariantNCS = iota
	VariantRFC4122
	VariantMicrosoft
	VariantFuture
)

// UUID DCE domains.
const (
	DomainPerson = iota
	DomainGroup
	DomainOrg
)

// Difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
const epochStart = 122192928000000000

// Used in string method conversion
const dash byte = '-'

// UUID v1/v2 storage.
var (
	storageMutex  sync.Mutex
	epochFunc     func() uint64 = unixTimeFunc
	clockSequence uint16
	lastTime      uint64
	hardwareAddr  [6]byte
	posixUID      = uint32(os.Getuid())
	posixGID      = uint32(os.Getgid())
)

// String parse helpers.
var (
	urnPrefix  = []byte("urn:uuid:")
	byteGroups = []int{8, 4, 4, 4, 12}
)

// Initialize storage
func init() {
	buf := make([]byte, 2)
	safeRandom(buf)
	clockSequence = binary.BigEndian.Uint16(buf)

	interfaces, err := net.Interfaces()
	if err == nil {
		for _, iface := range interfaces {
			if len(iface.HardwareAddr) >= 6 {
				copy(hardwareAddr[:], iface.HardwareAddr)
				return
			}
		}
	}

	// Initialize hardwareAddr randomly in case
	// of real network interfaces absence
	safeRandom(hardwareAddr[:])

	// Set multicast bit as recommended in RFC 4122
	hardwareAddr[0] |= 0x01
}

func safeRandom(dest []byte) {
	if _, err := rand.Read(dest); err != nil {
		panic(err)
	}
}

// Returns difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and current time.
// This is default epoch calculation function.
func unixTimeFunc() uint64 {
	return epochStart + uint64(time.Now().UnixNano()/100)
}

// UUID representation compliant with specification
// described in RFC 4122.
type UUID [16]byte

// The nil UUID is special form of UUID that is specified to have all
// 128 bits set to zero.
var Nil = UUID{}

// Predefined namespace UUIDs.
var (
	NamespaceDNS, _  = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	NamespaceURL, _  = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
	NamespaceOID, _  = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
	NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
)

// And returns result of binary AND of two UUIDs.
func And(u1 UUID, u2 UUID) UUID {
	u := UUID{}
	for i := 0; i < 16; i++ {
		u[i] = u1[i] & u2[i]
	}
	return u
}

// Or returns result of binary OR of two UUIDs.
func Or(u1 UUID, u2 UUID) UUID {
	u := UUID{}
	for i := 0; i < 16; i++ {
		u[i] = u1[i] | u2[i]
	}
	return u
}

// Equal returns true if u1 and u2 equals, otherwise returns false.
func Equal(u1 UUID, u2 UUID) bool {
	return bytes.Equal(u1[:], u2[:])
}

// Version returns algorithm version used to generate UUID.
func (u UUID) Version() uint {
	return uint(u[6] >> 4)
}

// Variant returns UUID layout variant.
func (u UUID) Variant() uint {
	switch {
	case (u[8] & 0x80) == 0x00:
		return VariantNCS
	case (u[8]&0xc0)|0x80 == 0x80:
		return VariantRFC4122
	case (u[8]&0xe0)|0xc0 == 0xc0:
		return VariantMicrosoft
	}
	return VariantFuture
}

// Bytes returns bytes slice representation of UUID.
func (u UUID) Bytes() []byte {
	return u[:]
}

// Returns canonical string representation of UUID:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (u UUID) String() string {
	buf := make([]byte, 36)

	hex.Encode(buf[0:8], u[0:4])
	buf[8] = dash
	hex.Encode(buf[9:13], u[4:6])
	buf[13] = dash
	hex.Encode(buf[14:18], u[6:8])
	buf[18] = dash
	hex.Encode(buf[19:23], u[8:10])
	buf[23] = dash
	hex.Encode(buf[24:], u[10:])

	return string(buf)
}

// SetVersion sets version bits.
func (u *UUID) SetVersion(v byte) {
	u[6] = (u[6] & 0x0f) | (v << 4)
}

// SetVariant sets variant bits as described in RFC 4122.
func (u *UUID) SetVariant() {
	u[8] = (u[8] & 0xbf) | 0x80
}

// MarshalText implements the encoding.TextMarshaler interface.
// The encoding is the same as returned by String.
func (u UUID) MarshalText() (text []byte, err error) {
	text = []byte(u.String())
	return
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Following formats are supported:
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
func (u *UUID) UnmarshalText(text []byte) (err error) {
	if len(text) < 32 {
		err = fmt.Errorf("uuid: invalid UUID string: %s", text)
		return
	}

	if bytes.Equal(text[:9], urnPrefix) {
		text = text[9:]
	} else if text[0] == '{' {
		text = text[1:]
	}

	b := u[:]

	for _, byteGroup := range byteGroups {
		if text[0] == '-' {
			text = text[1:]
		}

		_, err = hex.Decode(b[:byteGroup/2], text[:byteGroup])

		if err != nil {
			return
		}

		text = text[byteGroup:]
		b = b[byteGroup/2:]
	}

	return
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (u UUID) MarshalBinary() (data []byte, err error) {
	data = u.Bytes()
	return
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// It will return error if the slice isn't 16 bytes long.
func (u *UUID) UnmarshalBinary(data []byte) (err error) {
	if len(data) != 16 {
		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
		return
	}
	copy(u[:], data)

	return
}

// Scan implements the sql.Scanner interface.
// A 16-byte slice is handled by UnmarshalBinary, while
// a longer byte slice or a string is handled by UnmarshalText.
func (u *UUID) Scan(src interface{}) error {
	switch src := src.(type) {
	case []byte:
		if len(src) == 16 {
			return u.UnmarshalBinary(src)
		}
		return u.UnmarshalText(src)

	case string:
		return u.UnmarshalText([]byte(src))
	}

	return fmt.Errorf("uuid: cannot convert %T to UUID", src)
}

// FromBytes returns UUID converted from raw byte slice input.
// It will return error if the slice isn't 16 bytes long.
func FromBytes(input []byte) (u UUID, err error) {
	err = u.UnmarshalBinary(input)
	return
}

// FromString returns UUID parsed from string input.
// Input is expected in a form accepted by UnmarshalText.
func FromString(input string) (u UUID, err error) {
	err = u.UnmarshalText([]byte(input))
	return
}

// Returns UUID v1/v2 storage state.
// Returns epoch timestamp and clock sequence.
func getStorage() (uint64, uint16) {
	storageMutex.Lock()
	defer storageMutex.Unlock()

	timeNow := epochFunc()
	// Clock changed backwards since last UUID generation.
	// Should increase clock sequence.
	if timeNow <= lastTime {
		clockSequence++
	}
	lastTime = timeNow

	return timeNow, clockSequence
}

// NewV1 returns UUID based on current timestamp and MAC address.
func NewV1() UUID {
	u := UUID{}

	timeNow, clockSeq := getStorage()

	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
	binary.BigEndian.PutUint16(u[8:], clockSeq)

	copy(u[10:], hardwareAddr[:])

	u.SetVersion(1)
	u.SetVariant()

	return u
}

// NewV2 returns DCE Security UUID based on POSIX UID/GID.
func NewV2(domain byte) UUID {
	u := UUID{}

	switch domain {
	case DomainPerson:
		binary.BigEndian.PutUint32(u[0:], posixUID)
	case DomainGroup:
		binary.BigEndian.PutUint32(u[0:], posixGID)
	}

	timeNow, clockSeq := getStorage()

	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
	binary.BigEndian.PutUint16(u[8:], clockSeq)
	u[9] = domain

	copy(u[10:], hardwareAddr[:])

	u.SetVersion(2)
	u.SetVariant()

	return u
}

// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
func NewV3(ns UUID, name string) UUID {
	u := newFromHash(md5.New(), ns, name)
	u.SetVersion(3)
	u.SetVariant()

	return u
}

// NewV4 returns random generated UUID.
func NewV4() UUID {
	u := UUID{}
	safeRandom(u[:])
	u.SetVersion(4)
	u.SetVariant()

	return u
}

// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
func NewV5(ns UUID, name string) UUID {
	u := newFromHash(sha1.New(), ns, name)
	u.SetVersion(5)
	u.SetVariant()

	return u
}

// Returns UUID based on hashing of namespace UUID and name.
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
	u := UUID{}
	h.Write(ns[:])
	h.Write([]byte(name))
	copy(u[:], h.Sum(nil))

	return u
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"sync"

	dep "github.com/hashicorp/consul-template/dependency"
)

// Brain is what Template uses to determine the values that are
// available for template parsing.
type Brain struct {
	sync.Mutex

	catalogNodes     map[string][]*dep.Node
	catalogServices  map[string][]*dep.CatalogService
	datacenters      map[string][]string
	files            map[string]string
	healthServices   map[string][]*dep.HealthService
	storeKeys        map[string]string
	storeKeyPrefixes map[string][]*dep.KeyPair

	// receivedData is an internal tracker of which dependencies have stored data
	// in the brain
	receivedData map[string]struct{}
}

// NewBrain creates a new Brain with empty values for each
// of the key structs.
func NewBrain() *Brain {
	return &Brain{
		catalogNodes:     make(map[string][]*dep.Node),
		catalogServices:  make(map[string][]*dep.CatalogService),
		datacenters:      make(map[string][]string),
		files:            make(map[string]string),
		healthServices:   make(map[string][]*dep.HealthService),
		storeKeys:        make(map[string]string),
		storeKeyPrefixes: make(map[string][]*dep.KeyPair),
		receivedData:     make(map[string]struct{}),
	}
}

// Remember accepts a dependency and the data to store associated with that
// dep. This function converts the given data to a proper type and stores
// it interally.
func (b *Brain) Remember(d dep.Dependency, data interface{}) {
	log.Printf("[INFO] (brain) remembering %s", d.Display())

	b.Lock()
	defer b.Unlock()

	switch t := d.(type) {
	case *dep.CatalogNodes:
		b.catalogNodes[d.HashCode()] = data.([]*dep.Node)
	case *dep.CatalogServices:
		b.catalogServices[d.HashCode()] = data.([]*dep.CatalogService)
	case *dep.Datacenters:
		b.datacenters[d.HashCode()] = data.([]string)
	case *dep.File:
		b.files[d.HashCode()] = data.(string)
	case *dep.HealthServices:
		b.healthServices[d.HashCode()] = data.([]*dep.HealthService)
	case *dep.StoreKey:
		b.storeKeys[d.HashCode()] = data.(string)
	case *dep.StoreKeyPrefix:
		b.storeKeyPrefixes[d.HashCode()] = data.([]*dep.KeyPair)
	default:
		panic(fmt.Sprintf("brain: unknown dependency type %T", t))
	}

	b.receivedData[d.HashCode()] = struct{}{}
}

// Remembered returns true if the given dependency has received data at least once.
func (b *Brain) Remembered(d dep.Dependency) bool {
	log.Printf("[INFO] (brain) checking if %s has data", d.Display())

	b.Lock()
	defer b.Unlock()

	if _, ok := b.receivedData[d.HashCode()]; ok {
		log.Printf("[DEBUG] (brain) %s had data", d.Display())
		return true
	}

	log.Printf("[DEBUG] (brain) %s did not have data", d.Display())
	return false
}

// Forget accepts a dependency and removes all associated data with this
// dependency. It also resets the "receivedData" internal map.
func (b *Brain) Forget(d dep.Dependency) {
	log.Printf("[INFO] (brain) forgetting %s", d.Display())

	b.Lock()
	defer b.Unlock()

	switch t := d.(type) {
	case *dep.CatalogNodes:
		delete(b.catalogNodes, d.HashCode())
	case *dep.CatalogServices:
		delete(b.catalogServices, d.HashCode())
	case *dep.Datacenters:
		delete(b.datacenters, d.HashCode())
	case *dep.File:
		delete(b.files, d.HashCode())
	case *dep.HealthServices:
		delete(b.healthServices, d.HashCode())
	case *dep.StoreKey:
		delete(b.storeKeys, d.HashCode())
	case *dep.StoreKeyPrefix:
		delete(b.storeKeyPrefixes, d.HashCode())
	default:
		panic(fmt.Sprintf("brain: unknown dependency type %T", t))
	}

	delete(b.receivedData, d.HashCode())
}
<commit_msg>Move Brain log messages after the lock<commit_after>package main

import (
	"fmt"
	"log"
	"sync"

	dep "github.com/hashicorp/consul-template/dependency"
)

// Brain is what Template uses to determine the values that are
// available for template parsing.
type Brain struct {
	sync.Mutex

	catalogNodes     map[string][]*dep.Node
	catalogServices  map[string][]*dep.CatalogService
	datacenters      map[string][]string
	files            map[string]string
	healthServices   map[string][]*dep.HealthService
	storeKeys        map[string]string
	storeKeyPrefixes map[string][]*dep.KeyPair

	// receivedData is an internal tracker of which dependencies have stored data
	// in the brain
	receivedData map[string]struct{}
}

// NewBrain creates a new Brain with empty values for each
// of the key structs.
func NewBrain() *Brain {
	return &Brain{
		catalogNodes:     make(map[string][]*dep.Node),
		catalogServices:  make(map[string][]*dep.CatalogService),
		datacenters:      make(map[string][]string),
		files:            make(map[string]string),
		healthServices:   make(map[string][]*dep.HealthService),
		storeKeys:        make(map[string]string),
		storeKeyPrefixes: make(map[string][]*dep.KeyPair),
		receivedData:     make(map[string]struct{}),
	}
}

// Remember accepts a dependency and the data to store associated with that
// dep. This function converts the given data to a proper type and stores
// it interally.
func (b *Brain) Remember(d dep.Dependency, data interface{}) {
	b.Lock()
	defer b.Unlock()

	log.Printf("[INFO] (brain) remembering %s", d.Display())

	switch t := d.(type) {
	case *dep.CatalogNodes:
		b.catalogNodes[d.HashCode()] = data.([]*dep.Node)
	case *dep.CatalogServices:
		b.catalogServices[d.HashCode()] = data.([]*dep.CatalogService)
	case *dep.Datacenters:
		b.datacenters[d.HashCode()] = data.([]string)
	case *dep.File:
		b.files[d.HashCode()] = data.(string)
	case *dep.HealthServices:
		b.healthServices[d.HashCode()] = data.([]*dep.HealthService)
	case *dep.StoreKey:
		b.storeKeys[d.HashCode()] = data.(string)
	case *dep.StoreKeyPrefix:
		b.storeKeyPrefixes[d.HashCode()] = data.([]*dep.KeyPair)
	default:
		panic(fmt.Sprintf("brain: unknown dependency type %T", t))
	}

	b.receivedData[d.HashCode()] = struct{}{}
}

// Remembered returns true if the given dependency has received data at least once.
func (b *Brain) Remembered(d dep.Dependency) bool {
	b.Lock()
	defer b.Unlock()

	log.Printf("[INFO] (brain) checking if %s has data", d.Display())

	if _, ok := b.receivedData[d.HashCode()]; ok {
		log.Printf("[DEBUG] (brain) %s had data", d.Display())
		return true
	}

	log.Printf("[DEBUG] (brain) %s did not have data", d.Display())
	return false
}

// Forget accepts a dependency and removes all associated data with this
// dependency. It also resets the "receivedData" internal map.
func (b *Brain) Forget(d dep.Dependency) {
	b.Lock()
	defer b.Unlock()

	log.Printf("[INFO] (brain) forgetting %s", d.Display())

	switch t := d.(type) {
	case *dep.CatalogNodes:
		delete(b.catalogNodes, d.HashCode())
	case *dep.CatalogServices:
		delete(b.catalogServices, d.HashCode())
	case *dep.Datacenters:
		delete(b.datacenters, d.HashCode())
	case *dep.File:
		delete(b.files, d.HashCode())
	case *dep.HealthServices:
		delete(b.healthServices, d.HashCode())
	case *dep.StoreKey:
		delete(b.storeKeys, d.HashCode())
	case *dep.StoreKeyPrefix:
		delete(b.storeKeyPrefixes, d.HashCode())
	default:
		panic(fmt.Sprintf("brain: unknown dependency type %T", t))
	}

	delete(b.receivedData, d.HashCode())
}
<|endoftext|>