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 }