gdrive_server_node.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 from __future__ import print_function
4 
5 import datetime
6 from distutils.version import LooseVersion
7 import os.path
8 import pkg_resources
9 import sys
10 import time
11 
12 from httplib2 import ServerNotFoundError
13 from pydrive.auth import GoogleAuth
14 from pydrive.drive import GoogleDrive
15 from pydrive.files import ApiRequestError
16 import rospy
17 
18 from gdrive_ros.srv import MultipleUpload
19 from gdrive_ros.srv import MultipleUploadResponse
20 from gdrive_ros.srv import Upload
21 from gdrive_ros.srv import UploadResponse
22 
23 
24 if sys.version_info.major < 3 and \
25  LooseVersion(pkg_resources.get_distribution("rsa").version) \
26  >= LooseVersion('4.6.0'):
27  print('''rsa < 4.6.0 is required:
28  pip install oauth2client==4.2.3 rsa==4.5 pydrive==1.3.1
29  For more detailed information,
30  please read https://github.com/jsk-ros-pkg/jsk_3rdparty/tree/master/gdrive_ros#trouble-shooting
31 ''', file=sys.stderr)
32  sys.exit(1)
33 
34 
35 class GDriveServerNode(object):
36  folder_mime_type = 'application/vnd.google-apps.folder'
37  folder_url_format = 'https://drive.google.com/drive/folders/{}'
38  file_url_format = 'https://drive.google.com/uc?id={}'
39 
40  def __init__(self):
41  settings_yaml = rospy.get_param('~settings_yaml', None)
42  self.share_type = rospy.get_param('~share_type', 'anyone')
43  self.share_value = rospy.get_param('~share_value', 'anyone')
44  self.share_role = rospy.get_param('~share_role', 'reader')
45  self.share_with_link = rospy.get_param('~share_with_link', True)
46  auth_max_trial = rospy.get_param('~auth_max_trial', -1)
47  auth_wait_seconds = rospy.get_param('~auth_wait_seconds', 10.0)
48  if settings_yaml is not None:
49  self.gauth = GoogleAuth(settings_yaml)
50  # if client_config_file, save_credentials_file is not found, try to find relative to setting_yaml
51  dir_path = os.path.dirname(os.path.realpath(settings_yaml))
52  for file in ['client_config_file', 'save_credentials_file']:
53  if not os.path.isfile(self.gauth.settings[file]):
54  rospy.logwarn("{}:{} is not found, try to use {}".format(file, self.gauth.settings[file], os.path.join(dir_path, self.gauth.settings[file])))
55  self.gauth.settings[file] = os.path.join(dir_path, self.gauth.settings[file])
56  else:
57  rospy.logerr('param: ~settings_yaml is not correctly set.')
58  sys.exit(1)
59 
60  rospy.loginfo('Google drive authentication starts.')
61  auth_success = False
62  auth_count = 0
63  while (not auth_success and
64  (auth_max_trial < 0 or auth_count < auth_max_trial)):
65  try:
66  self.gauth.LocalWebserverAuth()
67  auth_success = True
68  except ServerNotFoundError as e:
69  rospy.logerr('Authentication failed: {}'.format(e))
70  auth_count = auth_count + 1
71  time.sleep(auth_wait_seconds)
72  if not auth_success:
73  rospy.logerr(
74  'Authentication failed {} times.'.format(auth_max_trial))
75  sys.exit(1)
76  self.gdrive = GoogleDrive(self.gauth)
77  rospy.loginfo('Google drive authentication finished.')
78  self.upload_server = rospy.Service('~upload', Upload, self._upload_cb)
79  self.upload_multi_server = rospy.Service(
80  '~upload_multi', MultipleUpload, self._upload_multi_cb)
81 
82  def _upload_cb(self, req):
83  timestamp = '{0:%Y%m%d%H%M%S}'.format(datetime.datetime.now())
84  parents_path = req.parents_path
85  parents_id = req.parents_id
86 
87  # response initialization
88  res = UploadResponse()
89  res.success = False
90  res.file_id = ''
91  res.file_url = ''
92 
93  if parents_id and parents_path:
94  rospy.logerr('parents_path and parents_id is both set.')
95  rospy.logerr(
96  'parents_id: {} is selected to upload.'.format(parents_id))
97  parents_path = ''
98 
99  if parents_path:
100  try:
101  parents_id = self._get_parents_id(
102  parents_path, mkdir=True)
103  except (ValueError, ApiRequestError, ServerNotFoundError) as e:
104  rospy.logerr(e)
105  rospy.logerr(
106  'Failed to get parents_id: {}'.format(parents_path))
107  return res
108  # root
109  elif parents_id == '' and parents_path == '':
110  parents_id = ''
111 
112  if req.use_timestamp_folder:
113  try:
114  parents_id = self._get_parents_id(
115  [timestamp], parents_id=parents_id, mkdir=True)
116  except (ValueError, ApiRequestError, ServerNotFoundError) as e:
117  rospy.logerr(e)
118  rospy.logerr(
119  'Failed to get parents_id: {} in {}'.format(
120  timestamp, self.folder_url_format.format(parents_id)))
121  return res
122 
123  success, file_id, file_url = self._upload_step(
124  req.file_path, req.file_title, parents_id,
125  req.use_timestamp_file_title, timestamp)
126  res.success = success
127  res.file_id = file_id
128  res.file_url = file_url
129  res.parents_id = parents_id
130  res.parents_url = self.folder_url_format.format(parents_id)
131  return res
132 
133  def _upload_multi_cb(self, req):
134  timestamp = '{0:%Y%m%d%H%M%S}'.format(datetime.datetime.now())
135  parents_path = req.parents_path
136  parents_id = req.parents_id
137 
138  # response initialization
139  res = MultipleUploadResponse()
140  res.successes = [False] * len(req.file_titles)
141  res.file_ids = [''] * len(req.file_titles)
142  res.file_urls = [''] * len(req.file_titles)
143 
144  if parents_id and parents_path:
145  rospy.logerr('parents_path and parents_id is both set.')
146  rospy.logerr(
147  'parents_id: {} is selected to upload.'.format(parents_id))
148  parents_path = ''
149 
150  if parents_path:
151  try:
152  parents_id = self._get_parents_id(
153  parents_path, mkdir=True)
154  except (ValueError, ApiRequestError, ServerNotFoundError) as e:
155  rospy.logerr(e)
156  rospy.logerr(
157  'Failed to get parents_id: {}'.format(parents_path))
158  return res
159  # root
160  elif parents_id == '' and parents_path == '':
161  parents_id = ''
162 
163  if req.use_timestamp_folder:
164  try:
165  parents_id = self._get_parents_id(
166  [timestamp], parents_id=parents_id, mkdir=True)
167  except (ValueError, ApiRequestError, ServerNotFoundError) as e:
168  rospy.logerr(e)
169  rospy.logerr(
170  'Failed to get parents_id: {} in {}'.format(
171  timestamp, self.folder_url_format.format(parents_id)))
172  return res
173 
174  for i, (file_path, file_title) in enumerate(
175  zip(req.file_paths, req.file_titles)):
176  success, file_id, file_url = self._upload_step(
177  file_path, file_title, parents_id,
178  req.use_timestamp_file_title, timestamp)
179  res.successes[i] = success
180  res.file_ids[i] = file_id
181  res.file_urls[i] = file_url
182  res.parents_id = parents_id
183  res.parents_url = self.folder_url_format.format(parents_id)
184  return res
185 
186  def _upload_step(self, file_path, file_title, parents_id,
187  use_timestamp_file_title=False, timestamp=None):
188  file_title = file_title if file_title else file_path.split('/')[-1]
189  file_path = os.path.expanduser(file_path)
190  if use_timestamp_file_title:
191  file_title = '{}_{}'.format(timestamp, file_title)
192 
193  success = False
194  file_id = ''
195  file_url = ''
196  folder_url = self.folder_url_format.format(parents_id)
197  try:
198  file_id = self._upload_file(
199  file_path, file_title, parents_id=parents_id)
200  file_url = self.file_url_format.format(file_id)
201  success = True
202  rospy.loginfo(
203  'Success to upload: {} -> {}'.format(file_path, file_url))
204  except (OSError, ApiRequestError, ServerNotFoundError) as e:
205  rospy.logerr(e)
206  rospy.logerr(
207  'Failed to upload: {} -> {}'.format(file_path, folder_url))
208  return success, file_id, file_url
209 
210  def _upload_file(self, file_path, file_title, parents_id=None):
211  if not os.path.exists(file_path):
212  raise OSError('File not found: {}'.format(file_path))
213  rospy.loginfo('Start uploading a file: {}'.format(file_title))
214  if parents_id:
215  gfile = self.gdrive.CreateFile(
216  {'parents': [{'id': parents_id}]})
217  else:
218  gfile = self.gdrive.CreateFile()
219  gfile.SetContentFile(file_path)
220  gfile['title'] = file_title
221  gfile.Upload()
222  gfile.InsertPermission({
223  'type': self.share_type,
224  'value': self.share_value,
225  'role': self.share_role,
226  'withLink': self.share_with_link,
227  })
228  rospy.loginfo('Finish uploading a file: {}'.format(file_title))
229  return gfile['id']
230 
231  def _upload_folder(self, folder_title, parents_id=None):
232  rospy.loginfo('Start making a folder: {}'.format(folder_title))
233  if parents_id:
234  gfolder = self.gdrive.CreateFile(
235  {'title': folder_title,
236  'parents': [{'id': parents_id}],
237  'mimeType': 'application/vnd.google-apps.folder'})
238  else:
239  gfolder = self.gdrive.CreateFile(
240  {'title': folder_title,
241  'mimeType': 'application/vnd.google-apps.folder'})
242  gfolder.Upload()
243  rospy.loginfo('Finish making a folder: {}'.format(folder_title))
244  return gfolder['id']
245 
246  def _get_parents_id(self, parents_path, parents_id=None, mkdir=False):
247  if parents_path == '':
248  return None
249 
250  if not isinstance(parents_path, list):
251  parents_path = [p for p in parents_path.split('/') if p != '']
252 
253  folder_title = parents_path[0]
254  parent = parents_id if parents_id else 'root'
255  gfiles = self.gdrive.ListFile(
256  {'q': "'{}' in parents and trashed=false".format(parent)})
257  gfiles = gfiles.GetList()
258  gfolders = []
259  for gf in gfiles:
260  if (gf['mimeType'] == self.folder_mime_type
261  and gf['title'] == folder_title):
262  gfolders.append(gf)
263 
264  if len(parents_path) == 1:
265  if len(gfolders) > 0:
266  return gfolders[0]['id']
267  if mkdir:
268  folder_id = self._upload_folder(
269  folder_title, parents_id=parents_id)
270  return folder_id
271  else:
272  raise ValueError(
273  'Folder is not found: {}'.format(folder_title))
274  else:
275  if len(gfolders) > 0 or mkdir:
276  if len(gfolders) > 0:
277  next_parents_id = gfolders[0]['id']
278  elif mkdir:
279  next_parents_id = self._upload_folder(
280  folder_title, parents_id=parents_id)
281  folder_id = self._get_parents_id(
282  parents_path[1:], parents_id=next_parents_id,
283  mkdir=mkdir)
284  return folder_id
285  else:
286  raise ValueError('folder is not found: {}', folder_title)
287 
288 
289 if __name__ == '__main__':
290  rospy.init_node('gdrive_server')
292  rospy.spin()
def _upload_folder(self, folder_title, parents_id=None)
def _upload_file(self, file_path, file_title, parents_id=None)
def _upload_step(self, file_path, file_title, parents_id, use_timestamp_file_title=False, timestamp=None)
def _get_parents_id(self, parents_path, parents_id=None, mkdir=False)


gdrive_ros
Author(s): Shingo Kitagawa
autogenerated on Sat Jun 24 2023 02:40:20