Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend_v1 / local_sync_delegate.cc
blob7c2b37dead9be6cfc15c8627f359a71666fd2a3c
1 // Copyright 2013 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.
5 #include "chrome/browser/sync_file_system/drive_backend_v1/local_sync_delegate.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "chrome/browser/sync_file_system/conflict_resolution_resolver.h"
10 #include "chrome/browser/sync_file_system/drive_backend_v1/api_util.h"
11 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_metadata_store.h"
12 #include "chrome/browser/sync_file_system/logger.h"
13 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
15 namespace sync_file_system {
16 namespace drive_backend {
18 LocalSyncDelegate::LocalSyncDelegate(
19 DriveFileSyncService* sync_service,
20 const FileChange& local_change,
21 const base::FilePath& local_path,
22 const SyncFileMetadata& local_metadata,
23 const fileapi::FileSystemURL& url)
24 : sync_service_(sync_service),
25 operation_(SYNC_OPERATION_NONE),
26 url_(url),
27 local_change_(local_change),
28 local_path_(local_path),
29 local_metadata_(local_metadata),
30 has_drive_metadata_(false),
31 has_remote_change_(false),
32 weak_factory_(this) {}
34 LocalSyncDelegate::~LocalSyncDelegate() {}
36 void LocalSyncDelegate::Run(const SyncStatusCallback& callback) {
37 // TODO(nhiroki): support directory operations (http://crbug.com/161442).
38 DCHECK(IsSyncFSDirectoryOperationEnabled() || !local_change_.IsDirectory());
39 operation_ = SYNC_OPERATION_NONE;
41 has_drive_metadata_ =
42 metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
44 if (!has_drive_metadata_)
45 drive_metadata_.set_md5_checksum(std::string());
47 sync_service_->EnsureOriginRootDirectory(
48 url_.origin(),
49 base::Bind(&LocalSyncDelegate::DidGetOriginRoot,
50 weak_factory_.GetWeakPtr(),
51 callback));
54 void LocalSyncDelegate::DidGetOriginRoot(
55 const SyncStatusCallback& callback,
56 SyncStatusCode status,
57 const std::string& origin_resource_id) {
58 if (status != SYNC_STATUS_OK) {
59 callback.Run(status);
60 return;
63 origin_resource_id_ = origin_resource_id;
65 has_remote_change_ =
66 remote_change_handler()->GetChangeForURL(url_, &remote_change_);
67 if (has_remote_change_ && drive_metadata_.resource_id().empty())
68 drive_metadata_.set_resource_id(remote_change_.resource_id);
70 SyncFileType remote_file_type =
71 has_remote_change_ ? remote_change_.change.file_type() :
72 has_drive_metadata_ ?
73 DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
74 drive_metadata_.type())
75 : SYNC_FILE_TYPE_UNKNOWN;
77 DCHECK_EQ(SYNC_OPERATION_NONE, operation_);
78 operation_ = LocalSyncOperationResolver::Resolve(
79 local_change_,
80 has_remote_change_ ? &remote_change_.change : NULL,
81 has_drive_metadata_ ? &drive_metadata_ : NULL);
83 util::Log(logging::LOG_VERBOSE, FROM_HERE,
84 "ApplyLocalChange for %s local_change:%s ===> %s",
85 url_.DebugString().c_str(),
86 local_change_.DebugString().c_str(),
87 SyncOperationTypeToString(operation_));
89 switch (operation_) {
90 case SYNC_OPERATION_ADD_FILE:
91 UploadNewFile(callback);
92 return;
93 case SYNC_OPERATION_ADD_DIRECTORY:
94 CreateDirectory(callback);
95 return;
96 case SYNC_OPERATION_UPDATE_FILE:
97 UploadExistingFile(callback);
98 return;
99 case SYNC_OPERATION_DELETE:
100 Delete(callback);
101 return;
102 case SYNC_OPERATION_NONE:
103 callback.Run(SYNC_STATUS_OK);
104 return;
105 case SYNC_OPERATION_CONFLICT:
106 HandleConflict(callback);
107 return;
108 case SYNC_OPERATION_RESOLVE_TO_LOCAL:
109 ResolveToLocal(callback);
110 return;
111 case SYNC_OPERATION_RESOLVE_TO_REMOTE:
112 ResolveToRemote(callback, remote_file_type);
113 return;
114 case SYNC_OPERATION_DELETE_METADATA:
115 DeleteMetadata(base::Bind(
116 &LocalSyncDelegate::DidApplyLocalChange,
117 weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
118 return;
119 case SYNC_OPERATION_FAIL: {
120 callback.Run(SYNC_STATUS_FAILED);
121 return;
124 NOTREACHED();
125 callback.Run(SYNC_STATUS_FAILED);
128 void LocalSyncDelegate::UploadNewFile(const SyncStatusCallback& callback) {
129 api_util()->UploadNewFile(
130 origin_resource_id_,
131 local_path_,
132 DriveFileSyncService::PathToTitle(url_.path()),
133 base::Bind(&LocalSyncDelegate::DidUploadNewFile,
134 weak_factory_.GetWeakPtr(), callback));
137 void LocalSyncDelegate::DidUploadNewFile(
138 const SyncStatusCallback& callback,
139 google_apis::GDataErrorCode error,
140 const std::string& resource_id,
141 const std::string& md5) {
142 switch (error) {
143 case google_apis::HTTP_CREATED:
144 UpdateMetadata(
145 resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
146 base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
147 weak_factory_.GetWeakPtr(), callback, error));
148 sync_service_->NotifyObserversFileStatusChanged(
149 url_,
150 SYNC_FILE_STATUS_SYNCED,
151 SYNC_ACTION_ADDED,
152 SYNC_DIRECTION_LOCAL_TO_REMOTE);
153 return;
154 case google_apis::HTTP_CONFLICT:
155 HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
156 callback);
157 return;
158 default:
159 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
163 void LocalSyncDelegate::CreateDirectory(const SyncStatusCallback& callback) {
164 DCHECK(IsSyncFSDirectoryOperationEnabled());
165 api_util()->CreateDirectory(
166 origin_resource_id_,
167 DriveFileSyncService::PathToTitle(url_.path()),
168 base::Bind(&LocalSyncDelegate::DidCreateDirectory,
169 weak_factory_.GetWeakPtr(), callback));
172 void LocalSyncDelegate::DidCreateDirectory(
173 const SyncStatusCallback& callback,
174 google_apis::GDataErrorCode error,
175 const std::string& resource_id) {
176 switch (error) {
177 case google_apis::HTTP_SUCCESS:
178 case google_apis::HTTP_CREATED: {
179 UpdateMetadata(
180 resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
181 base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
182 weak_factory_.GetWeakPtr(), callback, error));
183 sync_service_->NotifyObserversFileStatusChanged(
184 url_,
185 SYNC_FILE_STATUS_SYNCED,
186 SYNC_ACTION_ADDED,
187 SYNC_DIRECTION_LOCAL_TO_REMOTE);
188 return;
191 case google_apis::HTTP_CONFLICT:
192 // There were conflicts and a file was left.
193 // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
194 // Fall-through
196 default:
197 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
201 void LocalSyncDelegate::UploadExistingFile(const SyncStatusCallback& callback) {
202 DCHECK(has_drive_metadata_);
203 if (drive_metadata_.resource_id().empty()) {
204 UploadNewFile(callback);
205 return;
208 api_util()->UploadExistingFile(
209 drive_metadata_.resource_id(),
210 drive_metadata_.md5_checksum(),
211 local_path_,
212 base::Bind(&LocalSyncDelegate::DidUploadExistingFile,
213 weak_factory_.GetWeakPtr(), callback));
216 void LocalSyncDelegate::DidUploadExistingFile(
217 const SyncStatusCallback& callback,
218 google_apis::GDataErrorCode error,
219 const std::string& resource_id,
220 const std::string& md5) {
221 DCHECK(has_drive_metadata_);
222 switch (error) {
223 case google_apis::HTTP_SUCCESS:
224 UpdateMetadata(
225 resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
226 base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
227 weak_factory_.GetWeakPtr(), callback, error));
228 sync_service_->NotifyObserversFileStatusChanged(
229 url_,
230 SYNC_FILE_STATUS_SYNCED,
231 SYNC_ACTION_UPDATED,
232 SYNC_DIRECTION_LOCAL_TO_REMOTE);
233 return;
234 case google_apis::HTTP_CONFLICT:
235 HandleConflict(callback);
236 return;
237 case google_apis::HTTP_NOT_MODIFIED:
238 DidApplyLocalChange(callback,
239 google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
240 return;
241 case google_apis::HTTP_NOT_FOUND:
242 UploadNewFile(callback);
243 return;
244 default: {
245 const SyncStatusCode status =
246 GDataErrorCodeToSyncStatusCodeWrapper(error);
247 DCHECK_NE(SYNC_STATUS_OK, status);
248 callback.Run(status);
249 return;
254 void LocalSyncDelegate::Delete(const SyncStatusCallback& callback) {
255 if (!has_drive_metadata_) {
256 callback.Run(SYNC_STATUS_OK);
257 return;
260 if (drive_metadata_.resource_id().empty()) {
261 DidDelete(callback, google_apis::HTTP_NOT_FOUND);
262 return;
265 api_util()->DeleteFile(
266 drive_metadata_.resource_id(),
267 drive_metadata_.md5_checksum(),
268 base::Bind(&LocalSyncDelegate::DidDelete,
269 weak_factory_.GetWeakPtr(), callback));
272 void LocalSyncDelegate::DidDelete(
273 const SyncStatusCallback& callback,
274 google_apis::GDataErrorCode error) {
275 DCHECK(has_drive_metadata_);
277 switch (error) {
278 case google_apis::HTTP_SUCCESS:
279 case google_apis::HTTP_NOT_FOUND:
280 DeleteMetadata(base::Bind(
281 &LocalSyncDelegate::DidApplyLocalChange,
282 weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
283 sync_service_->NotifyObserversFileStatusChanged(
284 url_,
285 SYNC_FILE_STATUS_SYNCED,
286 SYNC_ACTION_DELETED,
287 SYNC_DIRECTION_LOCAL_TO_REMOTE);
288 return;
289 case google_apis::HTTP_PRECONDITION:
290 case google_apis::HTTP_CONFLICT:
291 // Delete |drive_metadata| on the conflict case.
292 // Conflicted remote change should be applied as a future remote change.
293 DeleteMetadata(base::Bind(
294 &LocalSyncDelegate::DidDeleteMetadataForDeletionConflict,
295 weak_factory_.GetWeakPtr(), callback));
296 sync_service_->NotifyObserversFileStatusChanged(
297 url_,
298 SYNC_FILE_STATUS_SYNCED,
299 SYNC_ACTION_DELETED,
300 SYNC_DIRECTION_LOCAL_TO_REMOTE);
301 return;
302 default: {
303 const SyncStatusCode status =
304 GDataErrorCodeToSyncStatusCodeWrapper(error);
305 DCHECK_NE(SYNC_STATUS_OK, status);
306 callback.Run(status);
307 return;
312 void LocalSyncDelegate::DidDeleteMetadataForDeletionConflict(
313 const SyncStatusCallback& callback,
314 SyncStatusCode status) {
315 callback.Run(SYNC_STATUS_OK);
318 void LocalSyncDelegate::ResolveToLocal(const SyncStatusCallback& callback) {
319 if (drive_metadata_.resource_id().empty()) {
320 DidDeleteFileToResolveToLocal(callback, google_apis::HTTP_NOT_FOUND);
321 return;
324 api_util()->DeleteFile(
325 drive_metadata_.resource_id(),
326 drive_metadata_.md5_checksum(),
327 base::Bind(
328 &LocalSyncDelegate::DidDeleteFileToResolveToLocal,
329 weak_factory_.GetWeakPtr(), callback));
332 void LocalSyncDelegate::DidDeleteFileToResolveToLocal(
333 const SyncStatusCallback& callback,
334 google_apis::GDataErrorCode error) {
335 if (error != google_apis::HTTP_SUCCESS &&
336 error != google_apis::HTTP_NOT_FOUND) {
337 callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
338 return;
341 DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
342 if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
343 UploadNewFile(callback);
344 return;
347 DCHECK(IsSyncFSDirectoryOperationEnabled());
348 DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
349 CreateDirectory(callback);
352 void LocalSyncDelegate::ResolveToRemote(
353 const SyncStatusCallback& callback,
354 SyncFileType remote_file_type) {
355 // Mark the file as to-be-fetched.
356 DCHECK(!drive_metadata_.resource_id().empty());
358 SetMetadataToBeFetched(
359 DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
360 remote_file_type),
361 base::Bind(&LocalSyncDelegate::DidResolveToRemote,
362 weak_factory_.GetWeakPtr(), callback));
363 // The synced notification will be dispatched when the remote file is
364 // downloaded.
367 void LocalSyncDelegate::DidResolveToRemote(
368 const SyncStatusCallback& callback,
369 SyncStatusCode status) {
370 DCHECK(has_drive_metadata_);
371 if (status != SYNC_STATUS_OK) {
372 callback.Run(status);
373 return;
376 SyncFileType file_type = SYNC_FILE_TYPE_FILE;
377 if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
378 file_type = SYNC_FILE_TYPE_DIRECTORY;
379 sync_service_->AppendFetchChange(
380 url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
381 callback.Run(status);
384 void LocalSyncDelegate::DidApplyLocalChange(
385 const SyncStatusCallback& callback,
386 const google_apis::GDataErrorCode error,
387 SyncStatusCode status) {
388 if ((operation_ == SYNC_OPERATION_DELETE ||
389 operation_ == SYNC_OPERATION_DELETE_METADATA) &&
390 (status == SYNC_FILE_ERROR_NOT_FOUND ||
391 status == SYNC_DATABASE_ERROR_NOT_FOUND)) {
392 status = SYNC_STATUS_OK;
395 if (status == SYNC_STATUS_OK) {
396 remote_change_handler()->RemoveChangeForURL(url_);
397 status = GDataErrorCodeToSyncStatusCodeWrapper(error);
399 callback.Run(status);
402 void LocalSyncDelegate::UpdateMetadata(
403 const std::string& resource_id,
404 const std::string& md5,
405 DriveMetadata::ResourceType type,
406 const SyncStatusCallback& callback) {
407 has_drive_metadata_ = true;
408 drive_metadata_.set_resource_id(resource_id);
409 drive_metadata_.set_md5_checksum(md5);
410 drive_metadata_.set_conflicted(false);
411 drive_metadata_.set_to_be_fetched(false);
412 drive_metadata_.set_type(type);
413 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
416 void LocalSyncDelegate::ResetMetadataForStartOver(
417 const SyncStatusCallback& callback) {
418 has_drive_metadata_ = true;
419 DCHECK(!drive_metadata_.resource_id().empty());
420 drive_metadata_.set_md5_checksum(std::string());
421 drive_metadata_.set_conflicted(false);
422 drive_metadata_.set_to_be_fetched(false);
423 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
426 void LocalSyncDelegate::SetMetadataToBeFetched(
427 DriveMetadata::ResourceType type,
428 const SyncStatusCallback& callback) {
429 has_drive_metadata_ = true;
430 drive_metadata_.set_md5_checksum(std::string());
431 drive_metadata_.set_conflicted(false);
432 drive_metadata_.set_to_be_fetched(true);
433 drive_metadata_.set_type(type);
434 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
437 void LocalSyncDelegate::DeleteMetadata(const SyncStatusCallback& callback) {
438 metadata_store()->DeleteEntry(url_, callback);
441 void LocalSyncDelegate::HandleCreationConflict(
442 const std::string& resource_id,
443 DriveMetadata::ResourceType type,
444 const SyncStatusCallback& callback) {
445 // File-file conflict is found.
446 // Populates a fake drive_metadata and set has_drive_metadata = true.
447 // In HandleConflictLocalSync:
448 // - If conflict_resolution is manual, we'll change conflicted to true
449 // and save the metadata.
450 // - Otherwise we'll save the metadata with empty md5 and will start
451 // over local sync as UploadExistingFile.
452 drive_metadata_.set_resource_id(resource_id);
453 drive_metadata_.set_md5_checksum(std::string());
454 drive_metadata_.set_conflicted(false);
455 drive_metadata_.set_to_be_fetched(false);
456 drive_metadata_.set_type(type);
457 has_drive_metadata_ = true;
458 HandleConflict(callback);
461 void LocalSyncDelegate::HandleConflict(const SyncStatusCallback& callback) {
462 DCHECK(!drive_metadata_.resource_id().empty());
463 api_util()->GetResourceEntry(
464 drive_metadata_.resource_id(),
465 base::Bind(
466 &LocalSyncDelegate::DidGetEntryForConflictResolution,
467 weak_factory_.GetWeakPtr(), callback));
470 void LocalSyncDelegate::DidGetEntryForConflictResolution(
471 const SyncStatusCallback& callback,
472 google_apis::GDataErrorCode error,
473 scoped_ptr<google_apis::ResourceEntry> entry) {
474 SyncFileType remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
475 ConflictResolution resolution = CONFLICT_RESOLUTION_UNKNOWN;
477 if (error != google_apis::HTTP_SUCCESS ||
478 entry->updated_time().is_null()) {
479 resolution = CONFLICT_RESOLUTION_LOCAL_WIN;
480 } else {
481 SyncFileType local_file_type = local_metadata_.file_type;
482 base::Time local_modification_time = local_metadata_.last_modified;
483 base::Time remote_modification_time = entry->updated_time();
484 if (entry->is_file())
485 remote_file_type = SYNC_FILE_TYPE_FILE;
486 else if (entry->is_folder())
487 remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
488 else
489 remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
491 resolution = conflict_resolution_resolver()->Resolve(
492 local_file_type, local_modification_time,
493 remote_file_type, remote_modification_time);
496 switch (resolution) {
497 case CONFLICT_RESOLUTION_MARK_CONFLICT:
498 HandleManualResolutionCase(callback);
499 return;
500 case CONFLICT_RESOLUTION_LOCAL_WIN:
501 HandleLocalWinCase(callback);
502 return;
503 case CONFLICT_RESOLUTION_REMOTE_WIN:
504 HandleRemoteWinCase(callback, remote_file_type);
505 return;
506 case CONFLICT_RESOLUTION_UNKNOWN:
507 NOTREACHED();
509 NOTREACHED();
510 callback.Run(SYNC_STATUS_FAILED);
513 void LocalSyncDelegate::HandleManualResolutionCase(
514 const SyncStatusCallback& callback) {
515 if (drive_metadata_.conflicted()) {
516 callback.Run(SYNC_STATUS_HAS_CONFLICT);
517 return;
520 has_drive_metadata_ = true;
521 sync_service_->MarkConflict(
522 url_, &drive_metadata_,
523 base::Bind(&LocalSyncDelegate::DidMarkConflict,
524 weak_factory_.GetWeakPtr(), callback));
527 void LocalSyncDelegate::DidMarkConflict(
528 const SyncStatusCallback& callback,
529 SyncStatusCode status) {
530 DidApplyLocalChange(callback, google_apis::HTTP_CONFLICT, status);
533 void LocalSyncDelegate::HandleLocalWinCase(
534 const SyncStatusCallback& callback) {
535 util::Log(logging::LOG_VERBOSE, FROM_HERE,
536 "Resolving conflict for local sync: %s: LOCAL WIN",
537 url_.DebugString().c_str());
539 DCHECK(!drive_metadata_.resource_id().empty());
540 if (!has_drive_metadata_) {
541 StartOver(callback, SYNC_STATUS_OK);
542 return;
545 ResetMetadataForStartOver(base::Bind(&LocalSyncDelegate::StartOver,
546 weak_factory_.GetWeakPtr(), callback));
549 void LocalSyncDelegate::HandleRemoteWinCase(
550 const SyncStatusCallback& callback,
551 SyncFileType remote_file_type) {
552 util::Log(logging::LOG_VERBOSE, FROM_HERE,
553 "Resolving conflict for local sync: %s: REMOTE WIN",
554 url_.DebugString().c_str());
555 ResolveToRemote(callback, remote_file_type);
558 void LocalSyncDelegate::StartOver(const SyncStatusCallback& callback,
559 SyncStatusCode status) {
560 if (status != SYNC_STATUS_OK) {
561 callback.Run(status);
562 return;
565 remote_change_handler()->RemoveChangeForURL(url_);
567 // Return the control back to the sync service once.
568 callback.Run(SYNC_STATUS_RETRY);
571 SyncStatusCode
572 LocalSyncDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
573 google_apis::GDataErrorCode error) {
574 return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
577 DriveMetadataStore* LocalSyncDelegate::metadata_store() {
578 return sync_service_->metadata_store_.get();
581 APIUtilInterface* LocalSyncDelegate::api_util() {
582 return sync_service_->api_util_.get();
585 RemoteChangeHandler* LocalSyncDelegate::remote_change_handler() {
586 return &sync_service_->remote_change_handler_;
589 ConflictResolutionResolver* LocalSyncDelegate::conflict_resolution_resolver() {
590 return &sync_service_->conflict_resolution_resolver_;
593 } // namespace drive_backend
594 } // namespace sync_file_system