github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/broker/http/http.go (about)

     1  package http
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/tls"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"math/rand"
    11  	"net"
    12  	"net/http"
    13  	"net/url"
    14  	"runtime"
    15  	"sync"
    16  	"sync/atomic"
    17  	"time"
    18  
    19  	"github.com/volts-dev/volts/broker"
    20  	maddr "github.com/volts-dev/volts/internal/addr"
    21  	vnet "github.com/volts-dev/volts/internal/net"
    22  	"github.com/volts-dev/volts/logger"
    23  	"github.com/volts-dev/volts/router"
    24  	"github.com/volts-dev/volts/transport"
    25  
    26  	"github.com/google/uuid"
    27  	"github.com/volts-dev/volts/codec"
    28  	"github.com/volts-dev/volts/registry"
    29  	"github.com/volts-dev/volts/registry/cacher"
    30  
    31  	"golang.org/x/net/http2"
    32  )
    33  
    34  var log = logger.New("broker")
    35  
    36  type (
    37  	httpBroker struct {
    38  		sync.RWMutex
    39  		id          string
    40  		address     string
    41  		subscribers map[string][]*httpSubscriber
    42  		running     bool
    43  		exit        chan chan error
    44  
    45  		config    *broker.Config
    46  		router    *router.TRouter
    47  		transport transport.ITransport
    48  		started   atomic.Value // marks the serve as started
    49  
    50  		_mux     *http.ServeMux
    51  		client   *http.Client
    52  		registry registry.IRegistry
    53  
    54  		// offline message inbox
    55  
    56  		mtx   sync.RWMutex
    57  		inbox map[string][][]byte
    58  	}
    59  )
    60  
    61  var (
    62  	DefaultSubPath   = "/_sub"
    63  	serviceName      = "volts.http.broker"
    64  	broadcastVersion = "volts.http.broadcast"
    65  	registerTTL      = time.Minute
    66  	registerInterval = time.Second * 30
    67  )
    68  
    69  func init() {
    70  	broker.Register("http", New)
    71  }
    72  
    73  func newTransport(config *tls.Config) *http.Transport {
    74  	if config == nil {
    75  		config = &tls.Config{
    76  			InsecureSkipVerify: true,
    77  		}
    78  	}
    79  
    80  	dialTLS := func(network string, addr string) (net.Conn, error) {
    81  		return tls.Dial(network, addr, config)
    82  	}
    83  
    84  	t := &http.Transport{
    85  		Proxy: http.ProxyFromEnvironment,
    86  		Dial: (&net.Dialer{
    87  			Timeout:   30 * time.Second,
    88  			KeepAlive: 30 * time.Second,
    89  		}).Dial,
    90  		TLSHandshakeTimeout: 10 * time.Second,
    91  		DialTLS:             dialTLS,
    92  	}
    93  	runtime.SetFinalizer(&t, func(tr **http.Transport) {
    94  		(*tr).CloseIdleConnections()
    95  	})
    96  
    97  	// setup http2
    98  	http2.ConfigureTransport(t)
    99  
   100  	return t
   101  }
   102  
   103  func New(opts ...broker.Option) broker.IBroker {
   104  	var defaultOpts []broker.Option
   105  	defaultOpts = append(defaultOpts,
   106  		broker.WithName("http"),
   107  		broker.WithCodec(codec.JSON),
   108  		broker.WithRegistry(registry.Default()),
   109  		broker.WithContext(context.TODO()),
   110  	)
   111  
   112  	cfg := broker.NewConfig(append(defaultOpts, opts...)...)
   113  
   114  	// set address
   115  	addr := broker.DefaultAddress
   116  	if len(cfg.Addrs) > 0 && len(cfg.Addrs[0]) > 0 {
   117  		addr = cfg.Addrs[0]
   118  	}
   119  
   120  	b := &httpBroker{
   121  		id:          uuid.New().String(),
   122  		config:      cfg,
   123  		address:     addr,
   124  		registry:    cfg.Registry,
   125  		client:      &http.Client{Transport: newTransport(cfg.TLSConfig)},
   126  		subscribers: make(map[string][]*httpSubscriber),
   127  		exit:        make(chan chan error),
   128  		//mux:         http.NewServeMux(),
   129  		inbox: make(map[string][][]byte),
   130  	}
   131  	b.started.Store(false)
   132  
   133  	if b.transport == nil {
   134  		b.transport = transport.Default()
   135  		b.transport.Init(
   136  			transport.WithConfigPrefixName(cfg.String()),
   137  		)
   138  	}
   139  
   140  	if b.router == nil {
   141  		b.router = router.New(router.WithConfigPrefixName(cfg.String()))
   142  
   143  		// 注册路由
   144  		b.router.Url("POST", DefaultSubPath, b.Handler)
   145  	}
   146  
   147  	// specify the message handler
   148  	//b.mux.Handle(DefaultSubPath, b)
   149  
   150  	// get optional handlers
   151  	if b.config.Context != nil {
   152  		handlers, ok := b.config.Context.Value("http_handlers").(map[string]http.Handler)
   153  		if ok {
   154  			for pattern, handler := range handlers {
   155  				b.router.Url("POST", pattern, handler)
   156  			}
   157  		}
   158  	}
   159  
   160  	return b
   161  }
   162  
   163  func (self *httpBroker) String() string {
   164  	return self.config.Name
   165  }
   166  
   167  func (self *httpBroker) Init(opts ...broker.Option) error {
   168  	for _, opt := range opts {
   169  		opt(self.config)
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  func (self *httpBroker) Config() *broker.Config {
   176  	return self.config
   177  }
   178  
   179  func (self *httpBroker) Address() string {
   180  	self.RLock()
   181  	defer self.RUnlock()
   182  	return self.address
   183  }
   184  
   185  func (self *httpBroker) Start() error { // 开始阻塞监听
   186  	if self.started.Load().(bool) {
   187  		return nil
   188  	}
   189  
   190  	self.Lock()
   191  	defer self.Unlock()
   192  
   193  	/*
   194  		var l net.Listener
   195  		var err error
   196  
   197  		if self.config.Secure || self.config.TLSConfig != nil {
   198  			config := self.config.TLSConfig
   199  
   200  			fn := func(addr string) (net.Listener, error) {
   201  				if config == nil {
   202  					hosts := []string{addr}
   203  
   204  					// check if its a valid host:port
   205  					if host, _, err := net.SplitHostPort(addr); err == nil {
   206  						if len(host) == 0 {
   207  							hosts = maddr.IPs()
   208  						} else {
   209  							hosts = []string{host}
   210  						}
   211  					}
   212  
   213  					// generate a certificate
   214  					cert, err := vtls.Certificate(hosts...)
   215  					if err != nil {
   216  						return nil, err
   217  					}
   218  					config = &tls.Config{Certificates: []tls.Certificate{cert}}
   219  				}
   220  				return tls.Listen("tcp", addr, config)
   221  			}
   222  
   223  			l, err = vnet.Listen(self.address, fn)
   224  		} else {
   225  			fn := func(addr string) (net.Listener, error) {
   226  				return net.Listen("tcp", addr)
   227  			}
   228  
   229  			l, err = vnet.Listen(self.address, fn)
   230  		}
   231  
   232  		if err != nil {
   233  			return err
   234  		}
   235  
   236  		addr := self.address
   237  		self.address = l.Addr().String()
   238  
   239  		go http.Serve(l, self.router)
   240  		go func() {
   241  			self.run(l)
   242  			self.Lock()
   243  			self.config.Addrs = []string{addr}
   244  			self.address = addr
   245  			self.Unlock()
   246  		}()
   247  	*/
   248  	// start listening on the transport
   249  
   250  	ts, err := self.transport.Listen(self.address)
   251  	if err != nil {
   252  		return err
   253  	}
   254  
   255  	addr := self.address
   256  	self.address = ts.Addr().String()
   257  
   258  	exit := make(chan bool)
   259  
   260  	// 监听链接
   261  	go func() {
   262  		for {
   263  			// listen for connections
   264  			err := ts.Serve(self.router)
   265  
   266  			// TODO: listen for messages
   267  			// msg := broker.Exchange(service).Consume()
   268  
   269  			select {
   270  			// check if we're supposed to exit
   271  			case <-exit:
   272  				return
   273  			// check the error and backoff
   274  			default:
   275  				if err != nil {
   276  					log.Errf("Accept error: %v", err)
   277  
   278  					time.Sleep(time.Second)
   279  					continue
   280  				}
   281  			}
   282  
   283  			// no error just exit
   284  			return
   285  		}
   286  	}()
   287  
   288  	// mark the server as started
   289  	self.started.Store(true)
   290  
   291  	log.Infof("Listening on %s - %s", ts.Addr(), self.transport.String())
   292  
   293  	// 监听退出
   294  	go func() {
   295  		t := new(time.Ticker)
   296  
   297  		// only process if it exists
   298  		if self.config.RegisterInterval > time.Duration(0) {
   299  			// new ticker
   300  			t = time.NewTicker(self.config.RegisterInterval)
   301  		}
   302  
   303  		// return error chan
   304  		var ch chan error
   305  
   306  	Loop:
   307  		for {
   308  			select {
   309  			// register self on interval
   310  			case <-t.C:
   311  				self.RLock()
   312  				for _, subs := range self.subscribers {
   313  					for _, sub := range subs {
   314  						_ = self.registry.Register(sub.svc, registry.RegisterTTL(self.config.RegisterTTL))
   315  					}
   316  				}
   317  				self.RUnlock()
   318  				// received exit signal
   319  			// wait for exit
   320  			case ch = <-self.exit: // 监听来自self.Stop()信号
   321  				self.RLock()
   322  				for _, subs := range self.subscribers {
   323  					for _, sub := range subs {
   324  						_ = self.registry.Deregister(sub.svc)
   325  					}
   326  				}
   327  				self.RUnlock()
   328  
   329  				t.Stop()
   330  				close(exit)
   331  				break Loop
   332  			}
   333  		}
   334  
   335  		//self.Lock()
   336  		//swg := self.wg
   337  		//self.Unlock()
   338  
   339  		// wait for requests to finish
   340  		//if swg != nil {
   341  		//	swg.Wait()
   342  		//}
   343  
   344  		// close transport listener
   345  		ch <- ts.Close()
   346  
   347  		// swap back address
   348  		self.address = addr
   349  	}()
   350  
   351  	// set cache
   352  	//self.r = cache.New(self.config.Registry)
   353  
   354  	// set running
   355  	self.running = true
   356  	return nil
   357  }
   358  
   359  func (self *httpBroker) Close() error {
   360  	self.RLock()
   361  	if !self.running {
   362  		self.RUnlock()
   363  		return nil
   364  	}
   365  	self.RUnlock()
   366  
   367  	self.Lock()
   368  	defer self.Unlock()
   369  
   370  	// stop cache
   371  	rc, ok := self.registry.(cacher.ICacher)
   372  	if ok {
   373  		rc.Stop()
   374  	}
   375  
   376  	// exit and return err
   377  	ch := make(chan error)
   378  	self.exit <- ch
   379  	err := <-ch
   380  
   381  	// set not running
   382  	self.running = false
   383  	return err
   384  }
   385  
   386  func (self *httpBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error {
   387  	var cfg broker.PublishConfig
   388  	for _, opt := range opts {
   389  		opt(&cfg)
   390  	}
   391  
   392  	if cfg.Codec == nil {
   393  		// 验证解码器
   394  		cfg.Codec = codec.IdentifyCodec(cfg.SerializeType)
   395  		if cfg.Codec == nil { // no codec specified
   396  			cfg.Codec = codec.IdentifyCodec(codec.JSON)
   397  			//return fmt.Errorf("no codec specified") // errors.UnsupportedCodec("volts.client", cf)
   398  		}
   399  	}
   400  
   401  	// create the message first
   402  	m := &broker.Message{
   403  		Header: make(map[string]string),
   404  		Body:   message.Body,
   405  	}
   406  
   407  	for k, v := range message.Header {
   408  		m.Header[k] = v
   409  	}
   410  
   411  	m.Header["v-topic"] = topic
   412  
   413  	// encode the message
   414  	body, err := cfg.Codec.Encode(m)
   415  	if err != nil {
   416  		return err
   417  	}
   418  
   419  	// save the message
   420  	self.saveMessage(topic, body)
   421  
   422  	// now attempt to get the service
   423  	self.RLock()
   424  	s, err := self.registry.GetService(self.config.Name)
   425  	if err != nil {
   426  		self.RUnlock()
   427  		return err
   428  	}
   429  	self.RUnlock()
   430  
   431  	pub := func(node *registry.Node, t string, b []byte) error {
   432  		scheme := "http"
   433  
   434  		// check if secure is added in metadata
   435  		if node.Metadata["secure"] == "true" {
   436  			scheme = "https"
   437  		}
   438  
   439  		vals := url.Values{}
   440  		vals.Add("id", node.Id)
   441  
   442  		uri := fmt.Sprintf("%s://%s%s?%s", scheme, node.Address, DefaultSubPath, vals.Encode())
   443  		r, err := self.client.Post(uri, "application/json", bytes.NewReader(b))
   444  		if err != nil {
   445  			return err
   446  		}
   447  
   448  		// discard response body
   449  		io.Copy(ioutil.Discard, r.Body)
   450  		r.Body.Close()
   451  		return nil
   452  	}
   453  
   454  	srv := func(s []*registry.Service, b []byte) {
   455  		for _, service := range s {
   456  			var nodes []*registry.Node
   457  
   458  			for _, node := range service.Nodes {
   459  				// only use nodes tagged with broker http
   460  				if node.Metadata["broker"] != "http" {
   461  					continue
   462  				}
   463  
   464  				// look for nodes for the topic
   465  				if node.Metadata["topic"] != topic {
   466  					continue
   467  				}
   468  
   469  				nodes = append(nodes, node)
   470  			}
   471  
   472  			// only process if we have nodes
   473  			if len(nodes) == 0 {
   474  				continue
   475  			}
   476  
   477  			switch service.Version {
   478  			// broadcast version means broadcast to all nodes
   479  			case broadcastVersion:
   480  				var success bool
   481  
   482  				// publish to all nodes
   483  				for _, node := range nodes {
   484  					// publish async
   485  					if err := pub(node, topic, b); err == nil {
   486  						success = true
   487  					}
   488  				}
   489  
   490  				// save if it failed to publish at least once
   491  				if !success {
   492  					self.saveMessage(topic, b)
   493  				}
   494  			default:
   495  				// select node to publish to
   496  				node := nodes[rand.Int()%len(nodes)]
   497  
   498  				// publish async to one node
   499  				if err := pub(node, topic, b); err != nil {
   500  					// if failed save it
   501  					self.saveMessage(topic, b)
   502  				}
   503  			}
   504  		}
   505  	}
   506  
   507  	// do the rest async
   508  	go func() {
   509  		// get a third of the backlog
   510  		messages := self.getMessage(topic, 8)
   511  		delay := (len(messages) > 1)
   512  
   513  		// publish all the messages
   514  		for _, msg := range messages {
   515  			// serialize here
   516  			srv(s, msg)
   517  
   518  			// sending a backlog of messages
   519  			if delay {
   520  				time.Sleep(time.Millisecond * 100)
   521  			}
   522  		}
   523  	}()
   524  
   525  	return nil
   526  }
   527  
   528  func (self *httpBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.ISubscriber, error) {
   529  	var err error
   530  	var host, port string
   531  	scfg := broker.NewSubscribeOptions(opts...)
   532  
   533  	// parse address for host, port
   534  	host, port, err = net.SplitHostPort(self.Address())
   535  	if err != nil {
   536  		return nil, err
   537  	}
   538  
   539  	addr, err := maddr.Extract(host)
   540  	if err != nil {
   541  		return nil, err
   542  	}
   543  
   544  	var secure bool
   545  
   546  	if self.config.Secure || self.config.TLSConfig != nil {
   547  		secure = true
   548  	}
   549  
   550  	// register service
   551  	node := &registry.Node{
   552  		Id:      topic + "-" + self.id,
   553  		Address: vnet.HostPort(addr, port),
   554  		Metadata: map[string]string{
   555  			"secure": fmt.Sprintf("%t", secure),
   556  			"broker": "http",
   557  			"topic":  topic,
   558  		},
   559  	}
   560  
   561  	// check for queue group or broadcast queue
   562  	version := scfg.Queue
   563  	if len(version) == 0 {
   564  		version = self.config.BroadcastVersion
   565  	}
   566  
   567  	service := &registry.Service{
   568  		Name:    self.config.Name,
   569  		Version: version,
   570  		Nodes:   []*registry.Node{node},
   571  	}
   572  
   573  	// generate subscriber
   574  	subscriber := &httpSubscriber{
   575  		opts:  scfg,
   576  		hb:    self,
   577  		id:    node.Id,
   578  		topic: topic,
   579  		fn:    handler,
   580  		svc:   service,
   581  	}
   582  
   583  	// subscribe now
   584  	if err := self.subscribe(subscriber); err != nil {
   585  		return nil, err
   586  	}
   587  
   588  	// return the subscriber
   589  	return subscriber, nil
   590  }
   591  
   592  func (self *httpBroker) subscribe(s *httpSubscriber) error {
   593  	self.Lock()
   594  	defer self.Unlock()
   595  
   596  	if err := self.registry.Register(s.svc, registry.RegisterTTL(self.config.RegisterTTL)); err != nil {
   597  		return err
   598  	}
   599  
   600  	self.subscribers[s.topic] = append(self.subscribers[s.topic], s)
   601  	return nil
   602  }
   603  
   604  func (h *httpBroker) saveMessage(topic string, msg []byte) {
   605  	h.mtx.Lock()
   606  	defer h.mtx.Unlock()
   607  
   608  	// get messages
   609  	c := h.inbox[topic]
   610  
   611  	// save message
   612  	c = append(c, msg)
   613  
   614  	// max length 64
   615  	if len(c) > 64 {
   616  		c = c[:64]
   617  	}
   618  
   619  	// save inbox
   620  	h.inbox[topic] = c
   621  }
   622  
   623  func (h *httpBroker) getMessage(topic string, num int) [][]byte {
   624  	h.mtx.Lock()
   625  	defer h.mtx.Unlock()
   626  
   627  	// get messages
   628  	c, ok := h.inbox[topic]
   629  	if !ok {
   630  		return nil
   631  	}
   632  
   633  	// more message than requests
   634  	if len(c) >= num {
   635  		msg := c[:num]
   636  		h.inbox[topic] = c[num:]
   637  		return msg
   638  	}
   639  
   640  	// reset inbox
   641  	h.inbox[topic] = nil
   642  
   643  	// return all messages
   644  	return c
   645  }