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  }