github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/lib/fifo/fifo_windows.go (about)

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