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 }