From 4e2aa50cefd56f4bb119c9c6e6ab89afbb31351e Mon Sep 17 00:00:00 2001
From: Chloe Marcec <dmarcecguzman@gmail.com>
Date: Mon, 6 Sep 2021 21:16:21 +1000
Subject: [PATCH] account: EnsureTokenIdCacheAsync

Closes #2547, #6946
---
 src/core/CMakeLists.txt                    |  2 +
 src/core/hle/service/acc/acc.cpp           | 67 +++++++++++++++------
 src/core/hle/service/acc/async_context.cpp | 68 ++++++++++++++++++++++
 src/core/hle/service/acc/async_context.h   | 36 ++++++++++++
 4 files changed, 154 insertions(+), 19 deletions(-)
 create mode 100644 src/core/hle/service/acc/async_context.cpp
 create mode 100644 src/core/hle/service/acc/async_context.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 87d47e2e5d..7140d0db8b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -263,6 +263,8 @@ add_library(core STATIC
     hle/service/acc/acc_u0.h
     hle/service/acc/acc_u1.cpp
     hle/service/acc/acc_u1.h
+    hle/service/acc/async_context.cpp
+    hle/service/acc/async_context.h
     hle/service/acc/errors.h
     hle/service/acc/profile_manager.cpp
     hle/service/acc/profile_manager.h
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 882fc1492b..1db0542574 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -23,6 +23,7 @@
 #include "core/hle/service/acc/acc_su.h"
 #include "core/hle/service/acc/acc_u0.h"
 #include "core/hle/service/acc/acc_u1.h"
+#include "core/hle/service/acc/async_context.h"
 #include "core/hle/service/acc/errors.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/hle/service/glue/arp.h"
@@ -454,22 +455,6 @@ public:
         : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
 };
 
-class IAsyncContext final : public ServiceFramework<IAsyncContext> {
-public:
-    explicit IAsyncContext(Core::System& system_) : ServiceFramework{system_, "IAsyncContext"} {
-        // clang-format off
-        static const FunctionInfo functions[] = {
-            {0, nullptr, "GetSystemEvent"},
-            {1, nullptr, "Cancel"},
-            {2, nullptr, "HasDone"},
-            {3, nullptr, "GetResult"},
-        };
-        // clang-format on
-
-        RegisterHandlers(functions);
-    }
-};
-
 class ISessionObject final : public ServiceFramework<ISessionObject> {
 public:
     explicit ISessionObject(Core::System& system_, Common::UUID)
@@ -504,16 +489,42 @@ public:
     }
 };
 
+class EnsureTokenIdCacheAsyncInterface final : public IAsyncContext {
+public:
+    explicit EnsureTokenIdCacheAsyncInterface(Core::System& system_) : IAsyncContext(system_) {
+        MarkComplete();
+    }
+    ~EnsureTokenIdCacheAsyncInterface() = default;
+
+    void LoadIdTokenCache(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_ACC, "(STUBBED) called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(ResultSuccess);
+    }
+
+protected:
+    bool IsComplete() override {
+        return true;
+    }
+
+    void Cancel() override {}
+
+    ResultCode GetResult() override {
+        return ResultSuccess;
+    }
+};
+
 class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
 public:
     explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_)
-        : ServiceFramework{system_, "IManagerForApplication"}, user_id{user_id_} {
+        : ServiceFramework{system_, "IManagerForApplication"}, user_id{user_id_}, system(system_) {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
             {1, &IManagerForApplication::GetAccountId, "GetAccountId"},
-            {2, nullptr, "EnsureIdTokenCacheAsync"},
-            {3, nullptr, "LoadIdTokenCache"},
+            {2, &IManagerForApplication::EnsureIdTokenCacheAsync, "EnsureIdTokenCacheAsync"},
+            {3, &IManagerForApplication::LoadIdTokenCache, "LoadIdTokenCache"},
             {130, &IManagerForApplication::GetNintendoAccountUserResourceCacheForApplication, "GetNintendoAccountUserResourceCacheForApplication"},
             {150, nullptr, "CreateAuthorizationRequest"},
             {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
@@ -522,6 +533,8 @@ public:
         // clang-format on
 
         RegisterHandlers(functions);
+
+        ensure_token_id = std::make_shared<EnsureTokenIdCacheAsyncInterface>(system);
     }
 
 private:
@@ -540,6 +553,20 @@ private:
         rb.PushRaw<u64>(user_id.GetNintendoID());
     }
 
+    void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_ACC, "(STUBBED) called");
+
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(ResultSuccess);
+        rb.PushIpcInterface(ensure_token_id);
+    }
+
+    void LoadIdTokenCache(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_ACC, "(STUBBED) called");
+
+        ensure_token_id->LoadIdTokenCache(ctx);
+    }
+
     void GetNintendoAccountUserResourceCacheForApplication(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_ACC, "(STUBBED) called");
 
@@ -562,7 +589,9 @@ private:
         rb.Push(ResultSuccess);
     }
 
+    std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{};
     Common::UUID user_id{Common::INVALID_UUID};
+    Core::System& system;
 };
 
 // 6.0.0+
diff --git a/src/core/hle/service/acc/async_context.cpp b/src/core/hle/service/acc/async_context.cpp
new file mode 100644
index 0000000000..a58429090e
--- /dev/null
+++ b/src/core/hle/service/acc/async_context.cpp
@@ -0,0 +1,68 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/acc/async_context.h"
+
+namespace Service::Account {
+IAsyncContext::IAsyncContext(Core::System& system)
+    : ServiceFramework{system, "IAsyncContext"}, compeletion_event{system.Kernel()} {
+
+    Kernel::KAutoObject::Create(std::addressof(compeletion_event));
+    compeletion_event.Initialize("IAsyncContext:CompletionEvent");
+
+    // clang-format off
+        static const FunctionInfo functions[] = {
+            {0, &IAsyncContext::GetSystemEvent, "GetSystemEvent"},
+            {1, &IAsyncContext::Cancel, "Cancel"},
+            {2, &IAsyncContext::HasDone, "HasDone"},
+            {3, &IAsyncContext::GetResult, "GetResult"},
+        };
+    // clang-format on
+
+    RegisterHandlers(functions);
+}
+
+void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_ACC, "called");
+
+    IPC::ResponseBuilder rb{ctx, 2, 1};
+    rb.Push(ResultSuccess);
+    rb.PushCopyObjects(compeletion_event.GetReadableEvent());
+}
+
+void IAsyncContext::Cancel(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_ACC, "called");
+
+    Cancel();
+    MarkComplete();
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(ResultSuccess);
+}
+
+void IAsyncContext::HasDone(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_ACC, "called");
+
+    is_complete = IsComplete();
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(ResultSuccess);
+    rb.Push(is_complete);
+}
+
+void IAsyncContext::GetResult(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_ACC, "called");
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(GetResult());
+}
+
+void IAsyncContext::MarkComplete() {
+    is_complete = true;
+    compeletion_event.GetWritableEvent().Signal();
+}
+
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/async_context.h b/src/core/hle/service/acc/async_context.h
new file mode 100644
index 0000000000..2453a79f5a
--- /dev/null
+++ b/src/core/hle/service/acc/async_context.h
@@ -0,0 +1,36 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::Account {
+
+class IAsyncContext : public ServiceFramework<IAsyncContext> {
+public:
+    explicit IAsyncContext(Core::System& system_);
+
+    void GetSystemEvent(Kernel::HLERequestContext& ctx);
+    void Cancel(Kernel::HLERequestContext& ctx);
+    void HasDone(Kernel::HLERequestContext& ctx);
+    void GetResult(Kernel::HLERequestContext& ctx);
+
+protected:
+    virtual bool IsComplete() = 0;
+    virtual void Cancel() = 0;
+    virtual ResultCode GetResult() = 0;
+
+    void MarkComplete();
+
+    bool is_complete{false};
+    Kernel::KEvent compeletion_event;
+};
+
+} // namespace Service::Account