gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

io.go (4108B)


      1 // GoToSocial
      2 // Copyright (C) GoToSocial Authors admin@gotosocial.org
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 //
      5 // This program is free software: you can redistribute it and/or modify
      6 // it under the terms of the GNU Affero General Public License as published by
      7 // the Free Software Foundation, either version 3 of the License, or
      8 // (at your option) any later version.
      9 //
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU Affero General Public License for more details.
     14 //
     15 // You should have received a copy of the GNU Affero General Public License
     16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 package iotools
     19 
     20 import (
     21 	"io"
     22 	"os"
     23 )
     24 
     25 // ReadFnCloser takes an io.Reader and wraps it to use the provided function to implement io.Closer.
     26 func ReadFnCloser(r io.Reader, close func() error) io.ReadCloser {
     27 	return &readFnCloser{
     28 		Reader: r,
     29 		close:  close,
     30 	}
     31 }
     32 
     33 type readFnCloser struct {
     34 	io.Reader
     35 	close func() error
     36 }
     37 
     38 func (r *readFnCloser) Close() error {
     39 	return r.close()
     40 }
     41 
     42 // WriteFnCloser takes an io.Writer and wraps it to use the provided function to implement io.Closer.
     43 func WriteFnCloser(w io.Writer, close func() error) io.WriteCloser {
     44 	return &writeFnCloser{
     45 		Writer: w,
     46 		close:  close,
     47 	}
     48 }
     49 
     50 type writeFnCloser struct {
     51 	io.Writer
     52 	close func() error
     53 }
     54 
     55 func (r *writeFnCloser) Close() error {
     56 	return r.close()
     57 }
     58 
     59 // SilentReader wraps an io.Reader to silence any
     60 // error output during reads. Instead they are stored
     61 // and accessible (not concurrency safe!) via .Error().
     62 type SilentReader struct {
     63 	io.Reader
     64 	err error
     65 }
     66 
     67 // SilenceReader wraps an io.Reader within SilentReader{}.
     68 func SilenceReader(r io.Reader) *SilentReader {
     69 	return &SilentReader{Reader: r}
     70 }
     71 
     72 func (r *SilentReader) Read(b []byte) (int, error) {
     73 	n, err := r.Reader.Read(b)
     74 	if err != nil {
     75 		// Store error for now
     76 		if r.err == nil {
     77 			r.err = err
     78 		}
     79 
     80 		// Pretend we're happy
     81 		// to continue reading.
     82 		n = len(b)
     83 	}
     84 	return n, nil
     85 }
     86 
     87 func (r *SilentReader) Error() error {
     88 	return r.err
     89 }
     90 
     91 // SilentWriter wraps an io.Writer to silence any
     92 // error output during writes. Instead they are stored
     93 // and accessible (not concurrency safe!) via .Error().
     94 type SilentWriter struct {
     95 	io.Writer
     96 	err error
     97 }
     98 
     99 // SilenceWriter wraps an io.Writer within SilentWriter{}.
    100 func SilenceWriter(w io.Writer) *SilentWriter {
    101 	return &SilentWriter{Writer: w}
    102 }
    103 
    104 func (w *SilentWriter) Write(b []byte) (int, error) {
    105 	n, err := w.Writer.Write(b)
    106 	if err != nil {
    107 		// Store error for now
    108 		if w.err == nil {
    109 			w.err = err
    110 		}
    111 
    112 		// Pretend we're happy
    113 		// to continue writing.
    114 		n = len(b)
    115 	}
    116 	return n, nil
    117 }
    118 
    119 func (w *SilentWriter) Error() error {
    120 	return w.err
    121 }
    122 
    123 func StreamReadFunc(read func(io.Reader) error) io.Writer {
    124 	// In-memory stream.
    125 	pr, pw := io.Pipe()
    126 
    127 	go func() {
    128 		var err error
    129 
    130 		defer func() {
    131 			// Always pass along error.
    132 			pr.CloseWithError(err)
    133 		}()
    134 
    135 		// Start reading.
    136 		err = read(pr)
    137 	}()
    138 
    139 	return pw
    140 }
    141 
    142 func StreamWriteFunc(write func(io.Writer) error) io.Reader {
    143 	// In-memory stream.
    144 	pr, pw := io.Pipe()
    145 
    146 	go func() {
    147 		var err error
    148 
    149 		defer func() {
    150 			// Always pass along error.
    151 			pw.CloseWithError(err)
    152 		}()
    153 
    154 		// Start writing.
    155 		err = write(pw)
    156 	}()
    157 
    158 	return pr
    159 }
    160 
    161 type tempFileSeeker struct {
    162 	io.Reader
    163 	io.Seeker
    164 	tmp *os.File
    165 }
    166 
    167 func (tfs *tempFileSeeker) Close() error {
    168 	tfs.tmp.Close()
    169 	return os.Remove(tfs.tmp.Name())
    170 }
    171 
    172 // TempFileSeeker converts the provided Reader into a ReadSeekCloser
    173 // by using an underlying temporary file. Callers should call the Close
    174 // function when they're done with the TempFileSeeker, to release +
    175 // clean up the temporary file.
    176 func TempFileSeeker(r io.Reader) (io.ReadSeekCloser, error) {
    177 	tmp, err := os.CreateTemp(os.TempDir(), "gotosocial-")
    178 	if err != nil {
    179 		return nil, err
    180 	}
    181 
    182 	if _, err := io.Copy(tmp, r); err != nil {
    183 		return nil, err
    184 	}
    185 
    186 	return &tempFileSeeker{
    187 		Reader: tmp,
    188 		Seeker: tmp,
    189 		tmp:    tmp,
    190 	}, nil
    191 }