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 }