diff --git a/CMakeLists.txt b/CMakeLists.txt
index 587e39d6df..857d3a2aa0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1835,6 +1835,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Debugger/WebSocket/GameBroadcaster.h
Core/Debugger/WebSocket/GameSubscriber.cpp
Core/Debugger/WebSocket/GameSubscriber.h
+ Core/Debugger/WebSocket/ClientConfigSubscriber.cpp
+ Core/Debugger/WebSocket/ClientConfigSubscriber.h
Core/Debugger/WebSocket/GPUBufferSubscriber.cpp
Core/Debugger/WebSocket/GPUBufferSubscriber.h
Core/Debugger/WebSocket/GPURecordSubscriber.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 89454fd9e7..bacf3c18be 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -547,6 +547,7 @@
+
@@ -1118,6 +1119,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index cefdfb01cb..ea4f7321fa 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -718,6 +718,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
@@ -1782,6 +1785,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp
index 560dc719f2..038cbcd531 100644
--- a/Core/Debugger/WebSocket.cpp
+++ b/Core/Debugger/WebSocket.cpp
@@ -62,6 +62,7 @@
#include "Core/Debugger/WebSocket/MemorySubscriber.h"
#include "Core/Debugger/WebSocket/ReplaySubscriber.h"
#include "Core/Debugger/WebSocket/SteppingSubscriber.h"
+#include "Core/Debugger/WebSocket/ClientConfigSubscriber.h"
typedef DebuggerSubscriber *(*SubscriberInit)(DebuggerEventHandlerMap &map);
static const std::vector subscribers({
@@ -78,6 +79,7 @@ static const std::vector subscribers({
&WebSocketMemoryInit,
&WebSocketReplayInit,
&WebSocketSteppingInit,
+ &WebSocketClientConfigInit,
});
// To handle webserver restart, keep track of how many running.
@@ -139,6 +141,7 @@ void HandleDebuggerRequest(const http::Request &request) {
SetupDebuggerLock();
WebSocketClientInfo client_info;
+ auto& allowed_config = client_info.allowed;
GameBroadcaster game;
LogBroadcaster logger;
@@ -187,11 +190,17 @@ void HandleDebuggerRequest(const http::Request &request) {
while (ws->Process(highActivity ? 1.0f / 1000.0f : 1.0f / 60.0f)) {
std::lock_guard guard(lifecycleLock);
- // These send events that aren't just responses to requests.
- logger.Broadcast(ws);
- game.Broadcast(ws);
- stepping.Broadcast(ws);
- input.Broadcast(ws);
+ // These send events that aren't just responses to requests
+
+ // The client can explicitly ask not to be notified about some events
+ if (allowed_config.at("logger"))
+ logger.Broadcast(ws);
+ if (allowed_config.at("game"))
+ game.Broadcast(ws);
+ if (allowed_config.at("stepping"))
+ stepping.Broadcast(ws);
+ if (allowed_config.at("input"))
+ input.Broadcast(ws);
for (size_t i = 0; i < subscribers.size(); ++i) {
if (subscriberData[i]) {
diff --git a/Core/Debugger/WebSocket/ClientConfigSubscriber.cpp b/Core/Debugger/WebSocket/ClientConfigSubscriber.cpp
new file mode 100644
index 0000000000..a502e37c5b
--- /dev/null
+++ b/Core/Debugger/WebSocket/ClientConfigSubscriber.cpp
@@ -0,0 +1,107 @@
+// Copyright (c) 2018- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Core/Debugger/WebSocket/ClientConfigSubscriber.h"
+#include "Core/Debugger/WebSocket/WebSocketUtils.h"
+#include "Common/StringUtils.h"
+
+DebuggerSubscriber *WebSocketClientConfigInit(DebuggerEventHandlerMap & map) {
+ map["broadcast.config.get"] = &WebSocketBroadcastConfigGet;
+ map["broadcast.config.set"] = &WebSocketBroadcastConfigSet;
+
+ return nullptr;
+}
+
+
+// Request the current client broadcast configuration (broadcast.config.get)
+//
+// No parameters.
+//
+// Response (same event name):
+// - allowed: object with boolean fields:
+// - logger: whether logger events are allowed
+// - game: whether game events are allowed
+// - stepping: whether stepping events are allowed
+// - input: whether input events are allowed
+void WebSocketBroadcastConfigGet(DebuggerRequest & req) {
+ JsonWriter &json = req.Respond();
+ const auto& allowed_config = req.client->allowed;
+
+ json.pushDict("allowed");
+
+ json.writeBool("logger", allowed_config.at("logger"));
+ json.writeBool("game", allowed_config.at("game"));
+ json.writeBool("stepping", allowed_config.at("stepping"));
+ json.writeBool("input", allowed_config.at("input"));
+
+ json.end();
+}
+
+// Update the current client broadcast configuration (broadcast.config.set)
+//
+// Parameters:
+// - allowed: object with boolean fields (all of them are optional):
+// - logger: new logger config state
+// - game: new game config state
+// - stepping: new stepping config state
+// - input: new input config state
+//
+// Response (same event name):
+// - allowed: object with boolean fields:
+// - logger: whether logger events are now allowed
+// - game: whether game events are now allowed
+// - stepping: whether stepping events are bow allowed
+// - input: whether input events are now allowed
+void WebSocketBroadcastConfigSet(DebuggerRequest & req) {
+ JsonWriter &json = req.Respond();
+ // WebSocketClientInfo& client = req.client;
+ auto& allowed_config = req.client->allowed;
+
+ const JsonNode *jsonAllowed = req.data.get("allowed");
+ if (!jsonAllowed) {
+ return req.Fail("Missing 'allowed' parameter");
+ }
+ if (jsonAllowed->value.getTag() != JSON_OBJECT) {
+ return req.Fail("Invalid 'allowed' parameter type");
+ }
+
+ for (const JsonNode *broadcaster : jsonAllowed->value) {
+ auto it = allowed_config.find(broadcaster->key);
+ if (it == allowed_config.end()) {
+ return req.Fail(StringFromFormat("Unsupported 'allowed' object key '%s'", broadcaster->key));
+ }
+
+ if (broadcaster->value.getTag() == JSON_TRUE) {
+ it->second = true;
+ }
+ else if (broadcaster->value.getTag() == JSON_FALSE) {
+ it->second = false;
+ }
+ else if (broadcaster->value.getTag() != JSON_NULL) {
+ return req.Fail(StringFromFormat("Unsupported 'allowed' object type for key '%s'", broadcaster->key));
+ }
+ }
+
+ json.pushDict("allowed");
+
+ json.writeBool("logger", allowed_config.at("logger"));
+ json.writeBool("game", allowed_config.at("game"));
+ json.writeBool("stepping", allowed_config.at("stepping"));
+ json.writeBool("input", allowed_config.at("input"));
+
+ json.end();
+}
\ No newline at end of file
diff --git a/Core/Debugger/WebSocket/ClientConfigSubscriber.h b/Core/Debugger/WebSocket/ClientConfigSubscriber.h
new file mode 100644
index 0000000000..edf4b8a0e5
--- /dev/null
+++ b/Core/Debugger/WebSocket/ClientConfigSubscriber.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2018- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Core/Debugger/WebSocket/WebSocketUtils.h"
+
+DebuggerSubscriber *WebSocketClientConfigInit(DebuggerEventHandlerMap &map);
+
+void WebSocketBroadcastConfigSet(DebuggerRequest &req);
+void WebSocketBroadcastConfigGet(DebuggerRequest &req);
\ No newline at end of file
diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h
index 6c104eef3c..d00a4f4366 100644
--- a/Core/Debugger/WebSocket/WebSocketUtils.h
+++ b/Core/Debugger/WebSocket/WebSocketUtils.h
@@ -34,11 +34,17 @@
using namespace json;
struct WebSocketClientInfo {
- WebSocketClientInfo() : name(), version() {
-
+ WebSocketClientInfo() : name(), version(), allowed() {
+ // By default everything is on
+ allowed.emplace("logger", true);
+ allowed.emplace("game", true);
+ allowed.emplace("stepping", true);
+ allowed.emplace("input", true);
}
+
std::string name;
std::string version;
+ std::map allowed;
};
struct DebuggerErrorEvent {
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 1eaeaef5b1..1c27c3734a 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -295,6 +295,7 @@
+
@@ -534,6 +535,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 85f5201e01..f909a0f3c2 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -671,6 +671,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
@@ -1689,6 +1692,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index f28625f35b..497752f151 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -476,6 +476,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/Debugger/WebSocket.cpp \
$(SRC)/Core/Debugger/WebSocket/BreakpointSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp \
+ $(SRC)/Core/Debugger/WebSocket/ClientConfigSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/DisasmSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/GameSubscriber.cpp \