github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/pkg/blobserver/google/drive/service/service.go (about)

     1  /*
     2  Copyright 2013 Google Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // DriveService translates blobserver.Storage methods
    18  // into Google Drive API methods.
    19  package service
    20  
    21  import (
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  
    26  	"camlistore.org/third_party/code.google.com/p/goauth2/oauth"
    27  	client "camlistore.org/third_party/code.google.com/p/google-api-go-client/drive/v2"
    28  )
    29  
    30  const (
    31  	MimeTypeDriveFolder = "application/vnd.google-apps.folder"
    32  	MimeTypeCamliBlob   = "application/vnd.camlistore.blob"
    33  )
    34  
    35  // DriveService wraps Google Drive API to implement utility methods to
    36  // be performed on the root Drive destination folder.
    37  type DriveService struct {
    38  	transport  *oauth.Transport
    39  	apiservice *client.Service
    40  	parentId   string
    41  }
    42  
    43  // New initiates a new DriveService.
    44  func New(transport *oauth.Transport, parentId string) (*DriveService, error) {
    45  	apiservice, err := client.New(transport.Client())
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	service := &DriveService{transport: transport, apiservice: apiservice, parentId: parentId}
    50  	return service, err
    51  }
    52  
    53  // Get retrieves a file with its title
    54  func (s *DriveService) Get(id string) (*client.File, error) {
    55  	req := s.apiservice.Files.List()
    56  	// TODO: use field selectors
    57  	query := fmt.Sprintf("'%s' in parents and title = '%s'", s.parentId, id)
    58  	req.Q(query)
    59  	files, err := req.Do()
    60  
    61  	if err != nil || len(files.Items) < 1 {
    62  		return nil, err
    63  	}
    64  	return files.Items[0], err
    65  }
    66  
    67  // Lists the folder identified by parentId.
    68  func (s *DriveService) List(pageToken string, limit int) (files []*client.File, next string, err error) {
    69  	req := s.apiservice.Files.List()
    70  	req.Q(fmt.Sprintf("'%s' in parents and mimeType != '%s'", s.parentId, MimeTypeDriveFolder))
    71  
    72  	if pageToken != "" {
    73  		req.PageToken(pageToken)
    74  	}
    75  
    76  	if limit > 0 {
    77  		req.MaxResults(int64(limit))
    78  	}
    79  
    80  	result, err := req.Do()
    81  	if err != nil {
    82  		return
    83  	}
    84  	return result.Items, result.NextPageToken, err
    85  }
    86  
    87  // Upsert inserts a file, or updates if such a file exists.
    88  func (s *DriveService) Upsert(id string, data io.Reader) (file *client.File, err error) {
    89  	if file, err = s.Get(id); err != nil {
    90  		return
    91  	}
    92  	if file == nil {
    93  		file = &client.File{Title: id}
    94  		file.Parents = []*client.ParentReference{
    95  			&client.ParentReference{Id: s.parentId},
    96  		}
    97  		file.MimeType = MimeTypeCamliBlob
    98  		return s.apiservice.Files.Insert(file).Media(data).Do()
    99  	}
   100  
   101  	// TODO: handle large blobs
   102  	return s.apiservice.Files.Update(file.Id, file).Media(data).Do()
   103  }
   104  
   105  // Fetch retrieves the metadata and contents of a file.
   106  func (s *DriveService) Fetch(id string) (body io.ReadCloser, size int64, err error) {
   107  	file, err := s.Get(id)
   108  
   109  	// TODO: maybe in the case of no download link, remove the file.
   110  	// The file should have malformed or converted to a Docs file
   111  	// unwantedly.
   112  	if err != nil || file == nil || file.DownloadUrl != "" {
   113  		return
   114  	}
   115  
   116  	req, _ := http.NewRequest("GET", file.DownloadUrl, nil)
   117  	var resp *http.Response
   118  	if resp, err = s.transport.RoundTrip(req); err != nil {
   119  		return
   120  	}
   121  	return resp.Body, file.FileSize, err
   122  }
   123  
   124  // Stat retrieves file metadata and returns
   125  // file size. Returns error if file is not found.
   126  func (s *DriveService) Stat(id string) (int64, error) {
   127  	file, err := s.Get(id)
   128  	if err != nil || file == nil {
   129  		return 0, err
   130  	}
   131  	return file.FileSize, err
   132  }
   133  
   134  // Trash trashes an existing file.
   135  func (s *DriveService) Trash(id string) (err error) {
   136  	_, err = s.apiservice.Files.Trash(id).Do()
   137  	return
   138  }