diff options
author | 2022-12-21 11:17:43 +0100 | |
---|---|---|
committer | 2022-12-21 11:17:43 +0100 | |
commit | 6ebdc306edd9b1ee0d853bdad63c0fb418382eb7 (patch) | |
tree | e2e2e5262af41cbeea7dd716e9cdc53092078200 /internal/iotools | |
parent | [chore] note broken go v1.19.4 in contributing.md (#1278) (diff) | |
download | gotosocial-6ebdc306edd9b1ee0d853bdad63c0fb418382eb7.tar.xz |
[bugfix] Close reader gracefully when streaming recache of remote media to fileserver api caller (#1281)
* close pipereader on failed data function
* gently slurp the bytes
* readability updates
* go fmt
* tidy up file server tests + add more cases
* start moving io wrappers to separate iotools package. Remove use of buffering while piping recache stream
Signed-off-by: kim <grufwub@gmail.com>
* add license text
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/iotools')
-rw-r--r-- | internal/iotools/io.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/internal/iotools/io.go b/internal/iotools/io.go new file mode 100644 index 000000000..d16a4ce9c --- /dev/null +++ b/internal/iotools/io.go @@ -0,0 +1,121 @@ +/* + GoToSocial + Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package iotools + +import ( + "io" +) + +// ReadFnCloser takes an io.Reader and wraps it to use the provided function to implement io.Closer. +func ReadFnCloser(r io.Reader, close func() error) io.ReadCloser { + return &readFnCloser{ + Reader: r, + close: close, + } +} + +type readFnCloser struct { + io.Reader + close func() error +} + +func (r *readFnCloser) Close() error { + return r.close() +} + +// WriteFnCloser takes an io.Writer and wraps it to use the provided function to implement io.Closer. +func WriteFnCloser(w io.Writer, close func() error) io.WriteCloser { + return &writeFnCloser{ + Writer: w, + close: close, + } +} + +type writeFnCloser struct { + io.Writer + close func() error +} + +func (r *writeFnCloser) Close() error { + return r.close() +} + +// SilentReader wraps an io.Reader to silence any +// error output during reads. Instead they are stored +// and accessible (not concurrency safe!) via .Error(). +type SilentReader struct { + io.Reader + err error +} + +// SilenceReader wraps an io.Reader within SilentReader{}. +func SilenceReader(r io.Reader) *SilentReader { + return &SilentReader{Reader: r} +} + +func (r *SilentReader) Read(b []byte) (int, error) { + n, err := r.Reader.Read(b) + if err != nil { + // Store error for now + if r.err == nil { + r.err = err + } + + // Pretend we're happy + // to continue reading. + n = len(b) + } + return n, nil +} + +func (r *SilentReader) Error() error { + return r.err +} + +// SilentWriter wraps an io.Writer to silence any +// error output during writes. Instead they are stored +// and accessible (not concurrency safe!) via .Error(). +type SilentWriter struct { + io.Writer + err error +} + +// SilenceWriter wraps an io.Writer within SilentWriter{}. +func SilenceWriter(w io.Writer) *SilentWriter { + return &SilentWriter{Writer: w} +} + +func (w *SilentWriter) Write(b []byte) (int, error) { + n, err := w.Writer.Write(b) + if err != nil { + // Store error for now + if w.err == nil { + w.err = err + } + + // Pretend we're happy + // to continue writing. + n = len(b) + } + return n, nil +} + +func (w *SilentWriter) Error() error { + return w.err +} |