github.com/puellanivis/breton@v0.2.16/lib/files/sftpfiles/reader.go (about)

     1  package sftpfiles
     2  
     3  import (
     4  	"context"
     5  	"net/url"
     6  	"os"
     7  
     8  	"github.com/puellanivis/breton/lib/files"
     9  
    10  	"github.com/pkg/sftp"
    11  )
    12  
    13  type reader struct {
    14  	uri *url.URL
    15  	*Host
    16  
    17  	loading <-chan struct{}
    18  	f       *sftp.File
    19  	err     error
    20  }
    21  
    22  func (r *reader) Name() string {
    23  	return r.uri.String()
    24  }
    25  
    26  func (r *reader) Stat() (os.FileInfo, error) {
    27  	for range r.loading {
    28  	}
    29  
    30  	if r.err != nil {
    31  		return nil, r.err
    32  	}
    33  
    34  	return r.f.Stat()
    35  }
    36  
    37  func (r *reader) Read(b []byte) (n int, err error) {
    38  	for range r.loading {
    39  	}
    40  
    41  	if r.err != nil {
    42  		return 0, r.err
    43  	}
    44  
    45  	return r.f.Read(b)
    46  }
    47  
    48  func (r *reader) Seek(offset int64, whence int) (int64, error) {
    49  	for range r.loading {
    50  	}
    51  
    52  	if r.err != nil {
    53  		return 0, r.err
    54  	}
    55  
    56  	return r.f.Seek(offset, whence)
    57  }
    58  
    59  func (r *reader) Close() error {
    60  	for range r.loading {
    61  	}
    62  
    63  	if r.err != nil {
    64  		// This error is a connection error, and request-scoped.
    65  		// So, in the context of Close, the error is irrelevant, so we ignore it.
    66  		return nil
    67  	}
    68  
    69  	return r.f.Close()
    70  }
    71  
    72  func (fs *filesystem) Open(ctx context.Context, uri *url.URL) (files.Reader, error) {
    73  	h := fs.getHost(uri)
    74  
    75  	if cl := h.GetClient(); cl != nil {
    76  		f, err := cl.Open(uri.Path)
    77  		if err != nil {
    78  			return nil, files.PathError("open", uri.String(), err)
    79  		}
    80  
    81  		return f, nil
    82  	}
    83  
    84  	loading := make(chan struct{})
    85  
    86  	fixURL := *uri
    87  	fixURL.Host = h.uri.Host
    88  	fixURL.User = h.uri.User
    89  
    90  	r := &reader{
    91  		uri:  &fixURL,
    92  		Host: h,
    93  
    94  		loading: loading,
    95  	}
    96  
    97  	go func() {
    98  		defer close(loading)
    99  
   100  		select {
   101  		case loading <- struct{}{}:
   102  		case <-ctx.Done():
   103  			r.err = files.PathError("connect", h.Name(), ctx.Err())
   104  			return
   105  		}
   106  
   107  		cl, err := h.Connect()
   108  		if err != nil {
   109  			r.err = files.PathError("connect", h.Name(), err)
   110  			return
   111  		}
   112  
   113  		f, err := cl.Open(uri.Path)
   114  		if err != nil {
   115  			r.err = files.PathError("open", r.Name(), err)
   116  			return
   117  		}
   118  
   119  		r.f = f
   120  	}()
   121  
   122  	return r, nil
   123  }