RequestManager: Add a separate callback for failures. Separate because we usually don't need it, except Osk.

This commit is contained in:
Henrik Rydgård 2023-03-25 18:48:50 +01:00
parent 659b51e55a
commit 221d2f7eb5
4 changed files with 81 additions and 42 deletions

View File

@ -15,16 +15,16 @@ const char *RequestTypeAsString(SystemRequestType type) {
}
}
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string &param1, const std::string &param2, int param3) {
bool RequestManager::MakeSystemRequest(SystemRequestType type, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3) {
int requestId = idCounter_++;
// NOTE: We need to register immediately, in order to support synchronous implementations.
{
std::lock_guard<std::mutex> guard(callbackMutex_);
callbackMap_[requestId] = callback;
callbackMap_[requestId] = { callback, failedCallback };
}
INFO_LOG(SYSTEM, "Making system request %s: id %d, callback_valid %d", RequestTypeAsString(type), requestId, callback != nullptr);
INFO_LOG(SYSTEM, "Making system request %s: id %d", RequestTypeAsString(type), requestId);
if (!System_MakeRequest(type, requestId, param1, param2, param3)) {
{
std::lock_guard<std::mutex> guard(callbackMutex_);
@ -45,12 +45,13 @@ void RequestManager::PostSystemSuccess(int requestId, const char *responseString
}
std::lock_guard<std::mutex> responseGuard(responseMutex_);
PendingResponse response;
response.callback = iter->second;
PendingSuccess response;
response.callback = iter->second.callback;
response.responseString = responseString;
response.responseValue = responseValue;
pendingResponses_.push_back(response);
pendingSuccesses_.push_back(response);
INFO_LOG(SYSTEM, "PostSystemSuccess: Request %d (%s, %d)", requestId, responseString, responseValue);
callbackMap_.erase(iter);
}
void RequestManager::PostSystemFailure(int requestId) {
@ -60,28 +61,41 @@ void RequestManager::PostSystemFailure(int requestId) {
ERROR_LOG(SYSTEM, "PostSystemFailure: Unexpected request ID %d", requestId);
return;
}
INFO_LOG(SYSTEM, "PostSystemFailure: Request %d failed", requestId);
std::lock_guard<std::mutex> responseGuard(responseMutex_);
PendingFailure response;
response.callback = iter->second.failedCallback;
pendingFailures_.push_back(response);
callbackMap_.erase(iter);
}
void RequestManager::ProcessRequests() {
std::lock_guard<std::mutex> guard(responseMutex_);
for (auto &iter : pendingResponses_) {
for (auto &iter : pendingSuccesses_) {
if (iter.callback) {
iter.callback(iter.responseString.c_str(), iter.responseValue);
}
}
pendingResponses_.clear();
pendingSuccesses_.clear();
for (auto &iter : pendingFailures_) {
if (iter.callback) {
iter.callback();
}
}
pendingFailures_.clear();
}
void RequestManager::Clear() {
std::lock_guard<std::mutex> guard(callbackMutex_);
std::lock_guard<std::mutex> responseGuard(responseMutex_);
pendingResponses_.clear();
pendingSuccesses_.clear();
pendingFailures_.clear();
callbackMap_.clear();
}
void System_CreateGameShortcut(const Path &path, const std::string &title) {
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, path.ToString(), title, 0);
g_requestManager.MakeSystemRequest(SystemRequestType::CREATE_GAME_SHORTCUT, nullptr, nullptr, path.ToString(), title, 0);
}

View File

@ -10,6 +10,7 @@
class Path;
typedef std::function<void(const char *responseString, int responseValue)> RequestCallback;
typedef std::function<void()> RequestFailedCallback;
// Platforms often have to process requests asynchronously, on wildly different threads.
// (Especially Android...)
@ -18,7 +19,9 @@ class RequestManager {
public:
// These requests are to be handled by platform implementations.
// The callback you pass in will be called on the main thread later.
bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, const std::string &param1, const std::string &param2, int param3);
// Params are at the end since it's the part most likely to recieve additions in the future,
// now that we have both callbacks.
bool MakeSystemRequest(SystemRequestType type, RequestCallback callback, RequestFailedCallback failedCallback, const std::string &param1, const std::string &param2, int param3);
// Called by the platform implementation, when it's finished with a request.
void PostSystemSuccess(int requestId, const char *responseString, int responseValue = 0);
@ -35,19 +38,30 @@ private:
struct PendingRequest {
SystemRequestType type;
RequestCallback callback;
RequestFailedCallback failedCallback;
};
std::map<int, RequestCallback> callbackMap_;
struct CallbackPair {
RequestCallback callback;
RequestFailedCallback failedCallback;
};
std::map<int, CallbackPair> callbackMap_;
std::mutex callbackMutex_;
struct PendingResponse {
struct PendingSuccess {
std::string responseString;
int responseValue;
RequestCallback callback;
};
struct PendingFailure {
RequestFailedCallback callback;
};
int idCounter_ = 0;
std::vector<PendingResponse> pendingResponses_;
std::vector<PendingSuccess> pendingSuccesses_;
std::vector<PendingFailure> pendingFailures_;
std::mutex responseMutex_;
};
@ -57,14 +71,14 @@ extern RequestManager g_requestManager;
// Wrappers for easy requests.
// NOTE: Semantics have changed - this no longer calls the callback on cancellation.
inline void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, RequestCallback callback) {
g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, callback, title, defaultValue, 0);
inline void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::INPUT_TEXT_MODAL, callback, failedCallback, title, defaultValue, 0);
}
// This one will pop up a special image brwoser if available. You can also pick
// images with the file browser below.
inline void System_BrowseForImage(const std::string &title, RequestCallback callback) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, callback, title, "", 0);
inline void System_BrowseForImage(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_IMAGE, callback, failedCallback, title, "", 0);
}
enum class BrowseFileType {
@ -75,57 +89,57 @@ enum class BrowseFileType {
ANY,
};
inline void System_BrowseForFile(const std::string &title, BrowseFileType type, RequestCallback callback) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, callback, title, "", (int)type);
inline void System_BrowseForFile(const std::string &title, BrowseFileType type, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FILE, callback, failedCallback, title, "", (int)type);
}
inline void System_BrowseForFolder(const std::string &title, RequestCallback callback) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, callback, title, "", 0);
inline void System_BrowseForFolder(const std::string &title, RequestCallback callback, RequestFailedCallback failedCallback = nullptr) {
g_requestManager.MakeSystemRequest(SystemRequestType::BROWSE_FOR_FOLDER, callback, failedCallback, title, "", 0);
}
inline void System_CopyStringToClipboard(const std::string &string) {
g_requestManager.MakeSystemRequest(SystemRequestType::COPY_TO_CLIPBOARD, nullptr, string, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::COPY_TO_CLIPBOARD, nullptr, nullptr, string, "", 0);
}
inline void System_ExitApp() {
g_requestManager.MakeSystemRequest(SystemRequestType::EXIT_APP, nullptr, "", "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::EXIT_APP, nullptr, nullptr, "", "", 0);
}
inline void System_RestartApp(const std::string &params) {
g_requestManager.MakeSystemRequest(SystemRequestType::RESTART_APP, nullptr, params, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::RESTART_APP, nullptr, nullptr, params, "", 0);
}
// The design is a little weird, just a holdover from the old message. Can either toggle or set to on or off.
inline void System_ToggleFullscreenState(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, nullptr, param, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, nullptr, nullptr, param, "", 0);
}
inline void System_GraphicsBackendFailedAlert(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT, nullptr, param, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT, nullptr, nullptr, param, "", 0);
}
inline void System_CameraCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::CAMERA_COMMAND, nullptr, command, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::CAMERA_COMMAND, nullptr, nullptr, command, "", 0);
}
inline void System_GPSCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::GPS_COMMAND, nullptr, command, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::GPS_COMMAND, nullptr, nullptr, command, "", 0);
}
inline void System_MicrophoneCommand(const std::string &command) {
g_requestManager.MakeSystemRequest(SystemRequestType::MICROPHONE_COMMAND, nullptr, command, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::MICROPHONE_COMMAND, nullptr, nullptr, command, "", 0);
}
inline void System_ShareText(const std::string &text) {
g_requestManager.MakeSystemRequest(SystemRequestType::SHARE_TEXT, nullptr, text, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::SHARE_TEXT, nullptr, nullptr, text, "", 0);
}
inline void System_NotifyUIState(const std::string &state) {
g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_STATE, nullptr, state, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::NOTIFY_UI_STATE, nullptr, nullptr, state, "", 0);
}
inline void System_SetWindowTitle(const std::string &param) {
g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, nullptr, param, "", 0);
g_requestManager.MakeSystemRequest(SystemRequestType::SET_WINDOW_TITLE, nullptr, nullptr, param, "", 0);
}
// Non-inline to avoid including Path.h

View File

@ -892,15 +892,26 @@ int PSPOskDialog::NativeKeyboard() {
defaultText.assign(u"VALUE");
// There's already ConvertUCS2ToUTF8 in this file. Should we use that instead of the global ones?
System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText), [&](const std::string &value, int iValue) {
std::lock_guard<std::mutex> guard(nativeMutex_);
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
return;
System_InputBoxGetString(::ConvertUCS2ToUTF8(titleText), ::ConvertUCS2ToUTF8(defaultText),
[&](const std::string &value, int) {
// Success callback
std::lock_guard<std::mutex> guard(nativeMutex_);
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
return;
}
nativeValue_ = value;
nativeStatus_ = PSPOskNativeStatus::SUCCESS;
},
[&]() {
// Failure callback
std::lock_guard<std::mutex> guard(nativeMutex_);
if (nativeStatus_ != PSPOskNativeStatus::WAITING) {
return;
}
nativeValue_ = "";
nativeStatus_ = PSPOskNativeStatus::FAILURE;
}
nativeValue_ = value;
nativeStatus_ = iValue ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE;
});
);
} else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) {
inputChars = ConvertUTF8ToUCS2(nativeValue_);
nativeValue_.clear();

@ -1 +1 @@
Subproject commit 77551c429f86c0e077f26552b7c1c0f12a9f235e
Subproject commit b34f619e1c85810dcb3c578107d2e48ba4ee2b37