Skip to content

Instantly share code, notes, and snippets.

@andyollylarkin
Created August 22, 2023 07:06
Show Gist options
  • Save andyollylarkin/28f52255ba79831c34a6b54a82b53c66 to your computer and use it in GitHub Desktop.
Save andyollylarkin/28f52255ba79831c34a6b54a82b53c66 to your computer and use it in GitHub Desktop.
golang reader that continue reads when socket timeout exceeded
type TimeoutReader struct {
r ReadDeadliner
extendReadDeadline time.Duration
}
// Return reader that reads from r. If i/o timeout exceeded reader continue read.
// If another error occurs reader return that error.
func NewTimeoutReader(r ReadDeadliner, extendReadDeadline time.Duration) *TimeoutReader {
tr := new(TimeoutReader)
tr.r = r
tr.extendReadDeadline = extendReadDeadline
return tr
}
func (tr *TimeoutReader) ReadBytes(delim byte) ([]byte, error) {
var out bytes.Buffer
var bufSize int = 1
buf := make([]byte, bufSize)
for {
n, err := tr.r.Read(buf)
// if has error and no read bytes
if err != nil && n == 0 {
return out.Bytes(), err
}
if err != nil && n > 0 {
e, ok := err.(*net.OpError)
if ok && strings.Contains(e.Error(), "i/o timeout") {
tr.r.SetReadDeadline(time.Now().Add(tr.extendReadDeadline))
out.Write(buf)
cleanSlice(buf)
continue
} else {
out.Write(buf)
return out.Bytes(), e
}
}
pos := bytes.IndexByte(buf, delim)
if pos == -1 {
out.Write(buf)
cleanSlice(buf)
continue
} else {
out.Write(buf[0 : pos+1])
break
}
}
return out.Bytes(), nil
}
func (tr *TimeoutReader) Read(p []byte) (int, error) {
return tr.r.Read(p)
}
func cleanSlice(src []byte) {
tmp := make([]byte, len(src))
copy(src, tmp)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment