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  }