github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/xio/xio.go (about) 1 package xio 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "reflect" 8 "time" 9 10 "golang.org/x/net/websocket" 11 ) 12 13 func CopyPacketConn(dst interface{}, src net.PacketConn) (l int64, err error) { 14 buffer := make([]byte, 2*1024) 15 for { 16 n, from, xerr := src.ReadFrom(buffer) 17 if xerr != nil { 18 err = xerr 19 break 20 } 21 if out, ok := dst.(net.PacketConn); ok { 22 n, xerr = out.WriteTo(buffer[0:n], from) 23 } else if out, ok := dst.(io.Writer); ok { 24 n, xerr = out.Write(buffer[0:n]) 25 } else { 26 xerr = fmt.Errorf("not supported dst by type %v", reflect.TypeOf(dst)) 27 } 28 if xerr != nil { 29 err = xerr 30 break 31 } 32 l += int64(n) 33 } 34 return 35 } 36 37 func CopyPacketTo(dst net.PacketConn, to net.Addr, src io.Reader) (l int64, err error) { 38 buffer := make([]byte, 2*1024) 39 for { 40 n, xerr := src.Read(buffer) 41 if xerr != nil { 42 err = xerr 43 break 44 } 45 n, xerr = dst.WriteTo(buffer[0:n], to) 46 if xerr != nil { 47 err = xerr 48 break 49 } 50 l += int64(n) 51 } 52 return 53 } 54 55 // CopyMulti will copy data from Reader and write to multi Writer at the same time 56 func CopyMulti(dst []io.Writer, src io.Reader) (written int64, err error) { 57 written, err = CopyBufferMulti(dst, src, nil) 58 return 59 } 60 61 // CopyBufferMulti will copy data from Reader and write to multi Writer at the same time 62 func CopyBufferMulti(dst []io.Writer, src io.Reader, buf []byte) (written int64, err error) { 63 if buf == nil { 64 size := 32 * 1024 65 buf = make([]byte, size) 66 } 67 write := func(nr int, b []byte) (nw int, err error) { 68 for _, d := range dst { 69 nw, err = d.Write(b) 70 if err != nil { 71 break 72 } 73 if nr != nw { 74 err = io.ErrShortWrite 75 break 76 } 77 } 78 return 79 } 80 for { 81 nr, er := src.Read(buf) 82 if nr > 0 { 83 nw, ew := write(nr, buf[0:nr]) 84 if nw > 0 { 85 written += int64(nw) 86 } 87 if ew != nil { 88 err = ew 89 break 90 } 91 } 92 if er != nil { 93 if er != io.EOF { 94 err = er 95 } 96 break 97 } 98 } 99 return written, err 100 } 101 102 // CopyMax will copy data to writer and total limit by max 103 func CopyMax(dst io.Writer, src io.Reader, max int64) (written int64, err error) { 104 written, err = CopyBufferMax(dst, src, max, nil) 105 return 106 } 107 108 // CopyBufferMax will copy data to writer and total limit by max 109 func CopyBufferMax(dst io.Writer, src io.Reader, max int64, buf []byte) (written int64, err error) { 110 if buf == nil { 111 size := 32 * 1024 112 buf = make([]byte, size) 113 } 114 for { 115 limited := max - written 116 if limited < 1 { 117 err = fmt.Errorf("copy max limit") 118 break 119 } 120 if limited > int64(len(buf)) { 121 limited = int64(len(buf)) 122 } 123 nr, er := src.Read(buf[0:limited]) 124 if nr > 0 { 125 nw, ew := dst.Write(buf[0:nr]) 126 if nw > 0 { 127 written += int64(nw) 128 } 129 if ew != nil { 130 err = ew 131 break 132 } 133 if nr != nw { 134 err = io.ErrShortWrite 135 break 136 } 137 } 138 if er != nil { 139 if er != io.EOF { 140 err = er 141 } 142 break 143 } 144 } 145 return written, err 146 } 147 148 // FullBuffer will read data from reader until to buffer 149 func FullBuffer(r io.Reader, buffer []byte, length uint32, latest *time.Time) error { 150 all := uint32(0) 151 buf := buffer[:length] 152 for { 153 readed, err := r.Read(buf) 154 if err != nil { 155 return err 156 } 157 if latest != nil { 158 *latest = time.Now() 159 } 160 all += uint32(readed) 161 if all < length { 162 buf = buffer[all:length] 163 continue 164 } else { 165 break 166 } 167 } 168 return nil 169 } 170 171 // CopyBuffer will copy data and call dst Closer after done 172 func CopyBuffer(dst io.WriteCloser, src io.Reader, buf []byte) (n int64, err error) { 173 n, err = io.CopyBuffer(dst, src, buf) 174 dst.Close() 175 return 176 } 177 178 // StringConn is an ReadWriteCloser for return remote address info 179 type StringConn struct { 180 Name string 181 io.ReadWriteCloser 182 } 183 184 // NewStringConn will return new StringConn 185 func NewStringConn(raw io.ReadWriteCloser) *StringConn { 186 return &StringConn{ 187 ReadWriteCloser: raw, 188 } 189 } 190 191 func (s *StringConn) String() string { 192 if len(s.Name) > 0 { 193 return s.Name 194 } 195 return remoteAddr(s.ReadWriteCloser) 196 } 197 198 func remoteAddr(v interface{}) string { 199 if netc, ok := v.(net.Conn); ok { 200 return fmt.Sprintf("%v", netc.RemoteAddr()) 201 } 202 return fmt.Sprintf("%v", v) 203 } 204 205 // TCPKeepAliveListener is normal tcp listner for set tcp connection keep alive 206 type TCPKeepAliveListener struct { 207 *net.TCPListener 208 Period time.Duration 209 } 210 211 // NewTCPKeepAliveListener will create listener 212 func NewTCPKeepAliveListener(l *net.TCPListener) (listener *TCPKeepAliveListener) { 213 listener = &TCPKeepAliveListener{ 214 TCPListener: l, 215 Period: time.Minute, 216 } 217 return 218 } 219 220 // Accept will accept one connection 221 func (ln TCPKeepAliveListener) Accept() (net.Conn, error) { 222 tc, err := ln.AcceptTCP() 223 if err == nil { 224 tc.SetKeepAlive(true) 225 tc.SetKeepAlivePeriod(ln.Period) 226 } 227 return tc, err 228 } 229 230 // ListenerF is net.Listener func implement 231 type ListenerF func() (conn net.Conn, err error) 232 233 // Accept is net.Listener implement 234 func (l ListenerF) Accept() (conn net.Conn, err error) { 235 conn, err = l() 236 return 237 } 238 239 // Close is net.Listener implement 240 func (l ListenerF) Close() (err error) { 241 return 242 } 243 244 // Addr is net.Listener implement 245 func (l ListenerF) Addr() net.Addr { 246 return nil 247 } 248 249 // Network is net.Addr implement 250 func (l ListenerF) Network() string { 251 return "func" 252 } 253 254 func (l ListenerF) String() string { 255 return reflect.TypeOf(l).PkgPath() 256 } 257 258 // LocalAddr will return net.Conn.LocalAddr or fmt.Sprintf("%v", target) 259 func LocalAddr(target interface{}) string { 260 if conn, ok := target.(*websocket.Conn); ok { 261 return conn.LocalAddr().String() 262 } 263 if conn, ok := target.(net.Conn); ok { 264 return conn.LocalAddr().String() 265 } 266 return fmt.Sprintf("%v", target) 267 } 268 269 // RemoteAddr will return net.Conn.RemoteAddr or fmt.Sprintf("%v", target) 270 func RemoteAddr(target interface{}) string { 271 if conn, ok := target.(*websocket.Conn); ok { 272 return conn.Request().RemoteAddr 273 } 274 if conn, ok := target.(net.Conn); ok { 275 return conn.RemoteAddr().String() 276 } 277 return fmt.Sprintf("%v", target) 278 }