io.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package buf
  2. import (
  3. "io"
  4. "syscall"
  5. "time"
  6. )
  7. // Reader extends io.Reader with MultiBuffer.
  8. type Reader interface {
  9. // ReadMultiBuffer reads content from underlying reader, and put it into a MultiBuffer.
  10. ReadMultiBuffer() (MultiBuffer, error)
  11. }
  12. // ErrReadTimeout is an error that happens with IO timeout.
  13. var ErrReadTimeout = newError("IO timeout")
  14. // TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
  15. type TimeoutReader interface {
  16. ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
  17. }
  18. // Writer extends io.Writer with MultiBuffer.
  19. type Writer interface {
  20. // WriteMultiBuffer writes a MultiBuffer into underlying writer.
  21. WriteMultiBuffer(MultiBuffer) error
  22. }
  23. // WriteAllBytes ensures all bytes are written into the given writer.
  24. func WriteAllBytes(writer io.Writer, payload []byte) error {
  25. for len(payload) > 0 {
  26. n, err := writer.Write(payload)
  27. if err != nil {
  28. return err
  29. }
  30. payload = payload[n:]
  31. }
  32. return nil
  33. }
  34. // NewReader creates a new Reader.
  35. // The Reader instance doesn't take the ownership of reader.
  36. func NewReader(reader io.Reader) Reader {
  37. if mr, ok := reader.(Reader); ok {
  38. return mr
  39. }
  40. if useReadv {
  41. if sc, ok := reader.(syscall.Conn); ok {
  42. rawConn, err := sc.SyscallConn()
  43. if err != nil {
  44. newError("failed to get sysconn").Base(err).WriteToLog()
  45. } else {
  46. return NewReadVReader(reader, rawConn)
  47. }
  48. }
  49. }
  50. return &SingleReader{
  51. Reader: reader,
  52. }
  53. }
  54. // NewWriter creates a new Writer.
  55. func NewWriter(writer io.Writer) Writer {
  56. if mw, ok := writer.(Writer); ok {
  57. return mw
  58. }
  59. if _, ok := writer.(syscall.Conn); !ok {
  60. // If the writer doesn't implement syscall.Conn, it is probably not a TCP connection.
  61. return &SequentialWriter{
  62. Writer: writer,
  63. }
  64. }
  65. return &BufferToBytesWriter{
  66. Writer: writer,
  67. }
  68. }