From 86773a7f081a8a6c71643ecdc6573b65dbf0ccd3 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Sun, 28 Apr 2019 18:57:37 -0400
Subject: [PATCH] bcat: Implement cmd RequestSyncDeliveryCache and variant
 Variant also supports only updating a single directory. These just both
 invoke backend commands.

---
 src/core/hle/service/bcat/module.cpp | 72 +++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 1459fab113..605aa6e007 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -145,8 +145,8 @@ public:
     IBcatService(Backend& backend) : ServiceFramework("IBcatService"), backend(backend) {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {10100, nullptr, "RequestSyncDeliveryCache"},
-            {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"},
+            {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"},
+            {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"},
             {10200, nullptr, "CancelSyncDeliveryCacheRequest"},
             {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
             {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
@@ -162,7 +162,74 @@ public:
         };
         // clang-format on
         RegisterHandlers(functions);
+
+        auto& kernel{Core::System::GetInstance().Kernel()};
+        progress.at(static_cast<std::size_t>(SyncType::Normal)).event =
+            Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+                                                   "BCAT::IDeliveryCacheProgressEvent");
+        progress.at(static_cast<std::size_t>(SyncType::Directory)).event =
+            Kernel::WritableEvent::CreateEventPair(
+                kernel, Kernel::ResetType::OneShot,
+                "BCAT::IDeliveryCacheProgressEvent::DirectoryName");
+    }
+
+private:
+    enum class SyncType {
+        Normal,
+        Directory,
+        Count,
+    };
+
+    std::function<void(bool)> CreateCallback(SyncType type) {
+        return [this, type](bool success) {
+            auto& pair{progress.at(static_cast<std::size_t>(type))};
+            pair.impl.status = DeliveryCacheProgressImpl::Status::Complete;
+            pair.event.writable->Signal();
+        };
+    }
+
+    std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) {
+        const auto& pair{progress.at(static_cast<std::size_t>(type))};
+        return std::make_shared<IDeliveryCacheProgressService>(pair.event.readable, pair.impl);
     }
+
+    void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_BCAT, "called");
+
+        backend.Synchronize({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()},
+                            CreateCallback(SyncType::Normal));
+
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(RESULT_SUCCESS);
+        rb.PushIpcInterface(CreateProgressService(SyncType::Normal));
+    }
+
+    void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto name_raw = rp.PopRaw<DirectoryName>();
+        const auto name =
+            Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
+
+        LOG_DEBUG(Service_BCAT, "called, name={}", name);
+
+        backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()},
+                                     name, CreateCallback(SyncType::Directory));
+
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(RESULT_SUCCESS);
+        rb.PushIpcInterface(CreateProgressService(SyncType::Directory));
+    }
+
+    }
+
+    Backend& backend;
+
+    struct ProgressPair {
+        Kernel::EventPair event;
+        DeliveryCacheProgressImpl impl;
+    };
+
+    std::array<ProgressPair, static_cast<std::size_t>(SyncType::Count)> progress{};
 };
 
 void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
@@ -171,6 +238,7 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
     rb.PushIpcInterface<IBcatService>(*backend);
+}
 
 class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
 public:
-- 
GitLab