github.com/cs3org/reva/v2@v2.27.7/pkg/sdk/action/download.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package action 20 21 import ( 22 "fmt" 23 24 gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" 25 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 26 storage "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 27 "github.com/cs3org/reva/v2/pkg/errtypes" 28 "github.com/cs3org/reva/v2/pkg/sdk" 29 "github.com/cs3org/reva/v2/pkg/sdk/common/net" 30 ) 31 32 // DownloadAction is used to download files through Reva. 33 // WebDAV will be used automatically if the endpoint supports it. 34 type DownloadAction struct { 35 action 36 } 37 38 // DownloadFile retrieves the data of the provided file path. 39 // The method first tries to retrieve information about the remote file by performing a "stat" on it. 40 func (action *DownloadAction) DownloadFile(path string) ([]byte, error) { 41 // Get the ResourceInfo object of the specified path 42 fileInfoAct := MustNewFileOperationsAction(action.session) 43 info, err := fileInfoAct.Stat(path) 44 if err != nil { 45 return nil, fmt.Errorf("the path '%v' was not found: %v", path, err) 46 } 47 48 return action.Download(info) 49 } 50 51 // Download retrieves the data of the provided resource. 52 func (action *DownloadAction) Download(fileInfo *storage.ResourceInfo) ([]byte, error) { 53 if fileInfo.Type != storage.ResourceType_RESOURCE_TYPE_FILE { 54 return nil, fmt.Errorf("resource is not a file") 55 } 56 57 // Issue a file download request to Reva; this will provide the endpoint to read the file data from 58 download, err := action.initiateDownload(fileInfo) 59 if err != nil { 60 return nil, err 61 } 62 63 p, err := getDownloadProtocolInfo(download.Protocols, "simple") 64 if err != nil { 65 return nil, err 66 } 67 68 // Try to get the file via WebDAV first 69 if client, values, err := net.NewWebDAVClientWithOpaque(p.DownloadEndpoint, p.Opaque); err == nil { 70 data, err := client.Read(values[net.WebDAVPathName]) 71 if err != nil { 72 return nil, fmt.Errorf("error while reading from '%v' via WebDAV: %v", p.DownloadEndpoint, err) 73 } 74 return data, nil 75 } 76 77 // WebDAV is not supported, so directly read the HTTP endpoint 78 request, err := action.session.NewHTTPRequest(p.DownloadEndpoint, "GET", p.Token, nil) 79 if err != nil { 80 return nil, fmt.Errorf("unable to create an HTTP request for '%v': %v", p.DownloadEndpoint, err) 81 } 82 83 data, err := request.Do(true) 84 if err != nil { 85 return nil, fmt.Errorf("error while reading from '%v' via HTTP: %v", p.DownloadEndpoint, err) 86 } 87 return data, nil 88 } 89 90 func (action *DownloadAction) initiateDownload(fileInfo *storage.ResourceInfo) (*gateway.InitiateFileDownloadResponse, error) { 91 // Initiating a download request gets us the download endpoint for the specified resource 92 req := &provider.InitiateFileDownloadRequest{Ref: &provider.Reference{ResourceId: fileInfo.Id}} 93 res, err := action.session.Client().InitiateFileDownload(action.session.Context(), req) 94 if err := net.CheckRPCInvocation("initiating download", res, err); err != nil { 95 return nil, err 96 } 97 return res, nil 98 } 99 100 func getDownloadProtocolInfo(protocolInfos []*gateway.FileDownloadProtocol, protocol string) (*gateway.FileDownloadProtocol, error) { 101 for _, p := range protocolInfos { 102 if p.Protocol == protocol { 103 return p, nil 104 } 105 } 106 return nil, errtypes.NotFound(protocol) 107 } 108 109 // NewDownloadAction creates a new download action. 110 func NewDownloadAction(session *sdk.Session) (*DownloadAction, error) { 111 action := &DownloadAction{} 112 if err := action.initAction(session); err != nil { 113 return nil, fmt.Errorf("unable to create the DownloadAction: %v", err) 114 } 115 return action, nil 116 } 117 118 // MustNewDownloadAction creates a new download action and panics on failure. 119 func MustNewDownloadAction(session *sdk.Session) *DownloadAction { 120 action, err := NewDownloadAction(session) 121 if err != nil { 122 panic(err) 123 } 124 return action 125 }