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 }