105 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package consul is a consul implemenation of lock
 | 
						|
package consul
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/hashicorp/consul/api"
 | 
						|
	lock "github.com/micro/go-micro/sync/lock"
 | 
						|
)
 | 
						|
 | 
						|
type consulLock struct {
 | 
						|
	sync.Mutex
 | 
						|
 | 
						|
	locks map[string]*api.Lock
 | 
						|
	opts  lock.Options
 | 
						|
	c     *api.Client
 | 
						|
}
 | 
						|
 | 
						|
func (c *consulLock) Acquire(id string, opts ...lock.AcquireOption) error {
 | 
						|
	var options lock.AcquireOptions
 | 
						|
	for _, o := range opts {
 | 
						|
		o(&options)
 | 
						|
	}
 | 
						|
 | 
						|
	if options.Wait <= time.Duration(0) {
 | 
						|
		options.Wait = api.DefaultLockWaitTime
 | 
						|
	}
 | 
						|
 | 
						|
	ttl := fmt.Sprintf("%v", options.TTL)
 | 
						|
	if options.TTL <= time.Duration(0) {
 | 
						|
		ttl = api.DefaultLockSessionTTL
 | 
						|
	}
 | 
						|
 | 
						|
	l, err := c.c.LockOpts(&api.LockOptions{
 | 
						|
		Key:          c.opts.Prefix + id,
 | 
						|
		LockWaitTime: options.Wait,
 | 
						|
		SessionTTL:   ttl,
 | 
						|
	})
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = l.Lock(nil)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	c.Lock()
 | 
						|
	c.locks[id] = l
 | 
						|
	c.Unlock()
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (c *consulLock) Release(id string) error {
 | 
						|
	c.Lock()
 | 
						|
	defer c.Unlock()
 | 
						|
	l, ok := c.locks[id]
 | 
						|
	if !ok {
 | 
						|
		return errors.New("lock not found")
 | 
						|
	}
 | 
						|
	err := l.Unlock()
 | 
						|
	delete(c.locks, id)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (c *consulLock) String() string {
 | 
						|
	return "consul"
 | 
						|
}
 | 
						|
 | 
						|
func NewLock(opts ...lock.Option) lock.Lock {
 | 
						|
	var options lock.Options
 | 
						|
	for _, o := range opts {
 | 
						|
		o(&options)
 | 
						|
	}
 | 
						|
 | 
						|
	config := api.DefaultConfig()
 | 
						|
 | 
						|
	// set host
 | 
						|
	// config.Host something
 | 
						|
	// check if there are any addrs
 | 
						|
	if len(options.Nodes) > 0 {
 | 
						|
		addr, port, err := net.SplitHostPort(options.Nodes[0])
 | 
						|
		if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
 | 
						|
			port = "8500"
 | 
						|
			config.Address = fmt.Sprintf("%s:%s", options.Nodes[0], port)
 | 
						|
		} else if err == nil {
 | 
						|
			config.Address = fmt.Sprintf("%s:%s", addr, port)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	client, _ := api.NewClient(config)
 | 
						|
 | 
						|
	return &consulLock{
 | 
						|
		locks: make(map[string]*api.Lock),
 | 
						|
		opts:  options,
 | 
						|
		c:     client,
 | 
						|
	}
 | 
						|
}
 |