OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/chromeos/drive/drive_api_service.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/message_loop_proxy.h" | |
12 #include "base/task_runner_util.h" | |
13 #include "base/threading/sequenced_worker_pool.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/google_apis/drive_api_operations.h" | |
16 #include "chrome/browser/google_apis/drive_api_parser.h" | |
17 #include "chrome/browser/google_apis/gdata_wapi_parser.h" | |
18 #include "chrome/browser/google_apis/operation_runner.h" | |
19 #include "chrome/browser/google_apis/time_util.h" | |
20 #include "chrome/browser/profiles/profile.h" | |
21 #include "chrome/common/net/url_util.h" | |
22 #include "content/public/browser/browser_thread.h" | |
23 | |
24 using content::BrowserThread; | |
25 | |
26 namespace drive { | |
27 | |
28 namespace { | |
29 | |
30 // OAuth2 scopes for Drive API. | |
31 const char kDriveScope[] = "https://www.googleapis.com/auth/drive"; | |
32 const char kDriveAppsReadonlyScope[] = | |
33 "https://www.googleapis.com/auth/drive.apps.readonly"; | |
34 | |
35 scoped_ptr<google_apis::ResourceList> ParseResourceListOnBlockingPool( | |
36 scoped_ptr<base::Value> value, google_apis::GDataErrorCode* error) { | |
37 if (!value) { | |
38 // JSON value is not available. | |
39 return scoped_ptr<google_apis::ResourceList>(); | |
40 } | |
41 | |
42 // Parse the value into ResourceList via ChangeList. | |
43 // If failed, set (i.e. overwrite) the error flag and return immediately. | |
44 scoped_ptr<google_apis::ChangeList> change_list( | |
45 google_apis::ChangeList::CreateFrom(*value)); | |
46 if (!change_list) { | |
47 *error = google_apis::GDATA_PARSE_ERROR; | |
48 return scoped_ptr<google_apis::ResourceList>(); | |
49 } | |
50 | |
51 scoped_ptr<google_apis::ResourceList> resource_list = | |
52 google_apis::ResourceList::CreateFromChangeList(*change_list); | |
53 if (!resource_list) { | |
54 *error = google_apis::GDATA_PARSE_ERROR; | |
55 return scoped_ptr<google_apis::ResourceList>(); | |
56 } | |
57 | |
58 // Pass the result to the params, so that DidParseResourceListOnBlockingPool | |
59 // defined below can process it. | |
60 return resource_list.Pass(); | |
61 } | |
62 | |
63 // Callback invoked when the parsing of resource list is completed, | |
64 // regardless whether it is succeeded or not. | |
65 void DidParseResourceListOnBlockingPool( | |
66 const google_apis::GetResourceListCallback& callback, | |
67 google_apis::GDataErrorCode* error, | |
68 scoped_ptr<google_apis::ResourceList> resource_list) { | |
69 callback.Run(*error, resource_list.Pass()); | |
70 } | |
71 | |
72 // Sends a task to parse the JSON value into ResourceList on blocking pool, | |
73 // with a callback which is called when the task is done. | |
74 void ParseResourceListOnBlockingPoolAndRun( | |
75 const google_apis::GetResourceListCallback& callback, | |
76 google_apis::GDataErrorCode in_error, | |
77 scoped_ptr<base::Value> value) { | |
78 // Note that the error value may be overwritten in | |
79 // ParseResoruceListOnBlockingPool before used in | |
80 // DidParseResourceListOnBlockingPool. | |
81 google_apis::GDataErrorCode* error = | |
82 new google_apis::GDataErrorCode(in_error); | |
83 | |
84 PostTaskAndReplyWithResult( | |
85 BrowserThread::GetBlockingPool(), | |
86 FROM_HERE, | |
87 base::Bind(&ParseResourceListOnBlockingPool, | |
88 base::Passed(&value), error), | |
89 base::Bind(&DidParseResourceListOnBlockingPool, | |
90 callback, base::Owned(error))); | |
91 } | |
92 | |
93 // Parses the JSON value to ResourceEntry runs |callback|. | |
94 void ParseResourceEntryAndRun( | |
95 const google_apis::GetResourceEntryCallback& callback, | |
96 google_apis::GDataErrorCode error, | |
97 scoped_ptr<base::Value> value) { | |
98 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
99 | |
100 if (!value) { | |
101 callback.Run(error, scoped_ptr<google_apis::ResourceEntry>()); | |
102 return; | |
103 } | |
104 | |
105 // Parsing FileResource is cheap enough to do on UI thread. | |
106 scoped_ptr<google_apis::FileResource> file_resource = | |
107 google_apis::FileResource::CreateFrom(*value); | |
108 if (!file_resource) { | |
109 callback.Run(google_apis::GDATA_PARSE_ERROR, | |
110 scoped_ptr<google_apis::ResourceEntry>()); | |
111 return; | |
112 } | |
113 | |
114 // Converting to ResourceEntry is cheap enough to do on UI thread. | |
115 scoped_ptr<google_apis::ResourceEntry> entry = | |
116 google_apis::ResourceEntry::CreateFromFileResource(*file_resource); | |
117 if (!entry) { | |
118 callback.Run(google_apis::GDATA_PARSE_ERROR, | |
119 scoped_ptr<google_apis::ResourceEntry>()); | |
120 return; | |
121 } | |
122 | |
123 callback.Run(error, entry.Pass()); | |
124 } | |
125 | |
126 // Parses the JSON value to AccountMetadataFeed on the blocking pool and runs | |
127 // |callback| on the UI thread once parsing is done. | |
128 void ParseAccounetMetadataAndRun( | |
129 const google_apis::GetAccountMetadataCallback& callback, | |
130 google_apis::GDataErrorCode error, | |
131 scoped_ptr<base::Value> value) { | |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
133 DCHECK(!callback.is_null()); | |
134 | |
135 if (!value) { | |
136 callback.Run(error, scoped_ptr<google_apis::AccountMetadataFeed>()); | |
137 return; | |
138 } | |
139 | |
140 // Parsing AboutResource is cheap enough to do on UI thread. | |
141 scoped_ptr<google_apis::AboutResource> about_resource = | |
142 google_apis::AboutResource::CreateFrom(*value); | |
143 | |
144 // TODO(satorux): Convert AboutResource to AccountMetadataFeed. | |
145 // For now just returning an error. crbug.com/165621 | |
146 callback.Run(google_apis::GDATA_PARSE_ERROR, | |
147 scoped_ptr<google_apis::AccountMetadataFeed>()); | |
148 } | |
149 | |
150 } // namespace | |
151 | |
152 DriveAPIService::DriveAPIService( | |
153 net::URLRequestContextGetter* url_request_context_getter, | |
154 const GURL& base_url, | |
155 const std::string& custom_user_agent) | |
156 : url_request_context_getter_(url_request_context_getter), | |
157 profile_(NULL), | |
158 runner_(NULL), | |
159 url_generator_(base_url), | |
160 custom_user_agent_(custom_user_agent) { | |
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
162 } | |
163 | |
164 DriveAPIService::~DriveAPIService() { | |
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
166 if (runner_.get()) { | |
167 runner_->operation_registry()->RemoveObserver(this); | |
168 runner_->auth_service()->RemoveObserver(this); | |
169 } | |
170 } | |
171 | |
172 void DriveAPIService::Initialize(Profile* profile) { | |
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
174 profile_ = profile; | |
175 | |
176 std::vector<std::string> scopes; | |
177 scopes.push_back(kDriveScope); | |
178 scopes.push_back(kDriveAppsReadonlyScope); | |
179 runner_.reset( | |
180 new google_apis::OperationRunner(profile, | |
181 url_request_context_getter_, | |
182 scopes, | |
183 custom_user_agent_)); | |
184 runner_->Initialize(); | |
185 | |
186 runner_->auth_service()->AddObserver(this); | |
187 runner_->operation_registry()->AddObserver(this); | |
188 } | |
189 | |
190 void DriveAPIService::AddObserver(google_apis::DriveServiceObserver* observer) { | |
191 observers_.AddObserver(observer); | |
192 } | |
193 | |
194 void DriveAPIService::RemoveObserver( | |
195 google_apis::DriveServiceObserver* observer) { | |
196 observers_.RemoveObserver(observer); | |
197 } | |
198 | |
199 bool DriveAPIService::CanStartOperation() const { | |
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
201 | |
202 return HasRefreshToken(); | |
203 } | |
204 | |
205 void DriveAPIService::CancelAll() { | |
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
207 runner_->CancelAll(); | |
208 } | |
209 | |
210 bool DriveAPIService::CancelForFilePath(const FilePath& file_path) { | |
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
212 return operation_registry()->CancelForFilePath(file_path); | |
213 } | |
214 | |
215 google_apis::OperationProgressStatusList | |
216 DriveAPIService::GetProgressStatusList() const { | |
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
218 return operation_registry()->GetProgressStatusList(); | |
219 } | |
220 | |
221 void DriveAPIService::GetResourceList( | |
222 const GURL& url, | |
223 int64 start_changestamp, | |
224 const std::string& search_query, | |
225 bool shared_with_me, | |
226 const std::string& directory_resource_id, | |
227 const google_apis::GetResourceListCallback& callback) { | |
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
229 DCHECK(!callback.is_null()); | |
230 | |
231 if (search_query.empty()) | |
232 GetChangelist(url, start_changestamp, callback); | |
233 else | |
234 GetFilelist(url, search_query, callback); | |
235 | |
236 return; | |
237 // TODO(kochi): Implement !directory_resource_id.empty() case. | |
238 NOTREACHED(); | |
239 } | |
240 | |
241 void DriveAPIService::GetFilelist( | |
242 const GURL& url, | |
243 const std::string& search_query, | |
244 const google_apis::GetResourceListCallback& callback) { | |
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
246 DCHECK(!callback.is_null()); | |
247 | |
248 runner_->StartOperationWithRetry( | |
249 new google_apis::GetFilelistOperation( | |
250 operation_registry(), | |
251 url_request_context_getter_, | |
252 url_generator_, | |
253 url, | |
254 search_query, | |
255 base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback))); | |
256 } | |
257 | |
258 void DriveAPIService::GetChangelist( | |
259 const GURL& url, | |
260 int64 start_changestamp, | |
261 const google_apis::GetResourceListCallback& callback) { | |
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
263 DCHECK(!callback.is_null()); | |
264 | |
265 runner_->StartOperationWithRetry( | |
266 new google_apis::GetChangelistOperation( | |
267 operation_registry(), | |
268 url_request_context_getter_, | |
269 url_generator_, | |
270 url, | |
271 start_changestamp, | |
272 base::Bind(&ParseResourceListOnBlockingPoolAndRun, callback))); | |
273 } | |
274 | |
275 void DriveAPIService::GetResourceEntry( | |
276 const std::string& resource_id, | |
277 const google_apis::GetResourceEntryCallback& callback) { | |
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
279 DCHECK(!callback.is_null()); | |
280 | |
281 runner_->StartOperationWithRetry(new google_apis::GetFileOperation( | |
282 operation_registry(), | |
283 url_request_context_getter_, | |
284 url_generator_, | |
285 resource_id, | |
286 base::Bind(&ParseResourceEntryAndRun, callback))); | |
287 } | |
288 | |
289 void DriveAPIService::GetAccountMetadata( | |
290 const google_apis::GetAccountMetadataCallback& callback) { | |
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
292 DCHECK(!callback.is_null()); | |
293 | |
294 runner_->StartOperationWithRetry( | |
295 new google_apis::GetAboutOperation( | |
296 operation_registry(), | |
297 url_request_context_getter_, | |
298 url_generator_, | |
299 base::Bind(&ParseAccounetMetadataAndRun, callback))); | |
300 } | |
301 | |
302 void DriveAPIService::GetApplicationInfo( | |
303 const google_apis::GetDataCallback& callback) { | |
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
305 DCHECK(!callback.is_null()); | |
306 | |
307 runner_->StartOperationWithRetry( | |
308 new google_apis::GetApplistOperation(operation_registry(), | |
309 url_request_context_getter_, | |
310 url_generator_, | |
311 callback)); | |
312 } | |
313 | |
314 void DriveAPIService::DownloadHostedDocument( | |
315 const FilePath& virtual_path, | |
316 const FilePath& local_cache_path, | |
317 const GURL& content_url, | |
318 google_apis::DocumentExportFormat format, | |
319 const google_apis::DownloadActionCallback& callback) { | |
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
321 DCHECK(!callback.is_null()); | |
322 | |
323 // TODO(kochi): Implement this. | |
324 NOTREACHED(); | |
325 } | |
326 | |
327 void DriveAPIService::DownloadFile( | |
328 const FilePath& virtual_path, | |
329 const FilePath& local_cache_path, | |
330 const GURL& content_url, | |
331 const google_apis::DownloadActionCallback& download_action_callback, | |
332 const google_apis::GetContentCallback& get_content_callback) { | |
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
334 DCHECK(!download_action_callback.is_null()); | |
335 // get_content_callback may be null. | |
336 | |
337 // TODO(kochi): Implement this. | |
338 NOTREACHED(); | |
339 } | |
340 | |
341 void DriveAPIService::DeleteResource( | |
342 const GURL& edit_url, | |
343 const google_apis::EntryActionCallback& callback) { | |
344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
345 DCHECK(!callback.is_null()); | |
346 | |
347 // TODO(kochi): Implement this. | |
348 NOTREACHED(); | |
349 } | |
350 | |
351 void DriveAPIService::AddNewDirectory( | |
352 const GURL& parent_content_url, | |
353 const FilePath::StringType& directory_name, | |
354 const google_apis::GetResourceEntryCallback& callback) { | |
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
356 DCHECK(!callback.is_null()); | |
357 | |
358 // TODO(kochi): Implement this. | |
359 NOTREACHED(); | |
360 } | |
361 | |
362 void DriveAPIService::CopyHostedDocument( | |
363 const std::string& resource_id, | |
364 const FilePath::StringType& new_name, | |
365 const google_apis::GetResourceEntryCallback& callback) { | |
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
367 DCHECK(!callback.is_null()); | |
368 | |
369 // TODO(kochi): Implement this. | |
370 NOTREACHED(); | |
371 } | |
372 | |
373 void DriveAPIService::RenameResource( | |
374 const GURL& edit_url, | |
375 const FilePath::StringType& new_name, | |
376 const google_apis::EntryActionCallback& callback) { | |
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
378 DCHECK(!callback.is_null()); | |
379 | |
380 // TODO(kochi): Implement this. | |
381 NOTREACHED(); | |
382 } | |
383 | |
384 void DriveAPIService::AddResourceToDirectory( | |
385 const GURL& parent_content_url, | |
386 const GURL& edit_url, | |
387 const google_apis::EntryActionCallback& callback) { | |
388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
389 DCHECK(!callback.is_null()); | |
390 | |
391 // TODO(kochi): Implement this. | |
392 NOTREACHED(); | |
393 } | |
394 | |
395 void DriveAPIService::RemoveResourceFromDirectory( | |
396 const GURL& parent_content_url, | |
397 const std::string& resource_id, | |
398 const google_apis::EntryActionCallback& callback) { | |
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
400 DCHECK(!callback.is_null()); | |
401 | |
402 // TODO(kochi): Implement this. | |
403 NOTREACHED(); | |
404 } | |
405 | |
406 void DriveAPIService::InitiateUpload( | |
407 const google_apis::InitiateUploadParams& params, | |
408 const google_apis::InitiateUploadCallback& callback) { | |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
410 DCHECK(!callback.is_null()); | |
411 | |
412 // TODO(kochi): Implement this. | |
413 NOTREACHED(); | |
414 } | |
415 | |
416 void DriveAPIService::ResumeUpload( | |
417 const google_apis::ResumeUploadParams& params, | |
418 const google_apis::ResumeUploadCallback& callback) { | |
419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
420 DCHECK(!callback.is_null()); | |
421 | |
422 // TODO(kochi): Implement this. | |
423 NOTREACHED(); | |
424 } | |
425 | |
426 void DriveAPIService::AuthorizeApp( | |
427 const GURL& edit_url, | |
428 const std::string& app_ids, | |
429 const google_apis::AuthorizeAppCallback& callback) { | |
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
431 DCHECK(!callback.is_null()); | |
432 | |
433 // TODO(kochi): Implement this. | |
434 NOTREACHED(); | |
435 } | |
436 | |
437 bool DriveAPIService::HasAccessToken() const { | |
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
439 | |
440 return runner_->auth_service()->HasAccessToken(); | |
441 } | |
442 | |
443 bool DriveAPIService::HasRefreshToken() const { | |
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
445 | |
446 return runner_->auth_service()->HasRefreshToken(); | |
447 } | |
448 | |
449 google_apis::OperationRegistry* DriveAPIService::operation_registry() const { | |
450 return runner_->operation_registry(); | |
451 } | |
452 | |
453 void DriveAPIService::OnOAuth2RefreshTokenChanged() { | |
454 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
455 if (CanStartOperation()) { | |
456 FOR_EACH_OBSERVER( | |
457 google_apis::DriveServiceObserver, observers_, | |
458 OnReadyToPerformOperations()); | |
459 } | |
460 } | |
461 | |
462 void DriveAPIService::OnProgressUpdate( | |
463 const google_apis::OperationProgressStatusList& list) { | |
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
465 FOR_EACH_OBSERVER( | |
466 google_apis::DriveServiceObserver, observers_, OnProgressUpdate(list)); | |
467 } | |
468 | |
469 void DriveAPIService::OnAuthenticationFailed( | |
470 google_apis::GDataErrorCode error) { | |
471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
472 FOR_EACH_OBSERVER( | |
473 google_apis::DriveServiceObserver, observers_, | |
474 OnAuthenticationFailed(error)); | |
475 } | |
476 | |
477 } // namespace drive | |
OLD | NEW |