136 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package http adds a http lock implementation
 | |
| package http
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"hash/crc32"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/micro/go-micro/v2/sync/lock"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	DefaultPath    = "/sync/lock"
 | |
| 	DefaultAddress = "localhost:8080"
 | |
| )
 | |
| 
 | |
| type httpLock struct {
 | |
| 	opts lock.Options
 | |
| }
 | |
| 
 | |
| func (h *httpLock) url(do, id string) (string, error) {
 | |
| 	sum := crc32.ChecksumIEEE([]byte(id))
 | |
| 	node := h.opts.Nodes[sum%uint32(len(h.opts.Nodes))]
 | |
| 
 | |
| 	// parse the host:port or whatever
 | |
| 	uri, err := url.Parse(node)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	if len(uri.Scheme) == 0 {
 | |
| 		uri.Scheme = "http"
 | |
| 	}
 | |
| 
 | |
| 	// set path
 | |
| 	// build path
 | |
| 	path := filepath.Join(DefaultPath, do, h.opts.Prefix, id)
 | |
| 	uri.Path = path
 | |
| 
 | |
| 	// return url
 | |
| 	return uri.String(), nil
 | |
| }
 | |
| 
 | |
| func (h *httpLock) Acquire(id string, opts ...lock.AcquireOption) error {
 | |
| 	var options lock.AcquireOptions
 | |
| 	for _, o := range opts {
 | |
| 		o(&options)
 | |
| 	}
 | |
| 
 | |
| 	uri, err := h.url("acquire", id)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	ttl := fmt.Sprintf("%d", int64(options.TTL.Seconds()))
 | |
| 	wait := fmt.Sprintf("%d", int64(options.Wait.Seconds()))
 | |
| 
 | |
| 	rsp, err := http.PostForm(uri, url.Values{
 | |
| 		"id":   {id},
 | |
| 		"ttl":  {ttl},
 | |
| 		"wait": {wait},
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer rsp.Body.Close()
 | |
| 
 | |
| 	b, err := ioutil.ReadAll(rsp.Body)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// success
 | |
| 	if rsp.StatusCode == 200 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// return error
 | |
| 	return errors.New(string(b))
 | |
| }
 | |
| 
 | |
| func (h *httpLock) Release(id string) error {
 | |
| 	uri, err := h.url("release", id)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	vals := url.Values{
 | |
| 		"id": {id},
 | |
| 	}
 | |
| 
 | |
| 	req, err := http.NewRequest("DELETE", uri, strings.NewReader(vals.Encode()))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	rsp, err := http.DefaultClient.Do(req)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer rsp.Body.Close()
 | |
| 
 | |
| 	b, err := ioutil.ReadAll(rsp.Body)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// success
 | |
| 	if rsp.StatusCode == 200 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// return error
 | |
| 	return errors.New(string(b))
 | |
| }
 | |
| 
 | |
| func NewLock(opts ...lock.Option) lock.Lock {
 | |
| 	var options lock.Options
 | |
| 	for _, o := range opts {
 | |
| 		o(&options)
 | |
| 	}
 | |
| 
 | |
| 	if len(options.Nodes) == 0 {
 | |
| 		options.Nodes = []string{DefaultAddress}
 | |
| 	}
 | |
| 
 | |
| 	return &httpLock{
 | |
| 		opts: options,
 | |
| 	}
 | |
| }
 |