github.com/bigcommerce/nomad@v0.9.3-bc/client/lib/fifo/fifo_windows.go (about)

     1  package fifo
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"os"
     7  	"sync"
     8  	"time"
     9  
    10  	winio "github.com/Microsoft/go-winio"
    11  )
    12  
    13  // PipeBufferSize is the size of the input and output buffers for the windows
    14  // named pipe
    15  const PipeBufferSize = int32(^uint16(0))
    16  
    17  type winFIFO struct {
    18  	listener net.Listener
    19  	conn     net.Conn
    20  	connLock sync.Mutex
    21  }
    22  
    23  func (f *winFIFO) Read(p []byte) (n int, err error) {
    24  	f.connLock.Lock()
    25  	defer f.connLock.Unlock()
    26  	if f.conn == nil {
    27  		c, err := f.listener.Accept()
    28  		if err != nil {
    29  			return 0, err
    30  		}
    31  
    32  		f.conn = c
    33  	}
    34  
    35  	// If the connection is closed then we need to close the listener
    36  	// to emulate unix fifo behavior
    37  	n, err = f.conn.Read(p)
    38  	if err == io.EOF {
    39  		f.listener.Close()
    40  	}
    41  	return n, err
    42  }
    43  
    44  func (f *winFIFO) Write(p []byte) (n int, err error) {
    45  	f.connLock.Lock()
    46  	defer f.connLock.Unlock()
    47  	if f.conn == nil {
    48  		c, err := f.listener.Accept()
    49  		if err != nil {
    50  			return 0, err
    51  		}
    52  
    53  		f.conn = c
    54  	}
    55  
    56  	// If the connection is closed then we need to close the listener
    57  	// to emulate unix fifo behavior
    58  	n, err = f.conn.Write(p)
    59  	if err == io.EOF {
    60  		f.listener.Close()
    61  	}
    62  	return n, err
    63  
    64  }
    65  
    66  func (f *winFIFO) Close() error {
    67  	return f.listener.Close()
    68  }
    69  
    70  // CreateAndRead creates a fifo at the given path and returns an io.ReadCloser open for it.
    71  // The fifo must not already exist
    72  func CreateAndRead(path string) (func() (io.ReadCloser, error), error) {
    73  	l, err := winio.ListenPipe(path, &winio.PipeConfig{
    74  		InputBufferSize:  PipeBufferSize,
    75  		OutputBufferSize: PipeBufferSize,
    76  	})
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	openFn := func() (io.ReadCloser, error) {
    82  		return &winFIFO{
    83  			listener: l,
    84  		}, nil
    85  	}
    86  
    87  	return openFn, nil
    88  }
    89  
    90  // OpenWriter opens a fifo that already exists and returns an io.WriteCloser for it
    91  func OpenWriter(path string) (io.WriteCloser, error) {
    92  	return winio.DialPipe(path, nil)
    93  }
    94  
    95  // Remove a fifo that already exists at a given path
    96  func Remove(path string) error {
    97  	dur := 500 * time.Millisecond
    98  	conn, err := winio.DialPipe(path, &dur)
    99  	if err == nil {
   100  		return conn.Close()
   101  	}
   102  
   103  	os.Remove(path)
   104  	return nil
   105  }
   106  
   107  func IsClosedErr(err error) bool {
   108  	return err == winio.ErrFileClosed
   109  }