github.com/viant/toolbox@v0.34.5/storage/service.go (about)

     1  // Package storage define abstract storage operation
     2  // Deprecated - please use https://github.com/viant/afs API instead
     3  // This package is frozen and no new functionality will be added, and future removal takes place.
     4  package storage
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"net/url"
    11  	"os"
    12  	"strings"
    13  )
    14  
    15  var DefaultFileMode os.FileMode = 0755
    16  
    17  //Service represents abstract way to accessing local or remote storage
    18  type Service interface {
    19  	//List returns a list of object for supplied url
    20  	List(URL string) ([]Object, error)
    21  	//Exists returns true if resource exists
    22  	Exists(URL string) (bool, error)
    23  	//Object returns a Object for supplied url
    24  	StorageObject(URL string) (Object, error)
    25  	//Download returns reader for downloaded storage object
    26  	Download(object Object) (io.ReadCloser, error)
    27  	//DownloadWithURL returns reader for downloaded URL object
    28  	DownloadWithURL(URL string) (io.ReadCloser, error)
    29  	//Upload uploads provided reader content for supplied storage object.
    30  	Upload(URL string, reader io.Reader) error
    31  	//Upload uploads provided reader content for supplied storage object.
    32  	UploadWithMode(URL string, mode os.FileMode, reader io.Reader) error
    33  	//Delete removes passed in storage object
    34  	Delete(object Object) error
    35  	//Register register schema with provided service
    36  	Register(schema string, service Service) error
    37  	//Closes storage service
    38  	Close() error
    39  }
    40  
    41  type storageService struct {
    42  	registry map[string]Service
    43  }
    44  
    45  func (s *storageService) getServiceForSchema(URL string) (Service, error) {
    46  	parsedUrl, err := url.Parse(URL)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	if result, found := s.registry[parsedUrl.Scheme]; found {
    52  		return result, nil
    53  	}
    54  
    55  	return nil, fmt.Errorf("failed to lookup url schema %v in %v", parsedUrl.Scheme, URL)
    56  }
    57  
    58  //List lists all object for passed in URL
    59  func (s *storageService) List(URL string) ([]Object, error) {
    60  	service, err := s.getServiceForSchema(URL)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	return service.List(URL)
    65  }
    66  
    67  //Exists returns true if resource exists
    68  func (s *storageService) Exists(URL string) (bool, error) {
    69  	service, err := s.getServiceForSchema(URL)
    70  	if err != nil {
    71  		return false, err
    72  	}
    73  	return service.Exists(URL)
    74  }
    75  
    76  //StorageObject returns storage object for provided URL
    77  func (s *storageService) StorageObject(URL string) (Object, error) {
    78  	service, err := s.getServiceForSchema(URL)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return service.StorageObject(URL)
    83  }
    84  
    85  //Download downloads content for passed in object
    86  func (s *storageService) Download(object Object) (io.ReadCloser, error) {
    87  	service, err := s.getServiceForSchema(object.URL())
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return service.Download(object)
    92  }
    93  
    94  //DownloadWithURL downloads content for passed in object URL
    95  func (s *storageService) DownloadWithURL(URL string) (io.ReadCloser, error) {
    96  	object, err := s.StorageObject(URL)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	return s.Download(object)
   101  }
   102  
   103  //Uploads content for passed in URL
   104  func (s *storageService) Upload(URL string, reader io.Reader) error {
   105  	service, err := s.getServiceForSchema(URL)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	return service.UploadWithMode(URL, 0644, reader)
   110  }
   111  
   112  //Uploads content for passed in URL
   113  func (s *storageService) UploadWithMode(URL string, mode os.FileMode, reader io.Reader) error {
   114  	service, err := s.getServiceForSchema(URL)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	return service.UploadWithMode(URL, mode, reader)
   119  }
   120  
   121  //Delete remove storage object
   122  func (s *storageService) Delete(object Object) error {
   123  	service, err := s.getServiceForSchema(object.URL())
   124  	if err != nil {
   125  		return err
   126  	}
   127  	return service.Delete(object)
   128  }
   129  
   130  //Close closes resources
   131  func (s *storageService) Close() error {
   132  	for _, service := range s.registry {
   133  		err := service.Close()
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  	return nil
   139  }
   140  
   141  //Register register storage schema
   142  func (s *storageService) Register(schema string, service Service) error {
   143  	s.registry[schema] = service
   144  	return nil
   145  }
   146  
   147  //NewService creates a new storage service
   148  func NewService() Service {
   149  	var result = &storageService{
   150  		registry: make(map[string]Service),
   151  	}
   152  	_ = result.Register("file", &fileStorageService{})
   153  	_ = result.Register("mem", NewMemoryService())
   154  	return result
   155  }
   156  
   157  //NewServiceForURL creates a new storage service for provided URL scheme and optional credential file
   158  func NewServiceForURL(URL, credentials string) (Service, error) {
   159  	parsedURL, err := url.Parse(URL)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	service := NewService()
   164  	provider := Registry().Get(parsedURL.Scheme)
   165  
   166  	if provider != nil {
   167  		if len(credentials) > 0 {
   168  			credentials = strings.Replace(credentials, "${env.HOME}", os.Getenv("HOME"), 1)
   169  			if strings.HasPrefix(credentials, "~") {
   170  				credentials = strings.Replace(credentials, "~", os.Getenv("HOME"), 1)
   171  			}
   172  		}
   173  		serviceForScheme, err := provider(credentials)
   174  		if err != nil {
   175  			return nil, fmt.Errorf("failed lookup service for %v: %v", parsedURL.Scheme, err)
   176  		}
   177  		err = service.Register(parsedURL.Scheme, serviceForScheme)
   178  		if err != nil {
   179  			return nil, err
   180  		}
   181  	} else if parsedURL.Scheme != "file" {
   182  		return nil, fmt.Errorf("unsupported scheme %v", URL)
   183  	}
   184  	return service, nil
   185  }
   186  
   187  //Download returns a download reader for supplied URL
   188  func Download(service Service, URL string) (io.ReadCloser, error) {
   189  	object, err := service.StorageObject(URL)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return service.Download(object)
   194  }
   195  
   196  //DownloadText returns a text for supplied URL
   197  func DownloadText(service Service, URL string) (string, error) {
   198  	reader, err := Download(service, URL)
   199  	if err != nil {
   200  		return "", err
   201  	}
   202  	defer reader.Close()
   203  	content, err := ioutil.ReadAll(reader)
   204  	if err != nil {
   205  		return "", err
   206  	}
   207  	return string(content), nil
   208  }