github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/network/transport/memory/memory.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/transport/memory/memory.go
    14  
    15  // Package memory is an in-memory transport
    16  package memory
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"fmt"
    22  	"math/rand"
    23  	"net"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/tickoalcantara12/micro/v3/service/network/transport"
    28  	maddr "github.com/tickoalcantara12/micro/v3/util/addr"
    29  	mnet "github.com/tickoalcantara12/micro/v3/util/net"
    30  )
    31  
    32  type memorySocket struct {
    33  	recv chan *transport.Message
    34  	send chan *transport.Message
    35  	// sock exit
    36  	exit chan bool
    37  	// listener exit
    38  	lexit chan bool
    39  
    40  	local  string
    41  	remote string
    42  
    43  	// for send/recv transport.Timeout
    44  	timeout time.Duration
    45  	ctx     context.Context
    46  	sync.RWMutex
    47  }
    48  
    49  type memoryClient struct {
    50  	*memorySocket
    51  	opts transport.DialOptions
    52  }
    53  
    54  type memoryListener struct {
    55  	addr  string
    56  	exit  chan bool
    57  	conn  chan *memorySocket
    58  	lopts transport.ListenOptions
    59  	topts transport.Options
    60  	sync.RWMutex
    61  	ctx context.Context
    62  }
    63  
    64  type memoryTransport struct {
    65  	opts transport.Options
    66  	sync.RWMutex
    67  	listeners map[string]*memoryListener
    68  }
    69  
    70  func (ms *memorySocket) Recv(m *transport.Message) error {
    71  	ms.RLock()
    72  	defer ms.RUnlock()
    73  
    74  	ctx := ms.ctx
    75  	if ms.timeout > 0 {
    76  		var cancel context.CancelFunc
    77  		ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout)
    78  		defer cancel()
    79  	}
    80  
    81  	select {
    82  	case <-ctx.Done():
    83  		return ctx.Err()
    84  	case <-ms.exit:
    85  		return errors.New("connection closed")
    86  	case <-ms.lexit:
    87  		return errors.New("server connection closed")
    88  	case cm := <-ms.recv:
    89  		*m = *cm
    90  	}
    91  	return nil
    92  }
    93  
    94  func (ms *memorySocket) Local() string {
    95  	return ms.local
    96  }
    97  
    98  func (ms *memorySocket) Remote() string {
    99  	return ms.remote
   100  }
   101  
   102  func (ms *memorySocket) Send(m *transport.Message) error {
   103  	ms.RLock()
   104  	defer ms.RUnlock()
   105  
   106  	ctx := ms.ctx
   107  	if ms.timeout > 0 {
   108  		var cancel context.CancelFunc
   109  		ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout)
   110  		defer cancel()
   111  	}
   112  
   113  	select {
   114  	case <-ctx.Done():
   115  		return ctx.Err()
   116  	case <-ms.exit:
   117  		return errors.New("connection closed")
   118  	case <-ms.lexit:
   119  		return errors.New("server connection closed")
   120  	case ms.send <- m:
   121  	}
   122  	return nil
   123  }
   124  
   125  func (ms *memorySocket) Close() error {
   126  	ms.Lock()
   127  	defer ms.Unlock()
   128  	select {
   129  	case <-ms.exit:
   130  		return nil
   131  	default:
   132  		close(ms.exit)
   133  	}
   134  	return nil
   135  }
   136  
   137  func (m *memoryListener) Addr() string {
   138  	return m.addr
   139  }
   140  
   141  func (m *memoryListener) Close() error {
   142  	m.Lock()
   143  	defer m.Unlock()
   144  	select {
   145  	case <-m.exit:
   146  		return nil
   147  	default:
   148  		close(m.exit)
   149  	}
   150  	return nil
   151  }
   152  
   153  func (m *memoryListener) Accept(fn func(transport.Socket)) error {
   154  	for {
   155  		select {
   156  		case <-m.exit:
   157  			return nil
   158  		case c := <-m.conn:
   159  			go fn(&memorySocket{
   160  				lexit:   c.lexit,
   161  				exit:    c.exit,
   162  				send:    c.recv,
   163  				recv:    c.send,
   164  				local:   c.Remote(),
   165  				remote:  c.Local(),
   166  				timeout: m.topts.Timeout,
   167  				ctx:     m.topts.Context,
   168  			})
   169  		}
   170  	}
   171  }
   172  
   173  func (m *memoryTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
   174  	m.RLock()
   175  	defer m.RUnlock()
   176  
   177  	listener, ok := m.listeners[addr]
   178  	if !ok {
   179  		return nil, errors.New("could not dial " + addr)
   180  	}
   181  
   182  	var options transport.DialOptions
   183  	for _, o := range opts {
   184  		o(&options)
   185  	}
   186  
   187  	client := &memoryClient{
   188  		&memorySocket{
   189  			send:    make(chan *transport.Message),
   190  			recv:    make(chan *transport.Message),
   191  			exit:    make(chan bool),
   192  			lexit:   listener.exit,
   193  			local:   addr,
   194  			remote:  addr,
   195  			timeout: m.opts.Timeout,
   196  			ctx:     m.opts.Context,
   197  		},
   198  		options,
   199  	}
   200  
   201  	// pseudo connect
   202  	select {
   203  	case <-listener.exit:
   204  		return nil, errors.New("connection error")
   205  	case listener.conn <- client.memorySocket:
   206  	}
   207  
   208  	return client, nil
   209  }
   210  
   211  func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
   212  	m.Lock()
   213  	defer m.Unlock()
   214  
   215  	var options transport.ListenOptions
   216  	for _, o := range opts {
   217  		o(&options)
   218  	}
   219  
   220  	host, port, err := net.SplitHostPort(addr)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	addr, err = maddr.Extract(host)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  
   230  	// if zero port then randomly assign one
   231  	if len(port) > 0 && port == "0" {
   232  		i := rand.Intn(20000)
   233  		port = fmt.Sprintf("%d", 10000+i)
   234  	}
   235  
   236  	// set addr with port
   237  	addr = mnet.HostPort(addr, port)
   238  
   239  	if _, ok := m.listeners[addr]; ok {
   240  		return nil, errors.New("already listening on " + addr)
   241  	}
   242  
   243  	listener := &memoryListener{
   244  		lopts: options,
   245  		topts: m.opts,
   246  		addr:  addr,
   247  		conn:  make(chan *memorySocket),
   248  		exit:  make(chan bool),
   249  		ctx:   m.opts.Context,
   250  	}
   251  
   252  	m.listeners[addr] = listener
   253  
   254  	return listener, nil
   255  }
   256  
   257  func (m *memoryTransport) Init(opts ...transport.Option) error {
   258  	for _, o := range opts {
   259  		o(&m.opts)
   260  	}
   261  	return nil
   262  }
   263  
   264  func (m *memoryTransport) Options() transport.Options {
   265  	return m.opts
   266  }
   267  
   268  func (m *memoryTransport) String() string {
   269  	return "memory"
   270  }
   271  
   272  func NewTransport(opts ...transport.Option) transport.Transport {
   273  	var options transport.Options
   274  
   275  	rand.Seed(time.Now().UnixNano())
   276  
   277  	for _, o := range opts {
   278  		o(&options)
   279  	}
   280  
   281  	if options.Context == nil {
   282  		options.Context = context.Background()
   283  	}
   284  
   285  	return &memoryTransport{
   286  		opts:      options,
   287  		listeners: make(map[string]*memoryListener),
   288  	}
   289  }