| 622 | } |
| 623 | |
| 624 | std::string CmdSyncRemoteApp(const std::string& provider, const std::string& accountId, const std::string& appId, |
| 625 | const std::string& cloudRootArg) { |
| 626 | std::string tokenPath = GetTokenPath(provider); |
| 627 | if (tokenPath.empty()) { |
| 628 | return JsonError("Cannot determine config directory"); |
| 629 | } |
| 630 | |
| 631 | uint32_t parsedAccountId = static_cast<uint32_t>(std::strtoul(accountId.c_str(), nullptr, 10)); |
| 632 | uint32_t parsedAppId = static_cast<uint32_t>(std::strtoul(appId.c_str(), nullptr, 10)); |
| 633 | if (parsedAccountId == 0 || parsedAppId == 0) { |
| 634 | return JsonError("Invalid account_id or app_id"); |
| 635 | } |
| 636 | |
| 637 | auto prov = CreateCloudProvider(provider); |
| 638 | if (!prov) { |
| 639 | return JsonError("Unknown provider: " + provider); |
| 640 | } |
| 641 | |
| 642 | if (!prov->Init(tokenPath)) { |
| 643 | return JsonError("Failed to initialize provider"); |
| 644 | } |
| 645 | |
| 646 | if (!prov->IsAuthenticated()) { |
| 647 | prov->Shutdown(); |
| 648 | return JsonError("Not authenticated"); |
| 649 | } |
| 650 | |
| 651 | std::string cloudRoot = NormalizeCloudRoot(cloudRootArg); |
| 652 | if (cloudRoot.empty()) { |
| 653 | prov->Shutdown(); |
| 654 | return JsonError("cloud_root is required"); |
| 655 | } |
| 656 | std::string storageRoot = cloudRoot + "storage/"; |
| 657 | #ifdef _WIN32 |
| 658 | for (auto& c : storageRoot) { if (c == '/') c = '\\'; } |
| 659 | #endif |
| 660 | |
| 661 | LocalStorage::Init(storageRoot); |
| 662 | LocalMetadataStore::Init(storageRoot); |
| 663 | LocalStorage::InitApp(parsedAccountId, parsedAppId); |
| 664 | LocalMetadataStore::InitApp(parsedAccountId, parsedAppId); |
| 665 | PendingOpsJournal::Init(storageRoot); |
| 666 | CloudStorage::Init(cloudRoot, std::move(prov)); |
| 667 | |
| 668 | bool hadNewer = CloudStorage::SyncFromCloud(parsedAccountId, parsedAppId); |
| 669 | bool drained = CloudWorkQueue::DrainQueueForApp(parsedAccountId, parsedAppId); |
| 670 | uint64_t localCN = LocalStorage::GetChangeNumber(parsedAccountId, parsedAppId); |
| 671 | auto localFiles = LocalStorage::GetFileList(parsedAccountId, parsedAppId); |
| 672 | auto rootTokens = LocalMetadataStore::LoadRootTokens(parsedAccountId, parsedAppId); |
| 673 | auto fileTokens = LocalMetadataStore::LoadFileTokens(parsedAccountId, parsedAppId); |
| 674 | |
| 675 | CloudStorage::Shutdown(); |
| 676 | |
| 677 | return JsonObject({ |
| 678 | {"success", JsonBool(drained)}, |
| 679 | {"had_newer", JsonBool(hadNewer)}, |
| 680 | {"drained", JsonBool(drained)}, |
| 681 | {"local_cn", JsonInt(static_cast<int64_t>(localCN))}, |
no test coverage detected