github.com/puellanivis/breton@v0.2.16/lib/files/sftpfiles/writer.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 writer struct { 14 uri *url.URL 15 *Host 16 17 loading <-chan struct{} 18 f *sftp.File 19 err error 20 } 21 22 func (w *writer) Name() string { 23 return w.uri.String() 24 } 25 26 func (w *writer) Stat() (os.FileInfo, error) { 27 for range w.loading { 28 } 29 30 if w.err != nil { 31 return nil, w.err 32 } 33 34 return w.f.Stat() 35 } 36 37 func (w *writer) Write(b []byte) (n int, err error) { 38 for range w.loading { 39 } 40 41 if w.err != nil { 42 return 0, w.err 43 } 44 45 return w.f.Write(b) 46 } 47 48 func (w *writer) Seek(offset int64, whence int) (int64, error) { 49 for range w.loading { 50 } 51 52 if w.err != nil { 53 return 0, w.err 54 } 55 56 return w.f.Seek(offset, whence) 57 } 58 59 func (w *writer) Sync() error { 60 for range w.loading { 61 } 62 63 return nil 64 } 65 66 func (w *writer) Close() error { 67 for range w.loading { 68 } 69 70 if w.err != nil { 71 // This error is a connection error, and request-scoped. 72 // So, in the context of Close, the error is irrelevant, so we ignore it. 73 return nil 74 } 75 76 return w.f.Close() 77 } 78 79 type noopSync struct { 80 *sftp.File 81 } 82 83 func (f noopSync) Sync() error { 84 return nil 85 } 86 87 func (fs *filesystem) Create(ctx context.Context, uri *url.URL) (files.Writer, error) { 88 h := fs.getHost(uri) 89 90 if cl := h.GetClient(); cl != nil { 91 f, err := cl.Create(uri.Path) 92 if err != nil { 93 return nil, files.PathError("create", uri.String(), err) 94 } 95 96 return noopSync{f}, nil 97 } 98 99 loading := make(chan struct{}) 100 101 fixURL := *uri 102 fixURL.Host = h.uri.Host 103 fixURL.User = h.uri.User 104 105 w := &writer{ 106 uri: &fixURL, 107 Host: h, 108 109 loading: loading, 110 } 111 112 go func() { 113 defer close(loading) 114 115 select { 116 case loading <- struct{}{}: 117 case <-ctx.Done(): 118 w.err = files.PathError("connect", h.Name(), ctx.Err()) 119 return 120 } 121 122 cl, err := h.Connect() 123 if err != nil { 124 w.err = files.PathError("connect", h.Name(), err) 125 return 126 } 127 128 f, err := cl.Create(uri.Path) 129 if err != nil { 130 w.err = files.PathError("create", w.Name(), err) 131 return 132 } 133 134 w.f = f 135 }() 136 137 return w, nil 138 }