gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/tunnel/broker/broker.go (about)

     1  // Package broker is a tunnel broker
     2  package broker
     3  
     4  import (
     5  	"context"
     6  
     7  	"gitee.com/liuxuezhan/go-micro-v1.18.0/broker"
     8  	"gitee.com/liuxuezhan/go-micro-v1.18.0/transport"
     9  	"gitee.com/liuxuezhan/go-micro-v1.18.0/tunnel"
    10  )
    11  
    12  type tunBroker struct {
    13  	opts   broker.Options
    14  	tunnel tunnel.Tunnel
    15  }
    16  
    17  type tunSubscriber struct {
    18  	topic   string
    19  	handler broker.Handler
    20  	opts    broker.SubscribeOptions
    21  
    22  	closed   chan bool
    23  	listener tunnel.Listener
    24  }
    25  
    26  type tunEvent struct {
    27  	topic   string
    28  	message *broker.Message
    29  }
    30  
    31  // used to access tunnel from options context
    32  type tunnelKey struct{}
    33  type tunnelAddr struct{}
    34  
    35  func (t *tunBroker) Init(opts ...broker.Option) error {
    36  	for _, o := range opts {
    37  		o(&t.opts)
    38  	}
    39  	return nil
    40  }
    41  
    42  func (t *tunBroker) Options() broker.Options {
    43  	return t.opts
    44  }
    45  
    46  func (t *tunBroker) Address() string {
    47  	return t.tunnel.Address()
    48  }
    49  
    50  func (t *tunBroker) Connect() error {
    51  	return t.tunnel.Connect()
    52  }
    53  
    54  func (t *tunBroker) Disconnect() error {
    55  	return t.tunnel.Close()
    56  }
    57  
    58  func (t *tunBroker) Publish(topic string, m *broker.Message, opts ...broker.PublishOption) error {
    59  	// TODO: this is probably inefficient, we might want to just maintain an open connection
    60  	// it may be easier to add broadcast to the tunnel
    61  	c, err := t.tunnel.Dial(topic, tunnel.DialMode(tunnel.Multicast))
    62  	if err != nil {
    63  		return err
    64  	}
    65  	defer c.Close()
    66  
    67  	return c.Send(&transport.Message{
    68  		Header: m.Header,
    69  		Body:   m.Body,
    70  	})
    71  }
    72  
    73  func (t *tunBroker) Subscribe(topic string, h broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
    74  	l, err := t.tunnel.Listen(topic, tunnel.ListenMode(tunnel.Multicast))
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	var options broker.SubscribeOptions
    80  	for _, o := range opts {
    81  		o(&options)
    82  	}
    83  
    84  	tunSub := &tunSubscriber{
    85  		topic:    topic,
    86  		handler:  h,
    87  		opts:     options,
    88  		closed:   make(chan bool),
    89  		listener: l,
    90  	}
    91  
    92  	// start processing
    93  	go tunSub.run()
    94  
    95  	return tunSub, nil
    96  }
    97  
    98  func (t *tunBroker) String() string {
    99  	return "tunnel"
   100  }
   101  
   102  func (t *tunSubscriber) run() {
   103  	for {
   104  		// accept a new connection
   105  		c, err := t.listener.Accept()
   106  		if err != nil {
   107  			select {
   108  			case <-t.closed:
   109  				return
   110  			default:
   111  				continue
   112  			}
   113  		}
   114  
   115  		// receive message
   116  		m := new(transport.Message)
   117  		if err := c.Recv(m); err != nil {
   118  			c.Close()
   119  			continue
   120  		}
   121  
   122  		// close the connection
   123  		c.Close()
   124  
   125  		// handle the message
   126  		go t.handler(&tunEvent{
   127  			topic: t.topic,
   128  			message: &broker.Message{
   129  				Header: m.Header,
   130  				Body:   m.Body,
   131  			},
   132  		})
   133  	}
   134  }
   135  
   136  func (t *tunSubscriber) Options() broker.SubscribeOptions {
   137  	return t.opts
   138  }
   139  
   140  func (t *tunSubscriber) Topic() string {
   141  	return t.topic
   142  }
   143  
   144  func (t *tunSubscriber) Unsubscribe() error {
   145  	select {
   146  	case <-t.closed:
   147  		return nil
   148  	default:
   149  		close(t.closed)
   150  		return t.listener.Close()
   151  	}
   152  }
   153  
   154  func (t *tunEvent) Topic() string {
   155  	return t.topic
   156  }
   157  
   158  func (t *tunEvent) Message() *broker.Message {
   159  	return t.message
   160  }
   161  
   162  func (t *tunEvent) Ack() error {
   163  	return nil
   164  }
   165  
   166  func NewBroker(opts ...broker.Option) broker.Broker {
   167  	options := broker.Options{
   168  		Context: context.Background(),
   169  	}
   170  	for _, o := range opts {
   171  		o(&options)
   172  	}
   173  	t, ok := options.Context.Value(tunnelKey{}).(tunnel.Tunnel)
   174  	if !ok {
   175  		t = tunnel.NewTunnel()
   176  	}
   177  
   178  	a, ok := options.Context.Value(tunnelAddr{}).(string)
   179  	if ok {
   180  		// initialise address
   181  		t.Init(tunnel.Address(a))
   182  	}
   183  
   184  	if len(options.Addrs) > 0 {
   185  		// initialise nodes
   186  		t.Init(tunnel.Nodes(options.Addrs...))
   187  	}
   188  
   189  	return &tunBroker{
   190  		opts:   options,
   191  		tunnel: t,
   192  	}
   193  }
   194  
   195  // WithAddress sets the tunnel address
   196  func WithAddress(a string) broker.Option {
   197  	return func(o *broker.Options) {
   198  		if o.Context == nil {
   199  			o.Context = context.Background()
   200  		}
   201  		o.Context = context.WithValue(o.Context, tunnelAddr{}, a)
   202  	}
   203  }
   204  
   205  // WithTunnel sets the internal tunnel
   206  func WithTunnel(t tunnel.Tunnel) broker.Option {
   207  	return func(o *broker.Options) {
   208  		if o.Context == nil {
   209  			o.Context = context.Background()
   210  		}
   211  		o.Context = context.WithValue(o.Context, tunnelKey{}, t)
   212  	}
   213  }