github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/network/tunnel/broker/broker.go (about)

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