gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/api/handler/registry/registry.go (about)

     1  // Package registry is a go-micro/registry handler
     2  package registry
     3  
     4  import (
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"strconv"
     9  	"time"
    10  
    11  	"github.com/gorilla/websocket"
    12  	"gitee.com/liuxuezhan/go-micro-v1.18.0/api/handler"
    13  	"gitee.com/liuxuezhan/go-micro-v1.18.0/registry"
    14  )
    15  
    16  const (
    17  	Handler = "registry"
    18  
    19  	pingTime      = (readDeadline * 9) / 10
    20  	readLimit     = 16384
    21  	readDeadline  = 60 * time.Second
    22  	writeDeadline = 10 * time.Second
    23  )
    24  
    25  type registryHandler struct {
    26  	opts handler.Options
    27  	reg  registry.Registry
    28  }
    29  
    30  func (rh *registryHandler) add(w http.ResponseWriter, r *http.Request) {
    31  	r.ParseForm()
    32  	b, err := ioutil.ReadAll(r.Body)
    33  	if err != nil {
    34  		http.Error(w, err.Error(), 500)
    35  		return
    36  	}
    37  	defer r.Body.Close()
    38  
    39  	var opts []registry.RegisterOption
    40  
    41  	// parse ttl
    42  	if ttl := r.Form.Get("ttl"); len(ttl) > 0 {
    43  		d, err := time.ParseDuration(ttl)
    44  		if err == nil {
    45  			opts = append(opts, registry.RegisterTTL(d))
    46  		}
    47  	}
    48  
    49  	var service *registry.Service
    50  	err = json.Unmarshal(b, &service)
    51  	if err != nil {
    52  		http.Error(w, err.Error(), 500)
    53  		return
    54  	}
    55  	err = rh.reg.Register(service, opts...)
    56  	if err != nil {
    57  		http.Error(w, err.Error(), 500)
    58  		return
    59  	}
    60  }
    61  
    62  func (rh *registryHandler) del(w http.ResponseWriter, r *http.Request) {
    63  	r.ParseForm()
    64  	b, err := ioutil.ReadAll(r.Body)
    65  	if err != nil {
    66  		http.Error(w, err.Error(), 500)
    67  		return
    68  	}
    69  	defer r.Body.Close()
    70  
    71  	var service *registry.Service
    72  	err = json.Unmarshal(b, &service)
    73  	if err != nil {
    74  		http.Error(w, err.Error(), 500)
    75  		return
    76  	}
    77  	err = rh.reg.Deregister(service)
    78  	if err != nil {
    79  		http.Error(w, err.Error(), 500)
    80  		return
    81  	}
    82  }
    83  
    84  func (rh *registryHandler) get(w http.ResponseWriter, r *http.Request) {
    85  	r.ParseForm()
    86  	service := r.Form.Get("service")
    87  
    88  	var s []*registry.Service
    89  	var err error
    90  
    91  	if len(service) == 0 {
    92  		//
    93  		upgrade := r.Header.Get("Upgrade")
    94  		connect := r.Header.Get("Connection")
    95  
    96  		// watch if websockets
    97  		if upgrade == "websocket" && connect == "Upgrade" {
    98  			rw, err := rh.reg.Watch()
    99  			if err != nil {
   100  				http.Error(w, err.Error(), 500)
   101  				return
   102  			}
   103  			watch(rw, w, r)
   104  			return
   105  		}
   106  
   107  		// otherwise list services
   108  		s, err = rh.reg.ListServices()
   109  	} else {
   110  		s, err = rh.reg.GetService(service)
   111  	}
   112  
   113  	if err != nil {
   114  		http.Error(w, err.Error(), 500)
   115  		return
   116  	}
   117  
   118  	if s == nil || (len(service) > 0 && (len(s) == 0 || len(s[0].Name) == 0)) {
   119  		http.Error(w, "Service not found", 404)
   120  		return
   121  	}
   122  
   123  	b, err := json.Marshal(s)
   124  	if err != nil {
   125  		http.Error(w, err.Error(), 500)
   126  		return
   127  	}
   128  
   129  	w.Header().Set("Content-Type", "application/json")
   130  	w.Header().Set("Content-Length", strconv.Itoa(len(b)))
   131  	w.Write(b)
   132  }
   133  
   134  func ping(ws *websocket.Conn, exit chan bool) {
   135  	ticker := time.NewTicker(pingTime)
   136  
   137  	for {
   138  		select {
   139  		case <-ticker.C:
   140  			ws.SetWriteDeadline(time.Now().Add(writeDeadline))
   141  			err := ws.WriteMessage(websocket.PingMessage, []byte{})
   142  			if err != nil {
   143  				return
   144  			}
   145  		case <-exit:
   146  			return
   147  		}
   148  	}
   149  }
   150  
   151  func watch(rw registry.Watcher, w http.ResponseWriter, r *http.Request) {
   152  	upgrader := websocket.Upgrader{
   153  		ReadBufferSize:  1024,
   154  		WriteBufferSize: 1024,
   155  	}
   156  
   157  	ws, err := upgrader.Upgrade(w, r, nil)
   158  	if err != nil {
   159  		http.Error(w, err.Error(), 500)
   160  		return
   161  	}
   162  
   163  	// we need an exit chan
   164  	exit := make(chan bool)
   165  
   166  	defer func() {
   167  		close(exit)
   168  	}()
   169  
   170  	// ping the socket
   171  	go ping(ws, exit)
   172  
   173  	for {
   174  		// get next result
   175  		r, err := rw.Next()
   176  		if err != nil {
   177  			http.Error(w, err.Error(), 500)
   178  			return
   179  		}
   180  
   181  		// write to client
   182  		ws.SetWriteDeadline(time.Now().Add(writeDeadline))
   183  		if err := ws.WriteJSON(r); err != nil {
   184  			return
   185  		}
   186  	}
   187  }
   188  
   189  func (rh *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   190  	switch r.Method {
   191  	case "GET":
   192  		rh.get(w, r)
   193  	case "POST":
   194  		rh.add(w, r)
   195  	case "DELETE":
   196  		rh.del(w, r)
   197  	}
   198  }
   199  
   200  func (rh *registryHandler) String() string {
   201  	return "registry"
   202  }
   203  
   204  func NewHandler(opts ...handler.Option) handler.Handler {
   205  	options := handler.NewOptions(opts...)
   206  
   207  	return &registryHandler{
   208  		opts: options,
   209  		reg:  options.Service.Client().Options().Registry,
   210  	}
   211  }