OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/sync/engine_impl/loopback_server/loopback_server.h" | 5 #include "components/sync/engine_impl/loopback_server/loopback_server.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <set> | 9 #include <set> |
10 #include <utility> | 10 #include <utility> |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 const ModelTypeToVersionMap request_version_map_; | 127 const ModelTypeToVersionMap request_version_map_; |
128 | 128 |
129 // The largest versions seen between client and server, ultimately used to | 129 // The largest versions seen between client and server, ultimately used to |
130 // send progress markers back to the client. | 130 // send progress markers back to the client. |
131 ModelTypeToVersionMap response_version_map_; | 131 ModelTypeToVersionMap response_version_map_; |
132 }; | 132 }; |
133 | 133 |
134 } // namespace | 134 } // namespace |
135 | 135 |
136 LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) | 136 LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) |
137 : version_(0), store_birthday_(0), persistent_file_(persistent_file) { | 137 : version_(0), |
| 138 store_birthday_(0), |
| 139 persistent_file_(persistent_file), |
| 140 observer_for_tests_(NULL) { |
138 Init(); | 141 Init(); |
139 } | 142 } |
140 | 143 |
141 LoopbackServer::~LoopbackServer() {} | 144 LoopbackServer::~LoopbackServer() {} |
142 | 145 |
143 void LoopbackServer::Init() { | 146 void LoopbackServer::Init() { |
144 if (LoadStateFromFile(persistent_file_)) | 147 if (LoadStateFromFile(persistent_file_)) |
145 return; | 148 return; |
146 | 149 |
147 keystore_keys_.push_back(GenerateNewKeystoreKey()); | 150 keystore_keys_.push_back(GenerateNewKeystoreKey()); |
148 | 151 |
149 const bool create_result = CreateDefaultPermanentItems(); | 152 const bool create_result = CreateDefaultPermanentItems(); |
150 DCHECK(create_result) << "Permanent items were not created successfully."; | 153 DCHECK(create_result) << "Permanent items were not created successfully."; |
151 } | 154 } |
152 | 155 |
153 std::string LoopbackServer::GenerateNewKeystoreKey() const { | 156 std::string LoopbackServer::GenerateNewKeystoreKey() const { |
154 // TODO(pastarmovj): Check if true random bytes is ok or alpha-nums is needed? | 157 // TODO(pastarmovj): Check if true random bytes is ok or alpha-nums is needed? |
155 return base::RandBytesAsString(kKeystoreKeyLenght); | 158 return base::RandBytesAsString(kKeystoreKeyLenght); |
156 } | 159 } |
157 | 160 |
158 bool LoopbackServer::CreatePermanentBookmarkFolder( | 161 bool LoopbackServer::CreatePermanentBookmarkFolder( |
159 const std::string& server_tag, | 162 const std::string& server_tag, |
160 const std::string& name) { | 163 const std::string& name) { |
161 DCHECK(thread_checker_.CalledOnValidThread()); | 164 DCHECK(thread_checker_.CalledOnValidThread()); |
162 std::unique_ptr<LoopbackServerEntity> entity = | 165 std::unique_ptr<LoopbackServerEntity> entity = |
163 PersistentPermanentEntity::Create(syncer::BOOKMARKS, server_tag, name, | 166 PersistentPermanentEntity::CreateNew( |
164 ModelTypeToRootTag(syncer::BOOKMARKS)); | 167 syncer::BOOKMARKS, server_tag, name, |
| 168 ModelTypeToRootTag(syncer::BOOKMARKS)); |
165 if (!entity) | 169 if (!entity) |
166 return false; | 170 return false; |
167 | 171 |
168 SaveEntity(std::move(entity)); | 172 SaveEntity(std::move(entity)); |
169 return true; | 173 return true; |
170 } | 174 } |
171 | 175 |
172 bool LoopbackServer::CreateDefaultPermanentItems() { | 176 bool LoopbackServer::CreateDefaultPermanentItems() { |
173 // Permanent folders are always required for Bookmarks (hierarchical | 177 // Permanent folders are always required for Bookmarks (hierarchical |
174 // structure) and Nigori (data stored in permanent root folder). | 178 // structure) and Nigori (data stored in permanent root folder). |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 string LoopbackServer::CommitEntity( | 320 string LoopbackServer::CommitEntity( |
317 const sync_pb::SyncEntity& client_entity, | 321 const sync_pb::SyncEntity& client_entity, |
318 sync_pb::CommitResponse_EntryResponse* entry_response, | 322 sync_pb::CommitResponse_EntryResponse* entry_response, |
319 const string& client_guid, | 323 const string& client_guid, |
320 const string& parent_id) { | 324 const string& parent_id) { |
321 if (client_entity.version() == 0 && client_entity.deleted()) { | 325 if (client_entity.version() == 0 && client_entity.deleted()) { |
322 return string(); | 326 return string(); |
323 } | 327 } |
324 | 328 |
325 std::unique_ptr<LoopbackServerEntity> entity; | 329 std::unique_ptr<LoopbackServerEntity> entity; |
| 330 syncer::ModelType type = GetModelType(client_entity); |
326 if (client_entity.deleted()) { | 331 if (client_entity.deleted()) { |
327 entity = PersistentTombstoneEntity::Create(client_entity); | 332 entity = PersistentTombstoneEntity::CreateFromEntity(client_entity); |
328 DeleteChildren(client_entity.id_string()); | 333 DeleteChildren(client_entity.id_string()); |
329 } else if (GetModelType(client_entity) == syncer::NIGORI) { | 334 } else if (type == syncer::NIGORI) { |
330 // NIGORI is the only permanent item type that should be updated by the | 335 // NIGORI is the only permanent item type that should be updated by the |
331 // client. | 336 // client. |
332 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); | 337 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
333 CHECK(iter != entities_.end()); | 338 CHECK(iter != entities_.end()); |
334 entity = PersistentPermanentEntity::CreateUpdatedNigoriEntity( | 339 entity = PersistentPermanentEntity::CreateUpdatedNigoriEntity( |
335 client_entity, *iter->second); | 340 client_entity, *iter->second); |
336 } else if (client_entity.has_client_defined_unique_tag()) { | 341 } else if (type == syncer::BOOKMARKS) { |
337 entity = PersistentUniqueClientEntity::Create(client_entity); | |
338 } else { | |
339 // TODO(pvalenzuela): Validate entity's parent ID. | 342 // TODO(pvalenzuela): Validate entity's parent ID. |
340 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); | 343 EntityMap::const_iterator iter = entities_.find(client_entity.id_string()); |
341 if (iter != entities_.end()) { | 344 if (iter != entities_.end()) { |
342 entity = PersistentBookmarkEntity::CreateUpdatedVersion( | 345 entity = PersistentBookmarkEntity::CreateUpdatedVersion( |
343 client_entity, *iter->second, parent_id); | 346 client_entity, *iter->second, parent_id); |
344 } else { | 347 } else { |
345 entity = PersistentBookmarkEntity::CreateNew(client_entity, parent_id, | 348 entity = PersistentBookmarkEntity::CreateNew(client_entity, parent_id, |
346 client_guid); | 349 client_guid); |
347 } | 350 } |
348 } | 351 } else { |
349 | 352 entity = PersistentUniqueClientEntity::CreateFromEntity(client_entity); |
350 if (!entity) { | |
351 LOG(ERROR) << "No server entity was created for client entity with type: " | |
352 << GetModelType(client_entity) | |
353 << " and ID: " << client_entity.id_string() << "."; | |
354 return string(); | |
355 } | 353 } |
356 | 354 |
357 const std::string id = entity->GetId(); | 355 const std::string id = entity->GetId(); |
358 SaveEntity(std::move(entity)); | 356 SaveEntity(std::move(entity)); |
359 BuildEntryResponseForSuccessfulCommit(id, entry_response); | 357 BuildEntryResponseForSuccessfulCommit(id, entry_response); |
360 return id; | 358 return id; |
361 } | 359 } |
362 | 360 |
| 361 void LoopbackServer::OverrideResponseType( |
| 362 ResponseTypeProvider response_type_override) { |
| 363 response_type_override_ = std::move(response_type_override); |
| 364 } |
| 365 |
363 void LoopbackServer::BuildEntryResponseForSuccessfulCommit( | 366 void LoopbackServer::BuildEntryResponseForSuccessfulCommit( |
364 const std::string& entity_id, | 367 const std::string& entity_id, |
365 sync_pb::CommitResponse_EntryResponse* entry_response) { | 368 sync_pb::CommitResponse_EntryResponse* entry_response) { |
366 EntityMap::const_iterator iter = entities_.find(entity_id); | 369 EntityMap::const_iterator iter = entities_.find(entity_id); |
367 CHECK(iter != entities_.end()); | 370 CHECK(iter != entities_.end()); |
368 const LoopbackServerEntity& entity = *iter->second; | 371 const LoopbackServerEntity& entity = *iter->second; |
369 entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); | 372 entry_response->set_response_type(response_type_override_ |
| 373 ? response_type_override_.Run(entity) |
| 374 : sync_pb::CommitResponse::SUCCESS); |
370 entry_response->set_id_string(entity.GetId()); | 375 entry_response->set_id_string(entity.GetId()); |
371 | 376 |
372 if (entity.IsDeleted()) { | 377 if (entity.IsDeleted()) { |
373 entry_response->set_version(entity.GetVersion() + 1); | 378 entry_response->set_version(entity.GetVersion() + 1); |
374 } else { | 379 } else { |
375 entry_response->set_version(entity.GetVersion()); | 380 entry_response->set_version(entity.GetVersion()); |
376 entry_response->set_name(entity.GetName()); | 381 entry_response->set_name(entity.GetName()); |
377 } | 382 } |
378 } | 383 } |
379 | 384 |
(...skipping 19 matching lines...) Expand all Loading... |
399 // Find all the children of id. | 404 // Find all the children of id. |
400 for (auto& entity : entities_) { | 405 for (auto& entity : entities_) { |
401 if (IsChild(entity.first, id)) { | 406 if (IsChild(entity.first, id)) { |
402 sync_pb::SyncEntity proto; | 407 sync_pb::SyncEntity proto; |
403 entity.second->SerializeAsProto(&proto); | 408 entity.second->SerializeAsProto(&proto); |
404 tombstones.emplace_back(proto); | 409 tombstones.emplace_back(proto); |
405 } | 410 } |
406 } | 411 } |
407 | 412 |
408 for (auto& tombstone : tombstones) { | 413 for (auto& tombstone : tombstones) { |
409 SaveEntity(PersistentTombstoneEntity::Create(tombstone)); | 414 SaveEntity(PersistentTombstoneEntity::CreateFromEntity(tombstone)); |
410 } | 415 } |
411 } | 416 } |
412 | 417 |
413 bool LoopbackServer::HandleCommitRequest( | 418 bool LoopbackServer::HandleCommitRequest( |
414 const sync_pb::CommitMessage& commit, | 419 const sync_pb::CommitMessage& commit, |
415 const std::string& invalidator_client_id, | 420 const std::string& invalidator_client_id, |
416 sync_pb::CommitResponse* response) { | 421 sync_pb::CommitResponse* response) { |
417 std::map<string, string> client_to_server_ids; | 422 std::map<string, string> client_to_server_ids; |
418 string guid = commit.cache_guid(); | 423 string guid = commit.cache_guid(); |
419 ModelTypeSet committed_model_types; | 424 ModelTypeSet committed_model_types; |
(...skipping 19 matching lines...) Expand all Loading... |
439 // Record the ID if it was renamed. | 444 // Record the ID if it was renamed. |
440 if (entity_id != client_entity.id_string()) { | 445 if (entity_id != client_entity.id_string()) { |
441 client_to_server_ids[client_entity.id_string()] = entity_id; | 446 client_to_server_ids[client_entity.id_string()] = entity_id; |
442 } | 447 } |
443 | 448 |
444 EntityMap::const_iterator iter = entities_.find(entity_id); | 449 EntityMap::const_iterator iter = entities_.find(entity_id); |
445 CHECK(iter != entities_.end()); | 450 CHECK(iter != entities_.end()); |
446 committed_model_types.Put(iter->second->GetModelType()); | 451 committed_model_types.Put(iter->second->GetModelType()); |
447 } | 452 } |
448 | 453 |
| 454 if (observer_for_tests_) |
| 455 observer_for_tests_->OnCommit(invalidator_client_id, committed_model_types); |
| 456 |
449 return true; | 457 return true; |
450 } | 458 } |
451 | 459 |
452 void LoopbackServer::ClearServerData() { | 460 void LoopbackServer::ClearServerData() { |
453 DCHECK(thread_checker_.CalledOnValidThread()); | 461 DCHECK(thread_checker_.CalledOnValidThread()); |
454 entities_.clear(); | 462 entities_.clear(); |
455 keystore_keys_.clear(); | 463 keystore_keys_.clear(); |
456 ++store_birthday_; | 464 ++store_birthday_; |
| 465 base::DeleteFile(persistent_file_, false); |
457 Init(); | 466 Init(); |
458 } | 467 } |
459 | 468 |
460 std::string LoopbackServer::GetStoreBirthday() const { | 469 std::string LoopbackServer::GetStoreBirthday() const { |
461 DCHECK(thread_checker_.CalledOnValidThread()); | 470 DCHECK(thread_checker_.CalledOnValidThread()); |
462 return base::Int64ToString(store_birthday_); | 471 return base::Int64ToString(store_birthday_); |
463 } | 472 } |
464 | 473 |
| 474 std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( |
| 475 ModelType model_type) { |
| 476 DCHECK(thread_checker_.CalledOnValidThread()); |
| 477 std::vector<sync_pb::SyncEntity> sync_entities; |
| 478 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 479 ++it) { |
| 480 const LoopbackServerEntity& entity = *it->second; |
| 481 if (!(entity.IsDeleted() || entity.IsPermanent()) && |
| 482 entity.GetModelType() == model_type) { |
| 483 sync_pb::SyncEntity sync_entity; |
| 484 entity.SerializeAsProto(&sync_entity); |
| 485 sync_entities.push_back(sync_entity); |
| 486 } |
| 487 } |
| 488 return sync_entities; |
| 489 } |
| 490 |
| 491 std::unique_ptr<base::DictionaryValue> |
| 492 LoopbackServer::GetEntitiesAsDictionaryValue() { |
| 493 DCHECK(thread_checker_.CalledOnValidThread()); |
| 494 std::unique_ptr<base::DictionaryValue> dictionary( |
| 495 new base::DictionaryValue()); |
| 496 |
| 497 // Initialize an empty ListValue for all ModelTypes. |
| 498 ModelTypeSet all_types = ModelTypeSet::All(); |
| 499 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { |
| 500 dictionary->Set(ModelTypeToString(it.Get()), |
| 501 base::MakeUnique<base::ListValue>()); |
| 502 } |
| 503 |
| 504 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 505 ++it) { |
| 506 const LoopbackServerEntity& entity = *it->second; |
| 507 if (entity.IsDeleted() || entity.IsPermanent()) { |
| 508 // Tombstones are ignored as they don't represent current data. Folders |
| 509 // are also ignored as current verification infrastructure does not |
| 510 // consider them. |
| 511 continue; |
| 512 } |
| 513 base::ListValue* list_value; |
| 514 if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()), |
| 515 &list_value)) { |
| 516 return std::unique_ptr<base::DictionaryValue>(); |
| 517 } |
| 518 // TODO(pvalenzuela): Store more data for each entity so additional |
| 519 // verification can be performed. One example of additional verification |
| 520 // is checking the correctness of the bookmark hierarchy. |
| 521 list_value->AppendString(entity.GetName()); |
| 522 } |
| 523 |
| 524 return dictionary; |
| 525 } |
| 526 |
| 527 bool LoopbackServer::ModifyEntitySpecifics( |
| 528 const std::string& id, |
| 529 const sync_pb::EntitySpecifics& updated_specifics) { |
| 530 EntityMap::const_iterator iter = entities_.find(id); |
| 531 if (iter == entities_.end() || |
| 532 iter->second->GetModelType() != |
| 533 GetModelTypeFromSpecifics(updated_specifics)) { |
| 534 return false; |
| 535 } |
| 536 |
| 537 LoopbackServerEntity* entity = iter->second.get(); |
| 538 entity->SetSpecifics(updated_specifics); |
| 539 UpdateEntityVersion(entity); |
| 540 return true; |
| 541 } |
| 542 |
| 543 bool LoopbackServer::ModifyBookmarkEntity( |
| 544 const std::string& id, |
| 545 const std::string& parent_id, |
| 546 const sync_pb::EntitySpecifics& updated_specifics) { |
| 547 EntityMap::const_iterator iter = entities_.find(id); |
| 548 if (iter == entities_.end() || |
| 549 iter->second->GetModelType() != syncer::BOOKMARKS || |
| 550 GetModelTypeFromSpecifics(updated_specifics) != syncer::BOOKMARKS) { |
| 551 return false; |
| 552 } |
| 553 |
| 554 PersistentBookmarkEntity* entity = |
| 555 static_cast<PersistentBookmarkEntity*>(iter->second.get()); |
| 556 |
| 557 entity->SetParentId(parent_id); |
| 558 entity->SetSpecifics(updated_specifics); |
| 559 if (updated_specifics.has_bookmark()) { |
| 560 entity->SetName(updated_specifics.bookmark().title()); |
| 561 } |
| 562 UpdateEntityVersion(entity); |
| 563 return true; |
| 564 } |
| 565 |
465 void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { | 566 void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
466 DCHECK(thread_checker_.CalledOnValidThread()); | 567 DCHECK(thread_checker_.CalledOnValidThread()); |
467 | 568 |
468 proto->set_version(kCurrentLoopbackServerProtoVersion); | 569 proto->set_version(kCurrentLoopbackServerProtoVersion); |
469 proto->set_store_birthday(store_birthday_); | 570 proto->set_store_birthday(store_birthday_); |
470 proto->set_last_version_assigned(version_); | 571 proto->set_last_version_assigned(version_); |
471 for (const auto& key : keystore_keys_) | 572 for (const auto& key : keystore_keys_) |
472 proto->add_keystore_keys(key); | 573 proto->add_keystore_keys(key); |
473 for (const auto& entity : entities_) { | 574 for (const auto& entity : entities_) { |
474 auto* new_entity = proto->mutable_entities()->Add(); | 575 auto* new_entity = proto->mutable_entities()->Add(); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 // write. | 629 // write. |
529 LOG(ERROR) << "Loopback sync can not read the persistent state file."; | 630 LOG(ERROR) << "Loopback sync can not read the persistent state file."; |
530 return false; | 631 return false; |
531 } | 632 } |
532 } | 633 } |
533 LOG(WARNING) << "Loopback sync persistent state file does not exist."; | 634 LOG(WARNING) << "Loopback sync persistent state file does not exist."; |
534 return false; | 635 return false; |
535 } | 636 } |
536 | 637 |
537 } // namespace syncer | 638 } // namespace syncer |
OLD | NEW |