gitee.com/sasukebo/go-micro/v4@v4.7.1/transport/memory.go (about)

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