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 }