github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/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 "errors" 23 "fmt" 24 "io" 25 "math" 26 "net/http" 27 28 "camlistore.org/third_party/code.google.com/p/goauth2/oauth" 29 client "camlistore.org/third_party/code.google.com/p/google-api-go-client/drive/v2" 30 ) 31 32 const ( 33 MimeTypeDriveFolder = "application/vnd.google-apps.folder" 34 MimeTypeCamliBlob = "application/vnd.camlistore.blob" 35 ) 36 37 // DriveService wraps Google Drive API to implement utility methods to 38 // be performed on the root Drive destination folder. 39 type DriveService struct { 40 transport *oauth.Transport 41 apiservice *client.Service 42 parentId string 43 } 44 45 // New initiates a new DriveService. 46 func New(transport *oauth.Transport, parentId string) (*DriveService, error) { 47 apiservice, err := client.New(transport.Client()) 48 if err != nil { 49 return nil, err 50 } 51 service := &DriveService{transport: transport, apiservice: apiservice, parentId: parentId} 52 return service, err 53 } 54 55 // Get retrieves a file with its title 56 func (s *DriveService) Get(id string) (*client.File, error) { 57 req := s.apiservice.Files.List() 58 // TODO: use field selectors 59 query := fmt.Sprintf("'%s' in parents and title = '%s'", s.parentId, id) 60 req.Q(query) 61 files, err := req.Do() 62 63 if err != nil || len(files.Items) < 1 { 64 return nil, err 65 } 66 return files.Items[0], err 67 } 68 69 // Lists the folder identified by parentId. 70 func (s *DriveService) List(pageToken string, limit int) (files []*client.File, next string, err error) { 71 req := s.apiservice.Files.List() 72 req.Q(fmt.Sprintf("'%s' in parents and mimeType != '%s'", s.parentId, MimeTypeDriveFolder)) 73 74 if pageToken != "" { 75 req.PageToken(pageToken) 76 } 77 78 if limit > 0 { 79 req.MaxResults(int64(limit)) 80 } 81 82 result, err := req.Do() 83 if err != nil { 84 return 85 } 86 return result.Items, result.NextPageToken, err 87 } 88 89 // Upsert inserts a file, or updates if such a file exists. 90 func (s *DriveService) Upsert(id string, data io.Reader) (file *client.File, err error) { 91 if file, err = s.Get(id); err != nil { 92 return 93 } 94 if file == nil { 95 file = &client.File{Title: id} 96 file.Parents = []*client.ParentReference{ 97 &client.ParentReference{Id: s.parentId}, 98 } 99 file.MimeType = MimeTypeCamliBlob 100 return s.apiservice.Files.Insert(file).Media(data).Do() 101 } 102 103 // TODO: handle large blobs 104 return s.apiservice.Files.Update(file.Id, file).Media(data).Do() 105 } 106 107 // Fetch retrieves the metadata and contents of a file. 108 func (s *DriveService) Fetch(id string) (body io.ReadCloser, size uint32, err error) { 109 file, err := s.Get(id) 110 111 // TODO: maybe in the case of no download link, remove the file. 112 // The file should have malformed or converted to a Docs file 113 // unwantedly. 114 if err != nil || file == nil || file.DownloadUrl != "" { 115 return 116 } 117 118 req, _ := http.NewRequest("GET", file.DownloadUrl, nil) 119 var resp *http.Response 120 if resp, err = s.transport.RoundTrip(req); err != nil { 121 return 122 } 123 if file.FileSize > math.MaxUint32 || file.FileSize < 0 { 124 err = errors.New("file too big") 125 } 126 return resp.Body, uint32(file.FileSize), err 127 } 128 129 // Stat retrieves file metadata and returns 130 // file size. Returns error if file is not found. 131 func (s *DriveService) Stat(id string) (int64, error) { 132 file, err := s.Get(id) 133 if err != nil || file == nil { 134 return 0, err 135 } 136 return file.FileSize, err 137 } 138 139 // Trash trashes an existing file. 140 func (s *DriveService) Trash(id string) (err error) { 141 _, err = s.apiservice.Files.Trash(id).Do() 142 return 143 }