gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/sync/lock/http/http.go (about)

     1  // Package http adds a http lock implementation
     2  package http
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"hash/crc32"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"net/url"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	"gitee.com/liuxuezhan/go-micro-v1.18.0/sync/lock"
    15  )
    16  
    17  var (
    18  	DefaultPath    = "/sync/lock"
    19  	DefaultAddress = "localhost:8080"
    20  )
    21  
    22  type httpLock struct {
    23  	opts lock.Options
    24  }
    25  
    26  func (h *httpLock) url(do, id string) (string, error) {
    27  	sum := crc32.ChecksumIEEE([]byte(id))
    28  	node := h.opts.Nodes[sum%uint32(len(h.opts.Nodes))]
    29  
    30  	// parse the host:port or whatever
    31  	uri, err := url.Parse(node)
    32  	if err != nil {
    33  		return "", err
    34  	}
    35  
    36  	if len(uri.Scheme) == 0 {
    37  		uri.Scheme = "http"
    38  	}
    39  
    40  	// set path
    41  	// build path
    42  	path := filepath.Join(DefaultPath, do, h.opts.Prefix, id)
    43  	uri.Path = path
    44  
    45  	// return url
    46  	return uri.String(), nil
    47  }
    48  
    49  func (h *httpLock) Acquire(id string, opts ...lock.AcquireOption) error {
    50  	var options lock.AcquireOptions
    51  	for _, o := range opts {
    52  		o(&options)
    53  	}
    54  
    55  	uri, err := h.url("acquire", id)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	ttl := fmt.Sprintf("%d", int64(options.TTL.Seconds()))
    61  	wait := fmt.Sprintf("%d", int64(options.Wait.Seconds()))
    62  
    63  	rsp, err := http.PostForm(uri, url.Values{
    64  		"id":   {id},
    65  		"ttl":  {ttl},
    66  		"wait": {wait},
    67  	})
    68  	if err != nil {
    69  		return err
    70  	}
    71  	defer rsp.Body.Close()
    72  
    73  	b, err := ioutil.ReadAll(rsp.Body)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	// success
    79  	if rsp.StatusCode == 200 {
    80  		return nil
    81  	}
    82  
    83  	// return error
    84  	return errors.New(string(b))
    85  }
    86  
    87  func (h *httpLock) Release(id string) error {
    88  	uri, err := h.url("release", id)
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	vals := url.Values{
    94  		"id": {id},
    95  	}
    96  
    97  	req, err := http.NewRequest("DELETE", uri, strings.NewReader(vals.Encode()))
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	rsp, err := http.DefaultClient.Do(req)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	defer rsp.Body.Close()
   107  
   108  	b, err := ioutil.ReadAll(rsp.Body)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	// success
   114  	if rsp.StatusCode == 200 {
   115  		return nil
   116  	}
   117  
   118  	// return error
   119  	return errors.New(string(b))
   120  }
   121  
   122  func NewLock(opts ...lock.Option) lock.Lock {
   123  	var options lock.Options
   124  	for _, o := range opts {
   125  		o(&options)
   126  	}
   127  
   128  	if len(options.Nodes) == 0 {
   129  		options.Nodes = []string{DefaultAddress}
   130  	}
   131  
   132  	return &httpLock{
   133  		opts: options,
   134  	}
   135  }