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  }