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,
 | |
| 	}
 | |
| }
 |