github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/xio/pipe.go (about)

     1  package xio
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  // PipedChan provoider Write buffer to Read implement by chan
    11  type PipedChan struct {
    12  	closed uint32
    13  	having []byte
    14  	locker *sync.Cond
    15  }
    16  
    17  // NewPipedChan will return new PipedChan
    18  func NewPipedChan() (piped *PipedChan) {
    19  	piped = &PipedChan{
    20  		locker: sync.NewCond(&sync.Mutex{}),
    21  	}
    22  	return
    23  }
    24  
    25  func (p *PipedChan) Read(b []byte) (n int, err error) {
    26  	p.locker.L.Lock()
    27  	defer p.locker.L.Unlock()
    28  	if len(p.having) < 1 {
    29  		if p.closed > 0 {
    30  			err = fmt.Errorf("closed")
    31  			return
    32  		}
    33  		p.locker.Wait()
    34  		if len(p.having) < 1 {
    35  			err = fmt.Errorf("closed")
    36  			return
    37  		}
    38  	}
    39  	n = copy(b, p.having)
    40  	p.having = p.having[n:]
    41  	if len(p.having) < 1 {
    42  		p.locker.Signal()
    43  	}
    44  	return
    45  }
    46  
    47  func (p *PipedChan) Write(b []byte) (n int, err error) {
    48  	p.locker.L.Lock()
    49  	defer p.locker.L.Unlock()
    50  	if p.closed < 1 && len(p.having) > 0 {
    51  		p.locker.Wait()
    52  	}
    53  	if p.closed > 0 {
    54  		err = fmt.Errorf("closed")
    55  		return
    56  	}
    57  	if len(p.having) > 0 {
    58  		panic("having")
    59  	}
    60  	p.having = make([]byte, len(b))
    61  	n = copy(p.having, b)
    62  	p.locker.Signal()
    63  	return
    64  }
    65  
    66  // Close will close piped channel
    67  func (p *PipedChan) Close() (err error) {
    68  	p.locker.L.Lock()
    69  	defer p.locker.L.Unlock()
    70  	if p.closed > 0 {
    71  		err = fmt.Errorf("closed")
    72  		return
    73  	}
    74  	p.closed = 1
    75  	p.locker.Broadcast()
    76  	return
    77  }
    78  
    79  // PipeReadWriteCloser is pipe connection
    80  type PipeReadWriteCloser struct {
    81  	Alias  string
    82  	reader *PipedChan
    83  	writer *PipedChan
    84  	side   *PipeReadWriteCloser
    85  }
    86  
    87  // Pipe will return new pipe connection.
    88  func Pipe() (a, b *PipeReadWriteCloser, err error) {
    89  	piperA := NewPipedChan()
    90  	piperB := NewPipedChan()
    91  
    92  	a = &PipeReadWriteCloser{
    93  		reader: piperA,
    94  		writer: piperB,
    95  		Alias:  "piped",
    96  	}
    97  	b = &PipeReadWriteCloser{
    98  		reader: piperB,
    99  		writer: piperA,
   100  		Alias:  "piped",
   101  	}
   102  	a.side = b
   103  	b.side = a
   104  	return
   105  }
   106  
   107  func (p *PipeReadWriteCloser) Read(b []byte) (n int, err error) {
   108  	n, err = p.reader.Read(b)
   109  	return
   110  }
   111  
   112  func (p *PipeReadWriteCloser) Write(b []byte) (n int, err error) {
   113  	n, err = p.writer.Write(b)
   114  	return
   115  }
   116  
   117  // Close will close reader/writer
   118  func (p *PipeReadWriteCloser) Close() (err error) {
   119  	p.reader.Close()
   120  	p.writer.Close()
   121  	p.side.reader.Close()
   122  	p.side.writer.Close()
   123  	return
   124  }
   125  
   126  func (p *PipeReadWriteCloser) String() string {
   127  	return p.Alias
   128  }
   129  
   130  // PipedConn is an implementation of the net.Conn interface for piped two connection.
   131  type PipedConn struct {
   132  	*PipeReadWriteCloser
   133  }
   134  
   135  // CreatePipedConn will return two piped connection.
   136  func CreatePipedConn() (a, b *PipedConn, err error) {
   137  	basea, baseb, err := Pipe()
   138  	if err == nil {
   139  		a = &PipedConn{PipeReadWriteCloser: basea}
   140  		b = &PipedConn{PipeReadWriteCloser: baseb}
   141  	}
   142  	return
   143  }
   144  
   145  // LocalAddr return self
   146  func (p *PipedConn) LocalAddr() net.Addr {
   147  	return p
   148  }
   149  
   150  // RemoteAddr return self
   151  func (p *PipedConn) RemoteAddr() net.Addr {
   152  	return p
   153  }
   154  
   155  // SetDeadline is empty
   156  func (p *PipedConn) SetDeadline(t time.Time) error {
   157  	return nil
   158  }
   159  
   160  // SetReadDeadline is empty
   161  func (p *PipedConn) SetReadDeadline(t time.Time) error {
   162  	return nil
   163  }
   164  
   165  // SetWriteDeadline is empty
   166  func (p *PipedConn) SetWriteDeadline(t time.Time) error {
   167  	return nil
   168  }
   169  
   170  // Network return "piped"
   171  func (p *PipedConn) Network() string {
   172  	return "piped"
   173  }
   174  
   175  func (p *PipedConn) String() string {
   176  	return p.PipeReadWriteCloser.String()
   177  }
   178  
   179  type PipedListener struct {
   180  	queue chan *PipedConn
   181  }
   182  
   183  func NewPipedListener() (listener *PipedListener) {
   184  	listener = &PipedListener{
   185  		queue: make(chan *PipedConn, 8),
   186  	}
   187  	return
   188  }
   189  
   190  func (p *PipedListener) Dial() (conn net.Conn, err error) {
   191  	conna, connb, err := CreatePipedConn()
   192  	if err == nil {
   193  		p.queue <- conna
   194  		conn = connb
   195  	}
   196  	return
   197  }
   198  
   199  func (p *PipedListener) Accept() (conn net.Conn, err error) {
   200  	c := <-p.queue
   201  	if c == nil {
   202  		err = fmt.Errorf("closed")
   203  	} else {
   204  		conn = c
   205  	}
   206  	return
   207  }
   208  
   209  func (p *PipedListener) Close() (err error) {
   210  	p.queue <- nil
   211  	return
   212  }
   213  
   214  func (p *PipedListener) Addr() net.Addr {
   215  	return p
   216  }
   217  
   218  // Network return "piped"
   219  func (p *PipedListener) Network() string {
   220  	return "piped"
   221  }
   222  
   223  func (p *PipedListener) String() string {
   224  	return fmt.Sprintf("%p", p)
   225  }