1 // Package ioconn allows any combination of an io.Reader, io.Writer and io.Closer to become a net.Conn. 2 package ioconn // import "vimagination.zapto.org/ioconn" 3 4 import ( 5 "cmp" 6 "errors" 7 "io" 8 "net" 9 "time" 10 ) 11 12 // CloserFunc is a func that implements the io.Closer interface allowing a 13 // closure or other function to be io.Closer. 14 type CloserFunc func() error 15 16 // Close simply calls the CloserFunc func. 17 func (c CloserFunc) Close() error { 18 return c() 19 } 20 21 // FileAddr is a net.Addr that represents a file. Should be a full path. 22 type FileAddr string 23 24 // Network always returns "file". 25 func (f FileAddr) Network() string { 26 return "file" 27 } 28 29 // String returns file://path. 30 func (f FileAddr) String() string { 31 return "file://" + string(f) 32 } 33 34 // Addr is a simple implementation of the net.Addr interface. 35 type Addr struct { 36 Net, Str string 37 } 38 39 // Network returns the Net string. 40 func (a Addr) Network() string { 41 return a.Net 42 } 43 44 // String returns the Str string. 45 func (a Addr) String() string { 46 return a.Str 47 } 48 49 // Conn implements a net.Conn. 50 type Conn struct { 51 io.Reader 52 io.Writer 53 io.Closer 54 Local, Remote net.Addr 55 ReadDeadline, WriteDeadline time.Time 56 } 57 58 // Read implements the io.Reader interface. 59 func (c *Conn) Read(p []byte) (int, error) { 60 if !c.ReadDeadline.IsZero() && time.Now().After(c.ReadDeadline) { 61 return 0, ErrTimeout 62 } 63 64 return c.Reader.Read(p) 65 } 66 67 // Write implements the io.Writer interface. 68 func (c *Conn) Write(p []byte) (int, error) { 69 if !c.ReadDeadline.IsZero() && time.Now().After(c.WriteDeadline) { 70 return 0, ErrTimeout 71 } 72 73 return c.Writer.Write(p) 74 } 75 76 // LocalAddr returns the Local Address. 77 func (c *Conn) LocalAddr() net.Addr { 78 return c.Local 79 } 80 81 // RemoteAddr returns the Remote Address. 82 func (c *Conn) RemoteAddr() net.Addr { 83 return c.Remote 84 } 85 86 // SetDeadline implements the Conn SetDeadline method. 87 func (c *Conn) SetDeadline(t time.Time) error { 88 return cmp.Or(c.SetReadDeadline(t), c.SetWriteDeadline(t)) 89 } 90 91 // SetReadDeadline implements the Conn SetReadDeadline method. 92 func (c *Conn) SetReadDeadline(t time.Time) error { 93 c.ReadDeadline = t 94 95 if rd, ok := c.Reader.(interface { 96 SetReadDeadline(time.Time) error 97 }); ok { 98 return rd.SetReadDeadline(t) 99 } 100 101 return nil 102 } 103 104 // SetWriteDeadline implements the Conn SetWriteDeadline method. 105 func (c *Conn) SetWriteDeadline(t time.Time) error { 106 c.WriteDeadline = t 107 108 if wd, ok := c.Writer.(interface { 109 SetWriteDeadline(time.Time) error 110 }); ok { 111 return wd.SetWriteDeadline(t) 112 } 113 114 return nil 115 } 116 117 // Errors. 118 var ( 119 ErrTimeout = errors.New("timeout occurred") 120 ) 121