github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/app/metrics/outbound.go (about) 1 package metrics 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/xmplusdev/xmcore/common" 8 "github.com/xmplusdev/xmcore/common/net" 9 "github.com/xmplusdev/xmcore/common/net/cnc" 10 "github.com/xmplusdev/xmcore/common/signal/done" 11 "github.com/xmplusdev/xmcore/transport" 12 ) 13 14 // OutboundListener is a net.Listener for listening metrics http connections. 15 type OutboundListener struct { 16 buffer chan net.Conn 17 done *done.Instance 18 } 19 20 func (l *OutboundListener) add(conn net.Conn) { 21 select { 22 case l.buffer <- conn: 23 case <-l.done.Wait(): 24 conn.Close() 25 default: 26 conn.Close() 27 } 28 } 29 30 // Accept implements net.Listener. 31 func (l *OutboundListener) Accept() (net.Conn, error) { 32 select { 33 case <-l.done.Wait(): 34 return nil, newError("listen closed") 35 case c := <-l.buffer: 36 return c, nil 37 } 38 } 39 40 // Close implement net.Listener. 41 func (l *OutboundListener) Close() error { 42 common.Must(l.done.Close()) 43 L: 44 for { 45 select { 46 case c := <-l.buffer: 47 c.Close() 48 default: 49 break L 50 } 51 } 52 return nil 53 } 54 55 // Addr implements net.Listener. 56 func (l *OutboundListener) Addr() net.Addr { 57 return &net.TCPAddr{ 58 IP: net.IP{0, 0, 0, 0}, 59 Port: 0, 60 } 61 } 62 63 // Outbound is an outbound.Handler that handles metrics http connections. 64 type Outbound struct { 65 tag string 66 listener *OutboundListener 67 access sync.RWMutex 68 closed bool 69 } 70 71 // Dispatch implements outbound.Handler. 72 func (co *Outbound) Dispatch(ctx context.Context, link *transport.Link) { 73 co.access.RLock() 74 75 if co.closed { 76 common.Interrupt(link.Reader) 77 common.Interrupt(link.Writer) 78 co.access.RUnlock() 79 return 80 } 81 82 closeSignal := done.New() 83 c := cnc.NewConnection(cnc.ConnectionInputMulti(link.Writer), cnc.ConnectionOutputMulti(link.Reader), cnc.ConnectionOnClose(closeSignal)) 84 co.listener.add(c) 85 co.access.RUnlock() 86 <-closeSignal.Wait() 87 } 88 89 // Tag implements outbound.Handler. 90 func (co *Outbound) Tag() string { 91 return co.tag 92 } 93 94 // Start implements common.Runnable. 95 func (co *Outbound) Start() error { 96 co.access.Lock() 97 co.closed = false 98 co.access.Unlock() 99 return nil 100 } 101 102 // Close implements common.Closable. 103 func (co *Outbound) Close() error { 104 co.access.Lock() 105 defer co.access.Unlock() 106 107 co.closed = true 108 return co.listener.Close() 109 }