Compare commits

...

3 Commits

Author SHA1 Message Date
Maufeat 5ed7a175e7 jthreaded 2026-08-19 10:01:30 +02:00
Maufeat f14c0a389a jthread 2026-08-19 09:05:44 +02:00
Maufeat 207a1c53df unstub IShopServiceAsync (but still stub Request, with empty json response) 2026-08-19 08:58:44 +02:00
+118 -13
View File
@@ -5,33 +5,136 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <ctime>
#include <mutex>
#include <string>
#include <vector>
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::NIM {
class IShopServiceAsync final : public ServiceFramework<IShopServiceAsync> {
public:
explicit IShopServiceAsync(Core::System& system_)
: ServiceFramework{system_, "IShopServiceAsync"} {
: ServiceFramework{system_, "IShopServiceAsync"},
service_context{system_, "IShopServiceAsync"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Cancel"},
{1, nullptr, "GetSize"},
{2, nullptr, "Read"},
{3, nullptr, "GetErrorCode"},
{4, nullptr, "Request"},
{5, nullptr, "Prepare"},
{0, D<&IShopServiceAsync::Cancel>, "Cancel"},
{1, D<&IShopServiceAsync::GetSize>, "GetSize"},
{2, D<&IShopServiceAsync::Read>, "Read"},
{3, D<&IShopServiceAsync::GetErrorCode>, "GetErrorCode"},
{4, D<&IShopServiceAsync::Request>, "Request"},
{5, D<&IShopServiceAsync::Prepare>, "Prepare"},
};
// clang-format on
RegisterHandlers(functions);
completion_event = service_context.CreateEvent("IShopServiceAsync:Completion");
}
~IShopServiceAsync() override {
CancelImpl();
service_context.CloseEvent(completion_event);
}
Kernel::KReadableEvent* GetEvent() const {
return &completion_event->GetReadableEvent();
}
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* completion_event;
std::jthread worker;
std::atomic<u32> error_code{0};
std::mutex data_mutex;
std::vector<u8> download_data;
void CancelImpl() {
worker.request_stop();
if (worker.joinable()) {
worker.join();
}
}
Result Cancel() {
LOG_DEBUG(Service_NIM, "called");
CancelImpl();
R_SUCCEED();
}
Result GetSize(Out<u64> out_size) {
LOG_DEBUG(Service_NIM, "called");
std::scoped_lock lock{data_mutex};
*out_size = download_data.size();
R_SUCCEED();
}
Result Read(Out<u64> out_size, u64 offset, OutBuffer<BufferAttr_HipcAutoSelect> out_buffer) {
std::scoped_lock lock{data_mutex};
u64 actual_read = 0;
if (offset < download_data.size()) {
actual_read = std::min<u64>(out_buffer.size(), download_data.size() - offset);
std::memcpy(out_buffer.data(), download_data.data() + offset, actual_read);
}
*out_size = actual_read;
R_SUCCEED();
}
Result GetErrorCode(Out<u32> out_error_code) {
LOG_DEBUG(Service_NIM, "called");
*out_error_code = error_code.load();
R_SUCCEED();
}
Result Request() {
LOG_DEBUG(Service_NIM, "(STUBBED) called");
CancelImpl();
error_code.store(0);
completion_event->Clear(system.Kernel());
{
std::scoped_lock lock{data_mutex};
download_data.clear();
}
worker = std::jthread([this](const std::stop_token& stop_token) {
if (stop_token.stop_requested()) {
error_code.store(1);
} else {
std::scoped_lock lock{data_mutex};
// Dummy JSON response, else it fails...
const std::string dummy_response = "{}";
download_data.assign(dummy_response.begin(), dummy_response.end());
error_code.store(0);
}
completion_event->Signal(system.Kernel());
});
R_SUCCEED();
}
Result Prepare(InArray<char, BufferAttr_HipcMapAlias> in_path, InArray<char, BufferAttr_HipcMapAlias> in_post) {
LOG_DEBUG(Service_NIM, "called");
if (!in_path.empty()) {
std::string url(in_path.data(), in_path.size());
LOG_INFO(Service_NIM, "Preparing request for URL: {}", url);
}
R_SUCCEED();
}
};
@@ -49,11 +152,13 @@ public:
}
private:
void CreateAsyncInterface(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
void CreateAsyncInterface(HLERequestContext& ctx) {LOG_DEBUG(Service_NIM, "called");
auto async_interface = std::make_shared<IShopServiceAsync>(system);
IPC::ResponseBuilder rb{ctx, 2, 1, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IShopServiceAsync>(ctx, system);
rb.PushCopyObjects(ctx, async_interface->GetEvent());
rb.PushIpcInterface<IShopServiceAsync>(ctx, std::move(async_interface));
}
};